调用约定

在计算机科学中，调用约定（calling convention）是一种定义子过程从调用处接受参数以及返回结果的方法的约定。不同调用约定的区别在于：
 参数和返回值放置的位置（在寄存器中；在调用栈中；两者混合）
 参数传递的顺序（或者单个参数不同部分的顺序）
 调用前设置和调用后清理的工作，在调用者和被调用者之间如何分配
 被调用者可以直接使用哪一个寄存器有时也包括在内。（否则的话被当成ABI的细节）
 哪一个寄存器被当作volatile的或者非volatile的，并且如果是volatile的，不需要被调用者恢复

架构举例
 x86 (32-位) 

32-位版本的x86架构使用了很多不同的调用约定。由于有着少量的架构寄存器，以及在历史上聚焦于简单性和更小代码大小，很多x86调用约定传递实际参数于堆栈之上。返回值（或到它的指针）被返回在一个寄存器中。一些约定对前几个实际参数使用寄存器，这可以增进性能，特别是对于被频繁调用的短小而简单的（就是不调用其他例程的例程）。

例子调用：
  push EAX            ; 传递一些寄存器结果
  push dword [EBP+20] ; 传递一些内存变量(FASM/TASM语法)
  push 3              ; 传递一些常量
  call calc           ; 返回的结果将在EAX中

典型的被调用者结构如下，其中某些或全部（ret除外）指令在简单过程中总是可以被优化掉的：
calc:
  push EBP            ; 保存旧的帧指针
  mov  EBP,ESP        ; 得到新的帧指针
  sub  ESP,localsize  ; 为局部变量预留空间
  .
  .                   ; 进行计算，留下结果于EAX
  .
  mov  ESP,EBP        ; 释放局部变量的空间
  pop  EBP            ; 复原旧的帧指针
  ret  paramsize      ; 释放参数空间并返回
一些约定留下分配的参数空间，使用平常的而非。在这种情况下，调用者可以于此例子中，或者用其他方式处置对ESP的变更。

 x86-64 

64-位版本的x86架构，叫做x86-64、x64、AMD64或Intel 64，有两个公用的调用序列。一个调用序列是Microsoft定义的x64调用约定，用于Windows；另一个调用序列规定于System V AMD64 ABI，用于类Unix系统，并在改动后用于OpenVMS。由于x86-64比32-位x86有更多的通用寄存器，两个约定都传递一些实际参数于寄存器之中。

 ARM (A32) 
标准32-位ARM调用约定分配16个通用寄存器为：
 r15：程序计数器（依据指令集规定）。
 r14：。BL指令，用在子例程调用中，存储返回地址于此寄存器。
 r13：堆栈寄存器。PUSH和POP指令在“Thumb”运行模态下只使用这个寄存器。
 r12：过程调用内部（Intra-Procedure-call）暂存（scratch）寄存器。
 r4 至 r11：局部变量。
 r0 至 r3：传给子例程的实际参数值和从子例程返回的结果值。

如果返回值的类型对于放入r0至r3太大，或者其大小在编译时间不能静态的确定，那么调用者必须在运行时间为这个值分配空间，并传递到这个空间的一个指针于r0，

子例程必须保持（preserve）r4至r11和栈指针的内容，这可以通过在中将其保存至堆栈，接着使用它们为暂存空间，接着在中从堆栈复原它们。特别是，调用其他子例程的子例程，在调用这些其他子例程之前，“必须”将链接寄存器r14中的返回地址保存到堆栈。但是在返回之时，这样的子例程不需要将这个值返回到r14，它们只需要将这个值装载进入程序计数器r15。

ARM调用约定强制使用完全降序的堆栈。此外，栈指针必须总是4-字节对齐，并且在具有公开接口的函数调用上必须总是8-字节对齐。

调用约定导致“典型”的ARM子例程会：
 在前言中，将r4至r11压入到堆栈，并将在r14中的返回地址压入堆栈，这可以通过单一的STM指令完成；
 复制任何要传递的实际参数（在r0至r3中）到局部暂存寄存器（r4至r11）；
 分配其他局部变量到剩余的局部暂存器（r4至r11）；
 进行计算并按需要使用BL调用其他子例程，假定r0至r3、r12和r14会被保持；
 将结果放入r0；
 在结语中，将r4至r11从堆栈取出，并取出返回地址放入程序计数器r15，这可以通过单一的LDM指令完成。

 ARM (A64) 
64-位ARM（AArch64）调用约定分配31个通用寄存器为：

 x31 (SP)：栈指针或零寄存器，依赖上下文。
 x30 (LR)：过程，用于从子例程返回。
 x29 (FP)：帧指针。
 x19 至 x28：被调用者保存。
 x18 (PR)：平台寄存器。用于某些操作系统特定的特殊功能，或一个额外的调用者保存寄存器。
 x16 (IP0) 和 x17 (IP1)：过程调用内部（Intra-Procedure-call）暂存（scratch）寄存器。
 x9 至 x15：局部变量，调用者保存。
 x8 (XR)：间接返回值地址。
 x0 至 x7：传递给子例程的实际参数值和从子例程返回的结果值。

所有以x开始的寄存器都由一个对应的前缀着w的32-位寄存器，比如32-位x0叫做w0。

类似的，32个浮点寄存器被分配为：

 v0 至 v7：传入的实际参数值和从子例程返回的结果值。
 v8 至 v15：被调用者保存，但只有底部64位需要被保持。
 v16 至 v31：局部变量，调用者保存。

参见

 X86调用约定，在Windows与Linux上的调用约定
 语言绑定

 名字修饰
 应用编程接口
 应用二进制接口
 SWIG

参考文献

Category:子程序