玩命加载中 . . .

3.2-寄存器与数据传送指令


寄存器与数据传送指令

64位的处理器中,原来8个16位寄存器扩展成了64位,还增加了8个

不同寄存器扮演不同的角色,相应的编程规范规定了如何使用这些寄存器

  • rax用来保存函数的返回值
  • rsp用来保存程序栈的结束位置
  • rdi, rsi, rdx, rcx, r8, r9可以用来传递函数参数

指令(Instruction)

包括操作码(Operation Code)和操作数(Operands)

  • 操作码决定了CPU执行操作的类型
  • 大多数指令具有一个或多个操作数

操作数可以分为3类:

  • 立即数(Immediate):以$开头,后面跟一个整数
  • 寄存器(Register):%rax,64位,32位,16位,8位寄存器都可以作为操作数
  • 内存引用(Memory Reference):寄存器加上小括号,如(%rdi)

MOV指令

有两个操作数,源操作数(Source operand)和目的操作数(Destination operand)

  • 源操作数可以是:立即数,寄存器,内存引用
  • 目的操作数是用来存放源操作数的内容,所以只能是寄存器或内存引用
规定:源操作数和目的操作数不能都是内存的地址

所以,放需要将一个数从内存的一个位置复制到另一个位置,需要两条mov指令来完成

mov memory, register    // 将内存源位置的数值加载到寄存器
mov register, memory    // 再将该寄存器的值写入目标位置

mov指令的后缀与寄存器的大小一定得是匹配的

movl $0x4050, %eax      // 立即数->寄存器 32位
movw %bp, %sp           // 寄存器->寄存器 16位
movb (%rdi, %rcx), %al  // 内存->寄存器 8位
movb $-17, (%rsp)       // 立即数->内存 8位
movq %rax, -12(%rbp)    // 寄存器->内存 64位

特殊情况

movq的源操作数是立即数时,该立即数只能是32位的补码表示,然后对该数值进行符号位扩展,将得到的64位数传送到目标位置

movabsq指令的源操作数可以是任意的64位立即数,目的操作数只能是寄存器

例子:
使用movabsq将一个64位立即数复制到寄存器rax

movabsq $0x0011223344556677, %rax

rax内的数值如图所示

接下来,使用movb指令将立即数-1复制到低8位的寄存器al

此时,rax的低8位发生了变化

然后,再用指令movw将-1复制给16位寄存器ax

此时,rax的低16位发生了变化

再用movl将立即数-1复制到32位寄存器eax

此时,rax的低32位发生了变化,而且高32位也被置0

  • 64位处理器的规定:movl的目的操作数是寄存器时,它会把寄存器的高4字节设置为0

当源操作数的数位小于目的操作数时,需要对目的操作数剩余的字节进行零扩展或符号位扩展

零扩展数据传送指令有5条,z表示zero,最后两个字符都是大小指示符

movzbw   8->16
movzbl   8->32
movzwl   16->32
movzbq   8->64
movzwq   16->64

符号位扩展传送指令有6条,s表示sign

movsbw  8->16
movsbl  8->32
movswl  16->32
movsbq  8->64
movswq  16->64
movslq  32->64

对比发现,零扩展没有32位到64位的扩展指令,这种情况可以用movl来实现,本身就是可以将高位置0

另外,符号位扩展还有一条没有操作数的特殊指令cltq,源操作数总是eax,目的操作数总是rax,就是对寄存器rax的高32位进行符号位扩展,等价于movslq %eax, %rax


文章作者: kunpeng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kunpeng !
  目录