本文主要参考这个学习网站的内容 http://c.biancheng.net/view/3476.htm
操作数
操作数有 3 种基本类型:
立即数——用数字文本表达式
寄存器操作数——使用 CPU 内已命名的寄存器
内存操作数——引用内存位置
mov
MOV指令:将源操作数复制到目的操作数
在几乎所有的汇编语言指令中,左边的操作数是目标操作数,而右边的操作数是源操作数。只要按照如下原则,MOV 指令使用操作数是非常灵活的。
- 两个操作数必须是同样的大小。
- 两个操作数不能同时为内存操作数。
- 指令指针寄存器(IP、EIP 或 RIP)不能作为目标操作数
下面是mov的标准格式:
MOV reg, reg
MOV mem, reg
MOV reg, mem
MOV mem, imm
MOV reg, imm
单条 MOV 指令不能用于直接将数据从一个内存位置传送到另一个内存位置。相反,在将源操作数的值赋给内存操作数之前,必须先将该数值传送给一个寄存器:
.data
val1 WORD ?
val2 WORD ?
.code
mov ax,val1
mov val2,ax
MOVZX 和 MOVSX
尽管 MOV 指令不能直接将较小的操作数复制到较大的操作数中,但是程序员可以想办法解决这个问题。假设要将 count(无符号,16 位)传送到 ECX(32 位),可以先将 ECX 设置为 0,然后将 count 传送到 CX:
.data
count WORD 1
.code
mov ecx,0
mov cx,count
MOVZX 指令(进行全零扩展并传送)将源操作数复制到目的操作数,并把目的操作数 0 扩展到 16 位或 32 位。这条指令只用于无符号整数,有三种不同的形式:
MOVZX reg32,reg/mem8
MOVZX reg32,reg/mem16
MOVZX reg16,reg/mem8
MOVSX 指令(进行符号扩展并传送)将源操作数内容复制到目的操作数,并把目的操作数符号扩展到 16 位或 32 位。这条指令只用于有符号整数,有三种不同的形式:
MOVSX reg32, reg/mem8
MOVSX reg32, reg/mem16
MOVSX reg16, reg/mem8
LAHF和SAHF
LAHF(加载状态标志位到 AH)指令将 EFLAGS 寄存器的低字节复制到 AH。被复制的标志位包括:符号标志位、零标志位、辅助进位标志位、奇偶标志位和进位标志位。使用这条指令,可以方便地把标志位副本保管在变量中:
.data
saveflags BYTE ?
.code
lahf ;将标志位加载到 AH
mov saveflags, ah ;用变量保存这些标志位
SAHF(保存 AH 内容到状态标志位)指令将 AH 内容复制到 EFLAGS(或 RFLAGS)寄存器低字节。例如,可以检索之前保存到变量中的标志位数值:
mov ah, saveflags ;加载被保存标志位到 AH
sahf ;复制到 FLAGS 寄存器
XCHG指令:交换两个操作数内容
XCHG主要有以下三种形式:
XCHG reg, reg
XCHG reg, mem
XCHG mem, reg
在数组排序应用中,XCHG 指令提供了一种简单的方法来交换两个数组元素。下面是几个使用 XCHG 指令的例子:
xchg ax,bx ;交换 16 位寄存器内容
xchg ah,al ;交换 8 位寄存器内容
xchg var1,bx ;交换 16 位内存操作数与 BX 寄存器内容
xchg eax,ebx ;交换 32 位寄存器内容
如果要交换两个内存操作数,则用寄存器作为临时容器,把 MOV 指令与 XCHG 指令一起使用:
mov ax,val1
xchg ax,val2
mov val1,ax
直接偏移操作数
变量名加上一个位移就形成了一个直接 - 偏移量操作数。这样可以访问那些没有显式标记的内存位置。假设现有一个字节数组 array1:
array1 BYTE 10h,20h,30h,40h,50h
用该数组作为 MOV 指令的源操作数,则自动传送数组的第一个字节:
mov al,array1 ;AL = 10h
通过在 array1 偏移量上加 1 就可以访问该数组的第二个字节:
mov al,[arrayB+1] ;AL = 20h
形如 array1+1 一样的表达式通过在变量偏移量上加常数来形成所谓的有效地址。
字和双字数组
在 16 位的字数组中,每个数组元素的偏移量比前一个多 2 个字节。这就是为什么在下面的例子中,数组 ArrayW 加 2 才能指向该数组的第二个元素:
.data
arrayW WORD 100h,200h,300h
.code
mov ax, arrayW ;AX = 100h
mov ax,[arrayW+2] ;AX = 200h
同理,双字数组则需要偏移4个字节
数据传输实例(包括上述所有指令)
;数据传输实例
.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD
.data
val1 WORD 1000h
val2 WORD 2000h
arrayB BYTE 10h,20h,30h,40h,50h
arrayW WORD 100h,200h,300h
arrayD DWORD 10000h,20000h
.code
main PROC
;演示 MOVZX 指令
mov bx,0A69Bh
movzx eax,bx ;EAX = 0000A69Bh
movzx edx,bl ;EDX = 0000009Bh
movzx cx,bl ;CX = 009Bh
;演示 MOVSX 指令
mov bx,0A69Bh
movsx eax,bx ;EAX = FFFFA69Bh
movsx edx,bl ;EDX = FFFFFF9Bh
mov bl,7Bh
movsx cx,bl ;CX = 007Bh
;内存-内存的交换
mov ax,val1 ;AX = 1000h
xchg ax val2 ;AX = 2000h,val2 = 1000h
mov val1,ax ;val1 = 2000h
;直接-偏移量寻址(字节数组)
mov al,arrayB ;AL = 10h
mov al,[arrayB+1] ;AL = 20h
mov al,[arrayB+2] ;AL = 30h
;直接-偏移量寻址(字数组)
mov ax,arrayW ;AX = 100h
mov ax,[arrayW+2] ;AX = 200h
;直接-偏移量寻址(双字数组)
mov eax,arrayD ;EAX = 10000h
mov eax,[arrayD+4] ;EAX = 20000h
mov eax,[arrayD+4] ;EAX = 20000h
INVOKE ExitProcess,0
main ENDP
END main