汇编指令格式

目录

一、C 语言与汇编的关系

1. 查看 C 代码的汇编输出

二、汇编指令基础格式

常见寄存器(x86-64架构)

三、C 代码与汇编指令对照

示例 1:简单加法

示例 2:函数调用

四、内存访问与寻址模式

1. 直接寻址

2. 寄存器间接寻址

3. 基址偏移寻址

五、关键指令详解

六、实战:循环结构

七、如何深入学习?


一、C 语言与汇编的关系

C 代码通过编译器(如 GCC)转换为汇编指令,最终生成机器码。汇编是 C 和机器码之间的桥梁,直接操作寄存器、内存和 CPU 指令。

1. 查看 C 代码的汇编输出

使用 GCC 生成汇编代码:

gcc -S -O0 -masm=intel test.c  # 生成 Intel 格式汇编(test.s)
  • -O0:禁用优化,保留代码原始结构

  • -masm=intel:指定 Intel 汇编语法(更易读)

二、汇编指令基础格式

Intel 格式汇编指令一般结构:

指令 [目标操作数], [源操作数]   ; 注释
  • 指令:操作类型(如 movaddcall

  • 操作数:寄存器、内存地址、立即数

  • 注释:用 ; 开头,解释代码逻辑

常见寄存器(x86-64架构)

三、C 代码与汇编指令对照

示例 1:简单加法

C 代码

int main() {
    int a = 10;
    int b = 20;
    int c = a + b;
    return c;
}

对应汇编(关键部分):

main:
    push    ebp               ; 保存旧的基址指针
    mov     ebp, esp          ; 设置新的栈帧基址
    sub     esp, 16           ; 为局部变量分配栈空间(16字节对齐)

    mov     DWORD PTR [ebp-4], 10   ; a = 10(存储到栈地址 ebp-4)
    mov     DWORD PTR [ebp-8], 20   ; b = 20(存储到栈地址 ebp-8)

    mov     eax, DWORD PTR [ebp-4]  ; 将a的值加载到eax
    add     eax, DWORD PTR [ebp-8]  ; eax = eax + b(即a + b)
    mov     DWORD PTR [ebp-12], eax  ; c = eax(结果存到ebp-12)

    mov     eax, DWORD PTR [ebp-12] ; 返回值存入eax
    leave                          ; 恢复栈帧(mov esp, ebp; pop ebp)
    ret                           ; 函数返回

关键点

  • 局部变量存储在栈上:通过 ebp - offset 访问(如 ebp-4)。

  • 运算通过寄存器中转:先将变量加载到 eax,再执行 add 操作。

  • 返回值通过 eax 传递:函数结束时,eax 的值即返回值。

示例 2:函数调用

C 代码

int add(int x, int y) {
    return x + y;
}

int main() {
    int result = add(3, 5);
    return result;
}

对应汇编(关键部分):

add:
    push    ebp
    mov     ebp, esp
    mov     eax, DWORD PTR [ebp+8]   ; 取第一个参数x(ebp+8)
    add     eax, DWORD PTR [ebp+12]  ; 加第二个参数y(ebp+12)
    pop     ebp
    ret

main:
    push    ebp
    mov     ebp, esp
    sub     esp, 16
    push    5                ; 第二个参数压栈
    push    3                ; 第一个参数压栈
    call    add              ; 调用函数
    add     esp, 8           ; 清理栈上的参数(2个int,共8字节)
    mov     DWORD PTR [ebp-4], eax  ; result = eax
    mov     eax, DWORD PTR [ebp-4]  ; 返回值
    leave
    ret

关键点

  • 参数传递:通过栈传递参数(32位模式下),ebp+8 是第一个参数,ebp+12 是第二个参数。

  • 函数调用步骤

    1. 参数从右向左压栈(先 push 5,再 push 3)。

    2. call 指令将返回地址压栈,并跳转到函数。

    3. 函数返回后,调用者负责清理栈上的参数(add esp, 8)。

四、内存访问与寻址模式

汇编通过不同寻址方式访问内存:

1. 直接寻址
mov eax, DWORD PTR [0x12345678]  ; 从内存地址0x12345678加载数据到eax
2. 寄存器间接寻址
mov ebx, 0x12345678
mov eax, DWORD PTR [ebx]         ; 通过ebx中的地址访问内存
3. 基址偏移寻址
mov eax, DWORD PTR [ebp-4]       ; 访问栈上的局部变量(基址为ebp)

五、关键指令详解

六、实战:循环结构

C 代码

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

对应汇编(关键部分):

main:
    push    ebp
    mov     ebp, esp
    sub     esp, 16
    mov     DWORD PTR [ebp-4], 0   ; sum = 0
    mov     DWORD PTR [ebp-8], 0   ; i = 0
.L2:
    cmp     DWORD PTR [ebp-8], 10  ; 比较i和10
    jge     .L4                    ; 如果i >= 10,跳转到.L4(退出循环)
    mov     eax, DWORD PTR [ebp-8] ; eax = i
    add     DWORD PTR [ebp-4], eax ; sum += eax
    add     DWORD PTR [ebp-8], 1   ; i++
    jmp     .L2                    ; 跳转回.L2(继续循环)
.L4:
    mov     eax, DWORD PTR [ebp-4] ; 返回值sum
    leave
    ret

关键点

  • 循环控制:通过 cmp 和条件跳转指令(如 jge)实现。

  • 标签(Label).L2 和 .L4 是编译器生成的跳转标签。

七、如何深入学习?

  1. 查看编译后的汇编
    使用 gcc -S 生成汇编代码,结合 -O0(无优化)和 -O2(优化)对比分析。

  2. 调试器分析
    用 GDB 单步执行程序,观察寄存器和内存变化。

  3. 参考手册参考手册http://Intel 64 and IA-32 Architectures Software Developer Manuals

  4. 实践练习
    尝试用汇编重写简单 C 函数(如计算阶乘)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值