x86_64常用汇编

本文用以记录常用汇编指令以供快速查找回忆,仅限于 X86_64 的 AT&T 格式。

语法格式

1. 引用寄存器前加 %。如

1
mov    %rsp, %rbp

2. 指令长度后缀

对于访问内存的数据,指令后加上 b w l q,操作 1 2 4 8 字节。如

1
2
3
4
movb   $0x1,0x201c3f(%rip)
nopw %cs:0x0(%rax,%rax,1)
movl $0x5,-0xc(%rbp)
movq $0x400b30,-0x18(%rbp)

3. 立即数前加 $。16 进制数用 0x 开头。如

1
2
movl   $1, %eax
mov $0x0,%eax

4. 注释可以用 ! 开头,也可以用 ;

5. 操作数顺序

从源操作数到目的操作数,如下将 %rsp 寄存器中的数传给 %rbp 寄存器。

1
mov    %rsp,%rbp

6. 数据声明

命令 数据类型
.ascii 文本字符串
.asciz 以空字符串结尾的文本字符串
.byte 字节值
.double 双精度浮点数
.float 单精度浮点数
.single 单精度浮点数同上
.int 32位整数
.long 32位整数同上
.octa 16字节整数
.quad 8字节整数
.short 16位整数
.comm 声明未初始化的数据的通用内存区域
.lcomm 声明未初始化的数据的本地通用内存区域

7. 文件组成

命令 作用
.org 定义当前汇编位置
.globl 让段全局可见
.text 存放代码指令正文段
.bss 存放未初始化的全局和静态变量,运行时该区域初始化为 0
.rodata read only data
.data 可读可写的数据段

8. 寻址方式

  • 直接寻址:把某个地址上的值放到寄存器中
1
mov    $0x8000,%eax
  • 间址寻址:把寄存器上的值所代表的地址所指向的值放到寄存器中
1
2
movl   $0x8000,%ebx  
movl (%ebx),%eax ; 间址寻址, 把地址 0x8000(在寄存器 %ebx 中)上的值放到 %eax 中
  • 基址寻址:以寄存器里的数值作为基址,加上一个常数得到最终地址,把地址上的值放到寄存器中
1
2
movl   $0x8000,%eax  
movl 4(%eax),%ebx ; 基址寻址, 把地址 0x8004(0x8000+4)上的值放到 %eax 中
  • 变址寻址:以两个寄存器里的数值之和加上一个常数得到最终地址,把地址上的值放到寄存器中
1
2
3
4
movl   $0x8000,%eax
movl $0x4,%ebx
movl (%eax,%ebx),%ecx ; 变址寻址, 把地址 0x8004(0x8000+4)上的值放到 %ecx 中
movl 4(%eax,%ebx),%ecx ; 变址寻址, 把地址 0x8008(0x8000+4+4)上的值放到 %ecx 中
  • 比例变址寻址:以一个寄存器里的数值加上另一个寄存器里的数字,乘以一个比例因子(1,2,4,8)再加上一个常数得到最终地址,把地址上的值放到寄存器中
1
2
3
4
5
6
movl   $0x2000,%eax   
movl $0x2,%ebx
movl (,%eax,4),%ecx ; 比例变址寻址, 把地址 0x8000(0 + 0x2000*4)上的值放到 %ecx 中
movl 6(,%eax,4), %ecx ; 比例变址寻址, 把地址 0x8006(0 + 0x2000*4 + 6)上的值放到 %ecx 中
movl (%ebx,%eax,4),%ecx ; 比例变址寻址, 把地址 0x8002(0x2 + 0x2000*4)上的值放到 %ecx 中
movl 6(%ebx,%eax,4),%ecx ; 比例变址寻址, 把地址 0x8008(0x2 + 0x2000*4 + 6)上的值放到 %ecx 中

常见指令

1. mov 用于将源操作数移动到目的操作数

1
mov    %rsp,%rbp      ; %rbp = %rsp

2. add 用于将源操作数加给目的操作数

1
addl   %eax,%ebx      ; %ebx = %ebx + %eax

3. sub 用于将两个数相减

1
subl   %eax,%ebx      ; %ebx = %ebx - %eax

4. inc 用于加一

1
incl   %eax           ; %eax = %eax + 1

5. dec 用于减一

1
decl   %eax           ; %eax = %eax - 1

6. push 用于将数据压入栈

1
pushl  %eax           ; 入栈,%esp = %esp - 0x4, %esp = %eax 

7. pop 用于将数据出栈

1
popl   %eax           ; 出栈,%eax = %esp, %esp = %esp + 0x4

8. jmp 跳转

1
2
3
4
5
6
7
8
9
10
11
jmp    label          ; 无条件跳转为 label, %rip = label
je label ; 相等 ZF = 1, %rip = label
jne label ; 不相等 ZF = 0, %rip = label
jg label ; 大于 %rip = label
jge label ; 大于等于 %rip = label
jl label ; 小于 %rip = label
jle label ; 小于等于 %rip = label
ja label ; 无符号比较 大于 %rip = label
jae label ; 无符号比较 大于等于 %rip = label
jb label ; 无符号比较 小于 %rip = label
jbe label ; 无符号比较 小于等于 %rip = label

9. mul 乘法

1
2
imull  %eax,%ebx      ; %ebx = %eax * %ebx  用于有符号数
mull %eax,%ebx ; %ebx = %eax * %ebx 用于无符号数

10. div 除法

1
2
idivl  %ebx           ; %edx = %eax % %ebx, %eax = %eax / %ebx  用于有符号数
divl %ebx ; %edx = %eax % %ebx, %eax = %eax / %ebx 用于无符号数

11. and 按位与

1
andl   %eax,%ebx      ; %ebx = %ebx & %eax

12. or 按位或

1
orl    %eax,%ebx      ; %ebx = %ebx | %eax

13. xor 按位异位

1
xorl   %eax,%ebx      ; %ebx = %eax ^ %ebx

14. shl 和 sal 位左移

1
2
shll   $1,%eax        ; %eax = %eax << 1  逻辑左移,填充 0
sall $1,%eax ; %eax = %eax << 1 算数左移,填充 0

15. shr 和 sar 位右移

1
2
shrl   $1,%eax        ; %eax = %eax >> 1  逻辑右移,填充 0
sarl $1,%eax ; %eax = %eax >> 1 算数右移,填充 符号位

16. lea 装载有效地址

1
leal   8(%ebx),%eax   ; %eax = 8 + %ebx 可理解为 %eax = &(*(%ebx)) + 8

17. call 函数调用

1
call   func_name      ; 将下一条指令的 %rip push 到栈中,之后 %rip = func_name 

18. ret 函数返回

1
ret                   ; 将函数返回地址的下一条要执行指令的值赋值给 %rip,push %rip

19. test 与运算并设置标志寄存器

1
testl  %eax,%ebx      ; %eax & %ebx,不会改变这两个寄存器值,改变标志寄存器零标志位(ZF)、符号标志位(SF)、奇偶标志位(PF)和进位标志位(CF),但不会影响溢出标志位(OF)

20. cmp 比较操作数大小

1
cmpl   %eax,%ebx      ; 根据 %ebx - %eax 的值来改变零标志位(ZF)、符号标志位(SF)、奇偶标志位(PF)、进位标志位(CF)和溢出标志位(OF)

21. rep 重复执行指令直到某一条件

1
2
repz   movsb          ; 重复执行 movsb 直到 ZF = 0
repne scasb ; 重复执行 scasb 直到 ZF = 1

22. lock 锁定总线

1
lock addl $1,(%eax)   ; 锁定总线,并使 *(%eax) = *(%eax) + 1,因为总线是锁定的,不会被其他处理器打断

23. xadd 交换两个操作数值,使他们相加

1
xaddl  %eax,%ebx      ; tmp = %eax,%eax = %ebx,%ebx = tmp + %ebx 交换两个数,并将和写到 %ebx

24. nop 空操作

1
nop                   ; 什么都不做,充当占位符或者插入延迟

25. hlt 使处理器暂停直到收到中断信号

1
hlt                   ; 使处理器进入暂停状态,直到发生外部中断。它通常用于操作系统内核中,以降低功耗和发热量。只有特权级别为 0 (内核态) 才能使用,否则会导致异常

26. xchg 交换两个操作数的值

1
xchgl  %eax,%ebx       ; tmp = %eax,%eax = %ebx,%ebx = tmp

27. cld 清除方向寄存器(DF)

1
cld                    ; 清除方向寄存器,使 %rdi 递增

28. movsb 移动字符串

1
movsb                  ; 以 %rsi 为源地址,%rdi 为目的地址,将字符以一个字节拷贝。每次执行 movsb,%rsi 和 %rdi 以方向标志寄存器(DF)自动递增或递减

29. scasb 查找字符

1
scasb                  ; 将被查找字符放到 %al 中,与 %rdi 地址的字符串依次比较,根据比较结果设置标志寄存器

30. cli 禁用所有中断

1
2
cli                    ; 禁用所用中断
hlt ; 使处理器保持暂停状态,直到中断被重新启用