汇编基础知识

分类

通用目的寄存器

64 位 32 位 16 位
RAX EAX AX
RBX EBX BX
RCX ECX CX
RDX EDX DX
RSI ESI SI
RDI EDI DI
RBP EBP BP
RSP ESP SP
R8-R15

段寄存器

32 位 16 位
CS CS
DS DS
ES ES
SS SS
FS
GS

指令指针寄存器

64 位 32 位 16 位
RIP EIP IP

标志寄存器

64 位 32 位 16 位
RFLAGS EFLAGS FLAGS

用途

  • rax/eax: 默认累加寄存器,乘法等操作会将其中一部分结果自动存放到 rax/eax 中,调用函数的时候也需要把返回值保存在 rax/eax 中。执行这些操作时不要用 rax/eax 保存一般数据。
  • rcx/ecx: 在执行循环的过程中记录循环计数器的值。在循环内部不要用 rcx/ecx 保存一般数据。
  • rbp/ebp: 用作栈帧中的帧指针。用来指向栈中的数据,应只当作专门寄存器使用。
  • rsp/esp: 栈指针寄存器。指向活动栈帧的顶部,应只当作专门寄存器使用。
  • rsi/esi & rdi/edi: 索引寄存器(变址寄存器)。与 STOSB、MOVSB、SCASB 这些字符串操作结合使用,以保存、加载、或扫描大量数据。这些操作会把 CPU 置于一种自动循环模式中,比开发者手工编写循环更有效率。
  • rip/eip: 扩展版指令指针寄存器。指向内存中的地址,以表示接下来应该获取、解码并执行的指令。在程序运行过程中自动调整,不应该通过编程修改。
  • rflags/eflags: 状态与控制寄存器。LAHF、SAHF 等特殊指令会把 CPU 的一些状态标志载入 ah 寄存器,或是将 ah 寄存器的值保存到状态寄存器中。除此之外,不应该用其他手段直接修改 rflags/eflags。该寄存器中的二进制位是在执行完算术运算之后根据一套布尔规则自动设置的。尽管 rflags 是 64 位,但其中能够用到的只有低 32 位,因此 x86 与 x86_64 处理器用的是同一套状态标志。

标志位

标志 代号 二进制位位置 备注
Carry(进位) CF 0000 0000 0001(0) 无符号整数的加法最高有效位需要进位、无符号整数的减法最高有效位需要借位
Parity(奇偶;校验) PF 0000 0000 0100(2) 结果中值为 1 的二进制位是偶数个
Auxiliary Carry(辅助进位)、Adjust(调整) AF 0000 0001 0000(4) BCD(以二进制形式编码的十进制数)运算中,低 4 位(二进制位)需要向高 4 位进位或借位
Zero(零) ZF 0000 0100 0000(6) 运算结果为 0
Sign(符号) SF 0000 1000 0000(7) 运算结果是负值(结果以补码形式表示最高有效位是 1)
Interrupt(中断) IF 0010 0000 0000(9) 如果该标志位 set,计算机就能够处理可屏蔽的硬件中断或者说中断请求
Direction(方向) DF 0100 0000 0000(10) clear,字符串按从左到右的顺序处理,体现为 rsi/esi 及 rdi/edi 这两个字符串索引寄存器会在每次字符串操作后递增。set,按照从右到左的顺序处理
Overflow(溢出) OF 1000 0000 0000(11) set,运算结果以补码形式表示时所需二进制位超过该运算所采取的个数。此标志针对带符号整数

通过 LAHF/SAHF 指令可以编辑的标志位及序号

7 6 5 4 3 2 1 0
SF ZF U AF U PF U CF

1、3、5 号二进制位是用不到的保留位。通过 SAHF 指令把 ah 的内容保存到标志寄存器时,这些二进制位的值不应该改变,3、5 始终为 0,1 号始终为 1。

立即数基数

基数 进制
b Binary
d Decimal
h Hexadecimal
q、 o Octal

程序段

GAS MASM NASM 备注
.bss .data SECTION .bss 未初始化变量
.data .data SECTION .data 已初始化变量
.text .code SECTION .text 代码段

数据定义

名称 大小
DB 1 byte
DW 2 byte
DD 4 byte
DQ 8 byte
DT 10 byte
名称 大小
BYTE 1 byte
WORD 2 byte
DWORD 4 byte
QWORD 8 byte
TBYTE 10 byte
NASM GAS MASM 类型
DB .byte, .ascii DB, BYTE 8 位整数
SBYTE 8 位带符号整数
DW .word DW, WORD 16 位整数
SWORD 16 位带符号整数
DD .long DD, DWORD 32 位整数
SDWORD 32 位带符号整数
DQ .quad DQ, QWORD 64 位整数
DT DT, TBYTE 80 位整数
.octa 128 位整数
NASM GAS 类型
RESB .lcomm 保留 8 位
RESW 保留 16 位
RESD 保留 32 位
RESQ 保留 64 位
REST 保留 80 位

命令

汇编:nasm -f {elf32|elf64} -o out.o source.asm 链接:ld -e _main -melf_i386 -o out source.o clang -o out -m32 source.o gcc -o out -m32 source.o

内联汇编代码 x86 约束修饰符

  • r、R:通用寄存器
  • q:寄存器中的低 8 位
  • Q:寄存器中的高 8 位
  • a、b、c、d:ax/eax/rax、bx/ebx/rbx、cx/ecx/rcx、dx/edx/rdx
  • S:si/esi/rsi
  • D:di/edi/rdi
  • A:ax/eax/rax 和 dx/edx/rdx,存放双字结果
  • f:任何一个 x87 栈寄存器
  • t:x87 栈顶 st0
  • u:x87 第二个寄存器 st1
  • y:任何一个 MMX 寄存器
  • x:任何一个 SSE 寄存器
  • m:任何一个内存操作数
  • o:可用作偏移量的内存操作数
  • V:不用做偏移量的内存操作数
  • g:任何一个通用寄存器或内存或立即数
  • X:任何操作数
  • p:可以作为有效内存地址即指针来使用的操作数
  • i:可以当成立即常量来使用的整数操作数
  • F:可以当成立即常量来使用的浮点操作数

内联汇编方言设置

代码声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
asm(".att_syntax \n\t"
"mov $1, %%eax \n\t"
"mov $0, %%ebx \n\t"
"add %%ebx, %%eax \n\t"
:
:
: "%eax", "%ebx"
);

asm(".intel_syntax noprefix \n\t"
"mov eax, 1 \n\t"
"mov ebx, 0 \n\t"
"add eax, ebx \n\t"
:
:
: "eax", "ebx"
);

命令指定

1
2
-masm=att
-masm=intel
分享