汇编指令之数据传送指令

阅读更多
        在 x86-64 中的寄存器与汇编操作数杂述一节中,我们介绍了 x86-64 中的 16 种寄存器和各种操作数寻址方式,本文将在此基础上介绍汇编中的数据传送指令。
        最简单形式的数据传送指令如下表所示。这些指令把数据从源位置复制到目的位置,不做任何变化。
汇编指令之数据传送指令_第1张图片
        这些指令都执行同样的操作,主要区别在于它们操作的数据大小不同,分别是 1、2、4 和 8 字节。源操作数指定的值是一个存储在寄存器或者内存中的立即数,目的操作数指定一个位置,可以是一个寄存器或者内存地址,但源操作数和目的操作数不能都指向内存位置。因此要将一个值从一个内存位置复制到另一个内存位置需要两条指令——第一条将源值加载到寄存器中,第二条再将该寄存器值写入目的位置。这些指令的寄存器操作数可以是 16 个寄存器有标号部分中的任意一个,不过寄存器部分的大小必须与指令最后一个字符(b、w、l 或 q)指定的大小匹配。多数情况下,MOV 指令只会更新目的操作数指定的那些寄存器字节或内存位置。唯一的例外是 movl 指令以寄存器作为目的地址时,它会把该寄存器的高位 4 字节设置为 0。这是 x86-64 采用的惯例,即任何为寄存器生成 32 位值的指令都会把该寄存器的高位部分设置成 0。
        上表中的最后一条指令是处理 64 位立即数数据的。因为常规的 movq 指令只能以表示为 32 位补码数字的立即数作为源操作数,然后再把这个值符号扩展得到 64 位的值,放到目的地址。而 movabsq 指令能够以任意 64 位立即数值作为源操作数,并且只能以寄存器作为目的位置。
        下面的 MOV 指令示例给出了源和目的类型的五种可能的组合(这里使用的是 ATT 汇编格式,MOV 指令的第一个操作数是源,第二个是目的操作数,Intel 汇编格式则是反的,下同)。
movl $0x4050, %eax              ; Immediate -> Register, 4 bytes
movw %bp, %sp                   ; Register -> Register, 2 bytes
movb (%rdi, %rcx), %al          ; Memory -> Register, 1 byte
movb $-17, (%rsp)               ; Immediate -> Memory, 1 byte
movq %rax, -12(%rbp)            ; Register -> Memory, 8 bytes

        除了上表中这些简单形式的移动指令,下面两张表记录的是另两类移动指令,它们可以在将较小范围的源值复制到较大范围的目的时使用。其中,MOVZ 类中的指令把目的中剩余的字节填充为 0,而 MOVS 类中的指令则通过符号扩展来填充。这两类指令名字的最后两个字符都是大小指示符:第一个字符指定源的大小,第二个指明目的的大小。
汇编指令之数据传送指令_第2张图片
汇编指令之数据传送指令_第3张图片
        需要注意的是,MOVZ 类指令中并没有一条明确的指令把 4 字节源值零扩展到 8 字节目的,因为正如前面所述,这可以用以寄存器为目的的 movl 指令来实现。另外,MOVS 类指令中还给出了 cltq 指令,其没有操作数,因为它总是以寄存器 %eax 作为源,以寄存器 %rax 作为符号扩展结果的目的。它的效果与指令“movslq %eax, %rax”完全一致,不过编码更为紧凑。
        下面这段汇编代码序列演示了数据传送指令是如何修改目的寄存器的高位字节的。
movabsq $0x0011223344556677, %rax    ; %rax = 0x0011223344556677
movb $-1, %al                        ; %rax = 0x00112233445566FF
movw $-1, %ax                        ; %rax = 0x001122334455FFFF
movl $-1, %eax                       ; %rax = 0x00112233FFFFFFFF
movq $-1, %rax                       ; %rax = 0xFFFFFFFFFFFFFFFF

        除了 MOV 类指令外,pushq 和 popq 指令也可以进行数据传送操作:通过 push 操作可以把数据压入栈,通过 pop 操作则将数据弹出栈。在 x86-64 中,程序栈存放在内存中的某个区域。栈一般是向下增长的,因此栈顶元素的地址是所有栈元素地址中最低的。栈顶元素的地址保存在栈指针寄存器 %rsp 中。下表给出了 pushq 和 popq 指令的执行情况。
汇编指令之数据传送指令_第4张图片
        因为栈和程序代码以及其他形式的程序数据都是放在同一内存中,所以程序可以用标准的内存寻址方法访问栈内的任意位置。例如,假设栈顶元素是四字,则指令“movq 8(%rsp), %rdx”会将第二个四字从栈中复制到寄存器 %rdx。

参考书籍:《深入理解计算机系统》第三章——程序的机器级表示。
  • 汇编指令之数据传送指令_第5张图片
  • 大小: 56.5 KB
  • 汇编指令之数据传送指令_第6张图片
  • 大小: 91 KB
  • 汇编指令之数据传送指令_第7张图片
  • 大小: 99.4 KB
  • 汇编指令之数据传送指令_第8张图片
  • 大小: 57.6 KB
  • 查看图片附件

你可能感兴趣的:(汇编指令,数据传送指令,mov指令)