手写x86汇编时,是否需主动遵守Linux x86调用约定?
Linux x86调用约定:手写汇编时必须主动遵守
核心结论:调用约定不会自动生效,完全需要程序员手动遵守。你看到clang生成的push/pop操作,就是编译器严格遵守约定的表现,手写汇编时你得自己完成对应的操作。
调用约定的本质是一套软件层面的规则,不是CPU硬件强制的。它明确了函数调用过程中的各项标准:
- 参数的传递顺序与存储位置(栈或寄存器)
- 哪些寄存器属于调用者保存:调用函数前,调用者必须自行保存这些寄存器的值,被调用函数可以随意修改它们
- 哪些寄存器属于被调用者保存:被调用函数必须先保存这些寄存器,返回前恢复原值,不能破坏调用者的状态
- 栈帧的维护方式、返回值的传递规则等
具体操作要求:
- 作为调用者(手写汇编调用C函数或其他遵守约定的函数):
- 提前保存「调用者保存」类寄存器(比如cdecl约定里的EAX、ECX、EDX),避免被调用函数修改后丢失数据
- 按照约定顺序将参数压栈(比如cdecl是从右到左)
- 调用结束后按约定清理栈(cdecl由调用者负责,stdcall由被调用者负责)
- 作为被调用者(手写汇编实现供C调用的函数):
- 函数开头必须保存「被调用者保存」类寄存器(比如EBX、ESI、EDI、EBP),通常用push指令压栈
- 函数结束前要通过pop指令恢复这些寄存器的原值,再执行返回操作
- 需维护好EBP栈帧结构,确保调用者的栈状态不被破坏
- 作为调用者(手写汇编调用C函数或其他遵守约定的函数):
你观察到的clang生成的push/pop,要么是调用者在保存自身需要的寄存器,要么是被调用者在履行自身的寄存器保存责任。如果手写汇编时不遵守这些规则,会直接导致栈混乱、寄存器值被意外覆盖、函数调用崩溃等问题。
内容的提问来源于stack exchange,提问作者Tarique
相关产品推荐
相关产品推荐

