GCC的调用约定
x32的调用约定
- IA-32
在32位的体系结构中,有3种调用约定,分别是cdecl
,stdcall
,fastcall
,GCC的默认调用约定为cdecl
。参数从右向左压栈,调用者负责在调用后清理堆栈,返回值保存在eax寄存器中,非易失寄存器为ebp
,esp
,ebx
,esi
,edi
。
参考 C Calling Convention
cdecl 调用约定
在这个约定中,调用者自己清理堆栈上的参数(arguments),这样就允许了可变参数列表的实现,如printf()。
cdecl
(C declaration,即C声明)是源起C语言的一种调用约定,也是C语言的事实上的标准。在x86架构上,其内容包括:
- 函数
实参
在线程栈上按照从右至左
的顺序依次压栈
。 - 函数
结果
保存在寄存器EAX
/AX
/AL
中。 浮点型结果
存放在寄存器ST0
中。- 编译后的
函数名前缀
以一个下划线
字符。 调用者
负责从线程栈中弹出实参(即清栈
)。- 8比特或者16比特长的整形实参提升为32比特长。
受
到函数调用影响
的寄存器(volatile registers):EAX
,ECX
,EDX
,ST0
-ST7
,ES
,GS
。不受
函数调用影响
的寄存器:EBX
,EBP
,ESP
,EDI
,ESI
,CS
,DS
。RET
指令从函数被调用者返回到调用者(实质上是读取寄存器EBP所指的线程栈之处保存的函数返回地址并加载到IP寄存器)
x64的调用约定
X86上的一些调用惯例需要通过栈来传递参数,对于X64来说,多数调用惯例都是通过寄存器来传递参数。
- X86-64
x64的调用约定只有一种,遵守system v ABI
的规范。但是Linux和windows却有一些差别。在windows X64中,前4
个参数通过rcx
,rdx
,r8
,r9
来传递,其余的参数按照从右向左
的顺序压栈。在Linux上,则是前6
个参数通过rdi
,rsi
,rdx
,rcx
,r8
,r9
传递,其余的参数按照从右向左的顺序压栈。
更详细的信息参考另一篇文章 system V ABI
参考资料
函数属性(GCC手册)