System V Application Binary Interface(System V ABI,或简称为 SysV ABI)是一个为 UNIX 系统(尤其是基于 System V 版本的 UNIX)定义的应用二进制接口(ABI)。ABI 是在操作系统、硬件、编译器之间进行交互的标准,它确保程序在不同的系统环境中能正确执行。System V ABI 的定义涵盖了多个方面,包括系统调用约定、函数调用约定、寄存器使用规范、堆栈布局、共享库机制、异常处理以及可执行文件格式等。
在 UNIX 和 Linux 系统中,System V ABI 被广泛应用于 x86、x86_64(AMD64)、ARM 等多种架构。对于希望在不同 Linux 发行版之间保持二进制兼容性的软件开发者来说,了解并遵循 System V ABI 的规范是非常必要的。下面将详细介绍 System V ABI 的核心要素。
1. 函数调用约定
函数调用约定(Calling Convention)是 ABI 的重要组成部分,定义了函数调用时参数和返回值的传递方式、寄存器的使用规则以及堆栈的布局。System V ABI 中规定了以下几个方面的内容:
- 参数传递:在 x86_64 架构下,前六个整数类型的参数使用寄存器
RDI
、RSI
、RDX
、RCX
、R8
和R9
传递,额外的参数则通过堆栈传递。浮点参数则使用XMM
寄存器传递。 - 返回值传递:返回值使用寄存器传递,例如整数类型的返回值使用
RAX
,浮点数使用XMM0
。 - 寄存器保存:一些寄存器在函数调用之间需要保持不变(callee-saved),如
RBX
、RBP
、R12
到R15
等。其他寄存器可以在函数调用过程中自由使用(caller-saved)。
2. 寄存器分配与使用
System V ABI 规范规定了特定寄存器的用途,使得不同的函数能够协调一致地使用寄存器。在 x86_64 架构中,寄存器通常分为两类:
- Callee-Saved 寄存器:调用者可以期望这些寄存器在函数调用后仍然保持原值。例如:
RBX
、RBP
、R12
到R15
。 - Caller-Saved 寄存器:调用者在调用函数前需要保存这些寄存器的值。例如:
RAX
、RDI
、RSI
、RDX
、RCX
、R8
、R9
等。
3. 堆栈布局
System V ABI 规范了函数调用时的堆栈布局,以确保各函数之间的参数传递和返回地址的存储符合标准。堆栈以 16 字节对齐的方式操作,从而在调用指令(如 CALL
和 RET
)时避免对齐问题。
- 栈帧(Stack Frame):每次函数调用都会生成一个栈帧,用于存储局部变量、参数和返回地址等。System V ABI 要求栈指针始终保持 16 字节对齐,以便于高效地访问数据。
- 红色区域(Red Zone):在栈帧下方的 128 字节区域称为红色区域,不会被异步信号破坏。函数可以临时使用该区域,适合放置临时变量。
4. 异常处理与栈展开
System V ABI 还定义了异常处理和栈展开(Stack Unwinding)的规则,以便在程序执行过程中发生异常时能够正确地清理栈帧和资源。在 x86_64 架构中,异常处理使用特定的数据结构(如 .eh_frame
),并使用 DWARF 格式描述函数调用帧,以便于调试器和异常处理器解析。
5. 动态链接与共享库
System V ABI 规范了动态链接库(Dynamic Library)和共享库(Shared Library)的加载和调用方式。借助 ELF(Executable and Linkable Format)文件格式的支持,Linux 和 UNIX 系统可以方便地加载共享库并进行动态链接。
- ELF 文件格式:System V ABI 指定使用 ELF 文件格式,其中包含了程序的各种段(Section),如
.text
段(代码段)、.data
段(数据段)等。 - PLT 和 GOT 表:函数调用时,使用 PLT(Procedure Linkage Table) 和 GOT(Global Offset Table)来实现位置无关代码(Position Independent Code,PIC),使得库能够在不同内存地址加载时仍然正确执行。
6. 系统调用约定
System V ABI 还规定了在 Linux 系统上的系统调用约定。在 x86_64 架构上,系统调用使用 SYSCALL
指令发起,并通过特定的寄存器传递参数:
- 系统调用号通过
RAX
寄存器传递。 - 系统调用的第一个参数放入
RDI
,第二个参数放入RSI
,依次类推。 - 系统调用的返回值放入
RAX
。
7. System V ABI 的重要性
System V ABI 的统一标准使得在不同的 Linux 发行版和 UNIX 系统之间保持程序的二进制兼容性成为可能。编译器、操作系统和链接器都遵循该标准,以便在多种硬件和软件环境下能够无缝地运行相同的二进制文件。这对于跨平台软件开发尤为重要,例如在 x86_64 架构上编译的程序可以在任何符合 System V ABI 的 Linux 系统上执行,而无需重新编译。
总结
System V ABI 是 UNIX 和 Linux 系统上应用程序二进制接口的基础标准。它在函数调用、寄存器使用、堆栈布局、异常处理、动态链接和系统调用等方面提供了统一的规范,极大地提升了跨系统的兼容性和程序的稳定性。对于希望在 Linux 和 UNIX 系统上开发跨平台应用程序的开发者,深入理解并遵循 System V ABI 规范,是编写高效、兼容性强的软件的重要步骤。