Skip to content

x86 汇编语言详细笔记

1. 高级语言与机器代码的对应关系

汇编语言是机器代码的符号化表示,直接对应处理器指令。高级语言(如 C/C++)通过编译器生成汇编代码,再转换为机器码(二进制)。

1.1 编译过程示例

以 C 语言代码为例:

c
int add(int a, int b) {
    return a + b;
}

GCC 生成的 AT&T 格式汇编(32 位)

assembly
add:
    push   %ebp
    mov    %esp, %ebp
    mov    0x8(%ebp), %eax   ; 取第一个参数a
    add    0xc(%ebp), %eax   ; 加上第二个参数b
    pop    %ebp
    ret

对应的机器码(十六进制):

55 89 E5 8B 45 08 03 45 0C 5D C3
  • 55push %ebp
  • 89 E5mov %esp, %ebp
  • 8B 45 08mov 0x8(%ebp), %eax
1.2 反汇编工具
  • objdumpobjdump -d 可执行文件
  • GDBdisassemble 函数名

2. AT&T 格式与 Intel 格式的对比

x86 汇编有两种主流语法:AT&T(GCC 默认)和 Intel(NASM/MASM)。

特性AT&T 格式Intel 格式
操作数顺序源操作数在前,目标在后目标在前,源在后
寄存器前缀%(如%eax无(如eax
立即数前缀$(如$0x10无(如10h
内存引用符号()(如(%eax)[](如[eax]
指令后缀操作数大小(如movl表示 32 位)无(通过操作数推断,如dword ptr
示例对比
assembly
; AT&T格式
movl $0x10, %eax       ; 将立即数0x10加载到eax
addl 4(%ebx), %eax     ; eax += *(ebx + 4)

; Intel格式
mov eax, 10h           ; 同AT&T第一行
add eax, [ebx + 4]     ; 同AT&T第二行

3. 常用 x86 汇编指令

3.1 数据传送指令
指令功能示例
mov数据移动mov %eax, %ebx(AT&T)
push压栈push $0x20
pop弹栈pop %eax
lea加载有效地址lea (%eax,%ebx,4), %ecx
3.2 算术运算
指令功能示例
add加法add $5, %eax
sub减法sub %ebx, %eax
mul无符号乘法(结果在 EDX:EAX)mul %ebx
div无符号除法(除数在 EDX:EAX)div %ebx
3.3 逻辑运算
指令功能示例
and按位与and $0x0F, %al
or按位或or %ebx, %eax
xor按位异或xor %eax, %eax(清零 eax)
not按位取反not %eax
3.4 控制流指令
指令功能示例
jmp无条件跳转jmp label
call调用函数call func
ret函数返回ret
cmp比较操作数cmp $10, %eax
test位测试(常用于逻辑判断)test %eax, %eax
3.5 条件跳转指令
指令触发条件说明
je/jz相等/结果为 0je label
jne/jnz不等/结果非 0jne label
jg有符号大于jg label
jl有符号小于jl label
ja无符号大于ja label
jb无符号小于jb label

4. 选择语句的机器级表示

4.1 if-else 语句

C 代码:

c
if (a > b) {
    max = a;
} else {
    max = b;
}

对应的 AT&T 汇编

assembly
movl a, %eax     ; 加载a到eax
movl b, %ebx     ; 加载b到ebx
cmp %ebx, %eax   ; 比较eax和ebx(a - b)
jle else_block   ; 若a <= b,跳转到else
movl %eax, max   ; max = a
jmp end_if       ; 跳过else块
else_block:
movl %ebx, max   ; max = b
end_if:
4.2 switch-case 语句

编译器通常将switch转换为跳转表(Jump Table)或连续cmp指令。


5. 循环语句的机器级表示

5.1 while 循环

C 代码:

c
int i = 0;
while (i < 10) {
    sum += i;
    i++;
}

对应的 AT&T 汇编

assembly
movl $0, %eax       ; eax = i = 0
movl $0, %ebx       ; ebx = sum = 0
loop_start:
cmp $10, %eax       ; 比较i和10
jge loop_end        ; 若i >= 10,跳出循环
add %eax, %ebx      ; sum += i
inc %eax            ; i++
jmp loop_start      ; 继续循环
loop_end:
5.2 for 循环

C 代码:

c
for (int i=0; i<10; i++) {
    sum += i;
}

汇编实现与while完全相同(编译器优化后)。


6. 内存寻址模式

x86 支持多种寻址方式,用于访问复杂数据结构(如数组、结构体)。

6.1 常见寻址模式
模式示例(AT&T)说明
直接寻址movl 0x1000, %eax访问固定地址
寄存器间接寻址movl (%ebx), %eax地址由寄存器给出
基址+偏移movl 4(%ebx), %eax地址 = ebx + 4
基址+变址+比例因子movl (%ebx,%ecx,4), %eax地址 = ebx + ecx*4
6.2 数组访问示例

C 代码:

c
int arr[3] = {10, 20, 30};
int val = arr[2];

AT&T 汇编

assembly
movl $2, %ecx           ; 索引ecx=2
movl arr(,%ecx,4), %eax ; eax = arr[2](地址 = arr + ecx*4)

7. 栈帧与函数调用

7.1 栈帧结构
  • ebp:栈基址指针(指向当前栈帧底部)。
  • esp:栈顶指针。
7.2 函数调用示例

C 代码:

c
int add(int a, int b) {
    return a + b;
}
int main() {
    add(3, 5);
}

AT&T 汇编

assembly
main:
    push $5         ; 参数b
    push $3         ; 参数a
    call add        ; 调用函数
    add $8, %esp    ; 清理栈(平衡堆栈)

add:
    push %ebp
    mov %esp, %ebp
    mov 8(%ebp), %eax   ; 取a
    add 12(%ebp), %eax  ; 加b
    pop %ebp
    ret

8. 高级主题

8.1 SIMD 指令集
  • SSE/AVX:用于向量化计算(如并行处理浮点数)。
  • 示例:movaps(对齐加载)、addps(浮点向量加法)。
8.2 内联汇编

在 C 代码中嵌入汇编(GCC 语法):

c
int a = 10, b;
asm("movl %1, %%eax; add $5, %%eax; movl %%eax, %0"
    : "=r"(b)      // 输出
    : "r"(a)       // 输入
    : "%eax"       // 破坏的寄存器
);

9. 调试与分析工具

  • GDB:单步调试、查看寄存器和内存。
  • strace:跟踪系统调用。
  • perf:性能分析。

总结

x86 汇编语言是理解计算机底层运行机制的关键。通过分析高级语言与汇编的对应关系、掌握常用指令和控制结构,能够深入优化代码、分析二进制程序或进行逆向工程。实践中建议结合反汇编工具和调试器逐步验证逻辑。