关于IA-32过程调用和其中的push、leave、ret指令

博主复习《计算机系统基础》,分享过程调用相关知识。介绍了过程调用的执行步骤,包括调用者和被调用者的操作;讲解了IA - 32的栈、栈帧结构,以及push %ebp、mov %esp,%ebp、leave ret等指令的作用,帮助理解程序执行机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在复(yu)习(xi)《计算机系统基础》这门课程,发现了寄叽还是有很多问题。当时在学的时候没注意到的小细节,现在在这里展开说说,就当是一个记录寄叽学习的过程。我这个人理解能力不太行,我能理解的话,应该大噶看了都能明白。

  1. 过程调用的执行步骤
    假定过程P调用过程Q,则P是调用者(caller),Q是被调用者。过程调用的执行步骤如下:
    ①P将入口参数(实参)放到Q能访问到的位置。
    ②P将返回地址存到特定的地方,然后将控制转移到Q。(返回地址就是CALL指令的下一条指令的地址)
    ③Q保存P的现场,并为自己的非静态局部变量分配空间。
    ④执行Q的过程体(函数体)。
    ⑤Q恢复P的现场,并释放局部变量所占空间。
    ⑥Q取出返回地址,将控制转移到P。

    上述步骤中,
    ①②是在过程P中完成的,其中②是由CALL指令实现的,通过CALL指令,将控制从过程P转移到了过程Q。
    ③④⑤⑥都是在被调用过程Q中完成的:
    在执行Q过程体之前的③通常称为准备阶段,用于保存P的现场并为Q的非静态局部变量分配空间,
    在执行Q过程体之后的⑤通常称为结束阶段,用于恢复P的现场并释放Q的局部变量。

  2. IA-32的栈、栈帧结构
    在了解程序指令代表的含义之前,先了解一下栈、栈帧是什么样子的。
    栈的高地址在上面,低地址在下面。
    在一个栈帧中,ebp(基址指针寄存器)指向的是栈帧的栈底,esp(栈指针寄存器)指向的是栈帧的栈顶。
    esp是由cpu机制决定的,pop、push指令都会自动调整esp的值。
    ebp只是存取某时刻的esp的值,这个时刻就是进入一个函数之后,cpu会将esp的值赋给ebp,此时就可以通过ebp对栈进行操作,比如获取函数参数、局部变量等。实际上用esp也可以,设置ebp是为了方便程序员,因为esp的值会在函数运行时不断发生变化。

  3. push %ebp,mov %esp,%ebp详解
    绝大多数的程序的最前面两条指令都是这个,下面分析以下这两条语句干了什么:
    首先是push %ebp。当前ebp寄存器里保存的是调用者(caller)栈帧的栈底地址,那么push %ebp就是将调用者栈帧的栈底地址压入栈,即保存旧的ebp的值,这里esp的值会自动调整。
    然后是mov %esp,%ebp。刚刚把旧的ebp的值保存下来了,但是ebp的值并没有发生变化。而现在正在执行一个新的函数,那么应该让ebp保存的是新的栈帧的栈底,所以才让当前esp存储的地址赋给ebp。那么这样一来的话,就相当于调用者栈帧的栈顶现在作为了新栈帧的栈底(保存的ebp的旧值属于新栈帧的内容),并且该栈底保存的是调用者栈帧的栈底地址,而此时新的栈帧的栈底和栈顶位于同一个位置。而我们在函数里面是要执行各种操作的,所以我们需要给新栈帧分配一定的内存。在这之前,还可能有一些push语句,这些push语句都是保存调用者的值,以便在函数运行完后再恢复数据。

  4. leave ret指令详解
    leave指令可以使栈做好返回的准备,它等价于mov %ebp,%esp,pop %ebp。首先是mov %ebp,%esp,当前保存的ebp的值使栈帧的栈底地址,所以这一句话的作用就是把esp给放回到调用者栈帧的栈顶,联系到进入函数时的语句mov %esp,%ebp,其实就是这个的逆过程,旨在恢复原来栈顶的状态。然后是pop %ebp,pop是对栈顶元素出栈,而现在的栈顶(也是栈底)存储的是调用者栈帧的栈底地址,这条指令就是把这一地址赋值给ebp(把被保存的ebp的值赋给寄存器ebp)。所以这句话就是恢复调用者栈帧的栈底,这样一来的话调用者栈帧旧基本上恢复到原来的状态了。
    leave只是做好了返回的准备,我们调用完函数之后,调用者还需要接着向下执行指令,那么调用完函数以后就应该跳转到该函数的下一条指令的地址,我们的CALL指令就是先将下一条指令的地址入栈,然后跳转,这里ret的作用就是把那一个地址给弹出栈,并且跳转到地址对应的语句,再接着执行,这样一来一个函数就完整的执行了。

现在我能想到的内容就这么多,有什么想法之后会继续补充。
悲惨的期末人要继续复习了。

<think>好的,用户想要了解x86汇编指令大全。首先,我需要明确用户的需求。可能是编程新手在学习汇编,或者是有经验的开发者需要参考资料。不管怎样,用户需要全面但结构清晰的指令列表,可能需要分类说明,方便查找理解。 接下来,我得回忆x86汇编的主要指令类别。通常分为数据传送、算术运算、逻辑运算、控制转移、堆栈操作、字符串处理、标志位操作、系统调用等。每个类别下有哪些常用指令呢?比如MOV、ADD、SUB这些基础的一定要提到。还要考虑不同位数的操作,比如3264位的区别,但用户可能更关注通用指令,暂时不深入扩展。 然后,要确保每个指令有简单的中文解释示例,比如语法格式,但用户提到要使用行内数学公式,可能用代码块或LaTeX?不过用户要求行内数学表达式用$...$,但汇编指令示例可能更适合用代码块。不过根据系统指令,可能数学表达式才需要LaTeX,而代码示例用普通格式。需要仔细处理。 另外,用户需要结构清晰的回答,分步骤或分类介绍。要避免信息过载,按类别分点,每个指令类别下举几个典型例子,并说明作用。可能还需要注意事项,比如不同环境下的差异,比如NASMMASM语法区别,或者64位系统的变化。 还要检查是否有过时或不常用的指令,确保列出的都是常用核心指令。可能还需要提到一些高级指令,如SIMD相关,但用户如果只需要基础,可能不需要太深入。但“大全”意味着覆盖面广,所以可能需要简要涵盖更多类别。 最后,确保回答符合LaTeX格式要求,数学表达式正确,但汇编指令本身可能不需要LaTeX,除非涉及数学符号。比如位移操作中的乘法,可以用$x \times 2^n$这样的格式。需要根据情况判断。 总结下来,结构应该是先分类,每类下列举指令,给出功能说明示例,注意语法正确,用中文解释清晰。同时可能需要最后的注意事项,提醒用户参考官方文档,注意环境差异等。这样用户既能获得全面的指令列表,又能理解如何应用。</think>以下是对x86汇编指令的整理分类说明,内容结构清晰且符合实际应用场景: ### 一、数据传送指令 1. **MOV** `MOV dest, src` 功能:将数据从源操作数(src)复制到目标操作数(dest) 示例:`MOV EAX, 5` 将立即数5存入EAX寄存器 2. **XCHG** `XCHG op1, op2` 功能:交换两个操作数的值 示例:`XCHG EAX, EBX` 交换EAXEBX的值 3. **LEA** `LEA dest, mem` 功能:计算内存地址偏移量并存入寄存器 示例:`LEA ESI, [EBX+4]` 将EBX+4的地址存入ESI ### 二、算术运算指令 1. **ADD/SUB** `ADD dest, src` / `SUB dest, src` 功能:加减运算($dest = dest \pm src$) 示例:`ADD AX, BX` 将AX与BX相加结果存AX 2. **MUL/DIV** `MUL src` / `DIV src` 功能:无符号乘法/除法 示例:`MUL BL` 将AL与BL相乘,结果存AX 3. **IMUL/IDIV** `IMUL src` / `IDIV src` 功能:有符号乘法/除法 示例:`IDIV ECX` 将EDX:EAX除以ECX ### 三、逻辑运算指令 1. **AND/OR/XOR** `AND dest, src` 功能:按位与/或/异或 示例:`XOR EAX, EAX` 快速清零EAX 2. **NOT** `NOT op` 功能:按位取反 示例:`NOT BYTE PTR [SI]` 反转内存字节 3. **SHL/SHR** `SHL dest, count` 功能:逻辑左移/右移(等价于$dest \times 2^{count}$) 示例:`SHR AX, 3` 将AX右移3位 ### 四、控制转移指令 1. **JMP** `JMP label` 功能:无条件跳转到指定地址 示例:`JMP loop_start` 2. **条件跳转** `JE/JZ` (等于/为零时跳转) `JG/JNLE` (有符号大于跳转) 示例:`CMP EAX, 10` + `JG larger` 若EAX>10则跳转 3. **CALL/RET** `CALL proc` / `RET` 功能:调用程序/返回主程序 示例:`CALL print_string` ### 五、堆栈操作指令 1. **PUSH/POP** `PUSH src` / `POP dest` 功能:压栈/弹栈操作 示例:`PUSHAD` 保存所有通用寄存器 2. **ENTER/LEAVE** 功能:创建/释放堆栈帧 示例:`ENTER 16,0` 分配16字节堆栈空间 ### 六、字符串操作指令 1. **MOVS** `MOVSB/MOVSW/MOVSD` 功能:按字节/字/双字传送字符串 需配合ESI/EDI寄存器使用 2. **CMPS** `CMPSB/CMPSW/CMPSD` 功能:字符串比较 ### 七、系统相关指令 1. **INT** `INT n` 功能:触发软中断 示例:`INT 0x80` Linux系统调用 2. **SYSCALL/SYSRET** 功能:x86_64快速系统调用 ### 八、标志位操作 1. **STC/CLC** 功能:设置/清除进位标志(CF) 2. **STD/CLD** 功能:设置/清除方向标志(DF) ### 注意事项 1. 不同汇编器(NASM/MASM/GAS)语法存在差异 2. 64位模式下部分指令行为改变(如PUSH立即数扩展) 3. 现代CPU优化建议使用更高效的指令组合 > 完整指令集超过2000条,建议通过Intel官方手册《Intel® 64 and IA-32 Architectures Software Developer’s Manual》查阅详细说明。实际编程时应结合调试工具(如GDB)验证指令行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值