x86-64位寄存器(16个)
rax:存放保存函数返回值
rbx:被调用者保存
rdi rsi rdx rcx 对应第1、2、3、4个参数
rsp:栈指针,存放栈帧的栈顶的偏移地址
r8 r9对应第5、6个参数
汇编
寻址
立即数寻址$Imm Imm(立即数)
寄存器寻址%ra R[ra] (寄存器)
绝对寻址Imm M[Imm] (存储器)
间接寻址(%ra)M[R[[ra]]
例题
下面有一点地址或寄存器的值,写出操作数的值
地址 值 寄存器 值
0x100 0xFF rax 0x100
0x104 0xab rcx 0x1
0x108 0x13 rdx 0x3
0x10C 0x11
操作数 值
rax 0x100(寄存器)
0x104 0xab(绝对寻址)
$0x108 0x108(立即数寻址)
(%rax) 0xFF(间接寻址)
指令
两种汇编模式
ATT汇编movq movb
普通汇编 mov rax,rbx=movq %rbx,%rax (ATT):把rbx的值赋给rax
mov
mov 数据传送指令 将数据从一个位置复制到另一个位置的指令
mov 寄存器/立即数 操作数用来指向一个执行所要使用源数据的值,放置结果的目的位置,mov 源操作数的值是一个立即数,值存放在内存或者寄存器中 目的操作数一个寄存器或者是一个内存地址。
单位:1字节 = 8bit 1字 = 8字节 = 64bit
movb 一个字节 (这个字代表双字节的意思,与上边的字不一样)
movw 一个字
movl 双字(寄存器的高四字节设置成0)
movq 四字
movabsq I,R R<-I 传送的是绝对的四字 目的操作数只能是寄存器
movl $0x4050,%eax 4bytes 立即数–寄存器
movw %bp,%sp 2bytes 寄存器–寄存器
movb (%rdi,%rcx),%al 1bytes 内存–寄存器
movb $-17,(%rsp) 1bytes 立即数–内存
movq %rax,-12(%rbp) 8bytes 寄存器–内存l
例题1
movabsq $0x0011223344556677 , %rax = 0011223344556677
( rax包含了eax eax包含了ax ax包含了al)
-1的16进制是0xFFFFFFFFFFFFFF,第一步结束后每一步rax的值是多少
movb $-1 ,%al , %rax = 00112233445566FF F = 1111
movw $-1 , %ax , %rax = 001122334455FFFF
movl $-1 , %eax , %rax = 00000000FFFFFFFF
movq $-1 ,%rax , %rax = FFFFFFFFFFFFFFFF
例题2
把下列汇编代码用c语言表示 (rax一直保存的是返回值)
decode1:
movq (%rdi) , %r8
movq (%rsi) , %rcx
movq (%rdx) , %rax
movq %r8 , (%rsi)
movq %rcx , (%rdx)
movq %rax , (%rdx)
ret
c语言
long decode1(long *xp,long *yp,long *zp){
long x = *xp;
long y = *yp;
long z = *zp;
*yp = x;
*zp = y;
*xp = z;
return z;
}
push和pop
push压入栈 pop弹出栈(pop弹出的值一直是一个最近压入栈的数据且仍在栈中)
由于栈是由大到小增长的,所以栈顶永远是地址最低的 %rsp保存着栈顶的元素
pushq popq 将四字压入栈中 将四字弹出栈
pushq %rbp = subq $8,%rsp movq %rbp,(%rsp) (rsp地址减8)
popq %rax <==> movq (%rsp),(%rax) addq $8,%rsp (rsp地址加8)
pop之后,值不会被删除,除非有一个新的值覆盖了原先的值
算数和逻辑操作
leaq --> 加载有效地址
inc --> 加一
dec --> 减一
neg --> 取负
not --> 取补
add --> 加
sub --> 减
imul --> 乘
xor --> 异或
or --> 或
and --> 与
sal --> 算数左移
sar --> 算数右移
shl -->逻辑左移
shr --> 逻辑右移
1.加载地址
movq的一种变形 从内存读数据到寄存器 但是没有引用内存 不是单纯的读数据,而是将有效地址加载到目的操作数 描述简单的算数操作
例题
rdi = x
leaq 7(%rdi,%rdi,4),%rax == 将rax的值设置为5x+7
2.一元操作和二元操作
只有一个操作数的是一元操作,既是源操作数也是目的操作数
地址 值 寄存器 值
0x100 0xFF rax 0x100
0x108 0xAB rcx 0x1
0x118 0x11 rdx 0x3
subq %rax,%rdx rdx = rdx -rax
addq %rcx , (%rax) ;更新的其实是一个内存位置 位置为0x100
imulq $16,(%rax,%rdx,8) ;更新的内存位置是0x118,值对应的是0x11*16=0x110
他们的目的和最终值写出来
imulq 有符号乘法 一个操作数 这个指令要求就是必须两个数都在寄存器rax中 把高64位存放在rdx,低64位存放在rax里面
salq $4,%rax(左移4位,扩大了2的4次方倍)
控制操作
t = a + b
无符号溢出 CF (条件码)
t==0 ZF
t < 0 SF
(a<0&&b<0) && (t<0 != a <0) 有符号溢出 OF
leaq 不会改变任何条件码 xor 会将进位标志和溢出位标志设置成0
cmpb 比较字节 cmpw 比较字 test 测试
cmp rsi,rdi
cmp根据两个比较数的差来设置条件码 (除了不更新寄存器以外,和sub操作是一样的 test也是除了不更新寄存器以外,和 and 操作是一样的)
testq %rax,%rax 检查rax是负数还是正数还是0
set指令设置条件码