Application Binary Interface(ABI) 是指应用程序在二进制级别上的调用约定和数据布局规则。它决定了一个程序如何与操作系统、库或其他程序的二进制部分交互。ABI 是在编译后的程序之间的接口,而不是在源码层面的接口。
ABI 的主要内容
函数调用约定(Calling Conventions)
定义了函数调用时:
参数如何传递(通过寄存器还是栈)。
返回值如何传递。
函数调用前后由谁负责保存寄存器(调用者还是被调用者)。
示例:
在 x86 平台上,Windows 使用 stdcall,Linux 使用 cdecl。
参数的顺序和方法可能不同,比如先传递右边的参数还是左边的。
二进制符号(Symbol Naming)
决定编译后的函数或变量符号在二进制文件中的命名规则。
C 的 ABI 通常直接使用函数名,例如 _add。
C++ 的 ABI 通常会进行名称修饰(Name Mangling)以支持函数重载,例如 _Z3addii。
数据类型的布局和对齐(Data Layout and Alignment)
定义了:
基本类型(如 int、double)的大小。
结构体和类的内存对齐规则。
字节序(大端或小端)。
异常处理(Exception Handling)
规定在不同模块或库之间如何传递和处理异常,特别是跨语言的异常。
动态链接(Dynamic Linking)
描述动态链接库(如 .so 或 .dll 文件)在加载和调用时的接口规则。
ABI 的作用
ABI 的核心作用是确保 二进制兼容性,即:
不同的模块(如动态库和主程序)可以协同工作,即使它们是由不同编译器编译的。
应用程序能够在某个硬件和操作系统平台上正常运行。
举例:C 和 C++ 的 ABI 差异
在 C 中:
int add(int a, int b) {
return a + b;
}
生成的二进制符号可能是:_add。
在 C++ 中:
int add(int a, int b) {
return a + b;
}
生成的二进制符号可能是:_Z3addii(因为 C++ 支持函数重载,需要进行名称修饰)。
因此,C++ 函数如果需要被其他语言或工具调用,就必须使用 extern "C" 以禁用名称修饰,从而遵循 C 的 ABI。
ABI 的重要性
跨语言调用:通过一致的 ABI,C 语言库可以被多种语言(如 Python、C#、Rust)调用。
跨编译器兼容:遵循相同的 ABI,不同编译器生成的代码可以协同运行。
动态链接库的使用:动态库通过 ABI 提供函数接口,供程序运行时调用。
总结
ABI 是程序运行时在二进制层面的契约,它规范了如何正确地调用函数、传递参数和处理数据,使得程序、库和系统可以无缝协作。
注意:该内容由由AIGC提供。