返回介绍

3.1 调用约定

发布于 2024-10-12 21:58:09 字数 1875 浏览 0 评论 0 收藏 0

调用约定(Calling Conventions)是 应用二进制接口 (ABI)的组成部分,内容包括:

  • 参数和返回值如何传递?(寄存器还是调用栈)
  • 按什么顺序?
  • 谁负责内存分配和清理?

早期常见的有 stdcall, cdecl, fastcall 等,x64 主流只有 Microsoft x64、System V AMD64 两种。

$ readelf -h ./test

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  
  OS/ABI:                            UNIX - System V

System V AMD64

主要用在 Solaris、FreeBSD、Linux、macOS 等系统。

  • 6 参数(整数、指针、结构 ...)依次使用 RDIRSIRDXRCXR8R9
  • 如某参数超过 8 字节,用连续的两个寄存器。
  • 如某参数超过 16 字节,则入栈。对应寄存器给后续参数使用。
  • 浮点数前 8 参数,使用 XMM0 ~ XMM7
  • 整形和浮点混用时,交叉使用 RDI... 和 XMM 等 14 个寄存器。
  • 剩余参数(含前 6 超过 16 字节等参数) 从右往左 依次入栈。
  • 返回值小于等于 8 字节,使用 RAX
  • 小于等于 16 字节,剩余部分用 RDX
  • 大于 16 字节,由调用方负责返回值内存,以寄存器传递内存地址。
typedef struct {
    long long x;
    int y;
    long long z;
} data_t;


void test (data_t d, int a1, int a2, int a3, int a4, int a5, 
                     int a6, int a7, int a8, int a9)
{
	...
}

--- d > 16 bytes ---
    
RDI: a1
RSI: a2
RDX: a3
RCX: a4
R8 : a5
R9 : a6

PUSH a9
PUSH a8
PUSH a7
PUSH d.z, d.y, d.x   // len(d) > 16
void test (int a, float b, int c, float d)

--- 交叉使用 ---
    
RDI : a
XMM0: b
RSI : c
XMM1: d
typedef struct {
    long long x;
    int y;
} data_t;


data_t test () { ... }
    
---- 8 < ret <= 16 bytes ---
    
RAX: ret.x
RDX: ret.y

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文