二进制组件之间需要一致约定
两个分别编译的函数要互相调用,必须在源码之外约定参数在哪里、返回值怎样取得、谁保存哪些寄存器及栈怎样排列。ABI还可涵盖目标文件、重定位和调试信息等格式,使不同工具生成的组件能正确衔接。
API常在源代码层描述可调用的接口,ABI则涉及编译后实际表示和传递方式。同名函数与相同源码声明,不足以证明两份二进制遵循相同约定;一个组件把参数放在寄存器,另一个却去不相应的位置读取,就无法仅靠名称一致工作。
参考:[1]
调用规则与数据布局都要核对
RISC-V标准整数调用约定把a0至a7用作参数寄存器,前两个还可用于返回值,并区分调用后必须保留的寄存器。这些软件分工不同于ISA允许某条指令读写哪些寄存器;例如x2作为栈指针,是调用约定赋予的角色。
数据大小也有不同配置。RISC-V的ILP32约定中int、long与指针为4字节;LP64中int仍为4字节,long与指针为8字节。结构体还受成员对齐与填充约束,不能把对象大小或内存布局仅凭语言类型名称猜出来。
兼容需要同时满足多层条件
同一指令集上也可能存在不同ABI,浮点参数是否经专用寄存器传递就是一种区别。RISC-V文档为不同约定给出命名和标记;连接工具可以检查部分不兼容信息,但不能因此假定任意混合组件都会被自动修好。
ABI稳定有助于保留已编译程序的使用能力,却不保证依赖库必然存在或实现没有缺陷。判断某个文件能否运行,还须核对架构扩展、操作系统服务、加载器及库版本。源码可重新编译与既有二进制可直接使用,是不同的兼容目标。