x86-64的CPU包含一组16个存储64位值的通用目的寄存器,用于存放整数和指针。
注意:
操作数类型分为
常用形式Imm(rb,ri,s)
基址变址寄存器rb和ri必须是64位寄存器,s只能是1、2、4、8。有效地址的计算为Addr=Imm+R[rb]+R[ri]*s,所以以操作数形式出现的Imm(rb,ri,s)表示M[Imm(rb,ri,s)]。
其他形式都是此形式的变式,Imm表示M[Imm],(rb)表示以R[rb]为有效地址的M[R[rb]]。
mov指令
movabsq $0x0011223344556677,%rax ;%rax=0011223344556677
movb $-1,%al ;%rax=00112233445566FF
movw $-1,%ax ;%rax=001122334455FFFF
movl $-1,%eax ;%rax=00000000FFFFFFFF
movq $-1,%rax ;%rax=FFFFFFFFFFFFFFFF
movz指令(零扩展,将较小源值复制到较大目的)
注意:在mov指令中源操作数为双字(后缀l)将高位设为0,因而movz指令缺少movzlq。
movabsq $0x0011223344556677,%rax ;%rax=0011223344556677
movb $0xAA,%dl ;%dl=AA
movb %dl,%al ;%rax=00112233445566AA
movzbq %dl,%rax ;%rax=00000000000000AA
movsbq %dl,%rax ;%rax=FFFFFFFFFFFFFFAA
将四字值压入栈,首先将栈指针减8,然后将值写入新栈顶地址。因此下式相等,区别在于pushq只有一个字节,而两条指令要8个字节。
pushq %rax = subq $8,%rsp ;Decrement stack pointer
movq %rax,(%rsp) ;Store %rax on stack
pop %rax = movq (%rsp),%rdx ;Read %rdx from stack
addp $8,%rsp ;Increment stack pointer
形式是从内存读数据到寄存器,实际上没有引用内存,并不是从内存读数据带到寄存器,而是将有效位置带到寄存器,例如M[R[rb]]中的有效地址R[rb]。
两个用法:
C程序代码
long scale(long x,long y,long z){
long t=x+4*y+12*z;
return t;
}
汇编代码
;long scale(long x,long y,long z)
;x in %rdi,y in %rsi,z in %rdx
scale:
leaq (%rdi,%rsi,4),%rax ;x+4*y
leaq (%rdx,%rdx,2),%rdx ;z+2*z=3*z
leaq (%rax,%rdx,4),%rax ;(x+4*y)+4*(3*z)=x+4*y+12*z
ret
C程序代码
long arith(long x,long y,long z){
long t1=x^y;
long t2=z*48;
long t3=t1&0x0F0F0F0F;
long t4=t2=t3;
}
汇编代码
;long arith(long x,long y,long z)
;x in %rdi,y in %rsi,z in %rdx
arith:
xorq %rsi,%rdi ;t1=x^y
leaq (%rdx,%rdx,2),%rax ;3*z
salq $4,%rax ;t2=16*(3*z)=48*z
andl $252645135,%edi ;t3=t1&0x0F0F0F0F
subq %rdi,%rax ;t2-t3
ret
上面代码可以看出