汇编语言学习08 之数据操作指令

本文主要参考这个学习网站的内容 http://c.biancheng.net/view/3476.htm

操作数

操作数有 3 种基本类型:
立即数——用数字文本表达式
寄存器操作数——使用 CPU 内已命名的寄存器
内存操作数——引用内存位置

mov

MOV指令:将源操作数复制到目的操作数
在几乎所有的汇编语言指令中,左边的操作数是目标操作数,而右边的操作数是源操作数。只要按照如下原则,MOV 指令使用操作数是非常灵活的。

  1. 两个操作数必须是同样的大小。
  2. 两个操作数不能同时为内存操作数。
  3. 指令指针寄存器(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
发布了16 篇原创文章 · 获赞 0 · 访问量 318

猜你喜欢

转载自blog.csdn.net/qq_43156233/article/details/103835989