ABI 是什么?
直译是 应用程序二进制接口,字面上理解,二进制接口指的是一套使用二进制应用程序的接口定义,多个ABI,就是多个接口定义。
接口,也叫界面,一套函数库有个api,也提供了一个函数集,这个函数集就是函数库和用户的接口、界面
在龙芯的github页面上,能看到两个关于ABI的文档:
龙芯架构 ELF psABI 规范
https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-CN.html
关于loongarch的介绍
https://github.com/loongson/linux/blob/loongarch-next/Documentation/translations/zh_CN/loongarch/introduction.rst
总结起来看:
应用程序二进制界面(接口),实际上对应的是二进制应用程序生成(编译)的一些要素的集合
这个集合包含以下内容:
- cpu上提供的寄存器要怎么用
- 参数要怎么传递(栈?寄存器?)
- 链接程序都做了什么(重定位信息处理?)
这个集合是一种编译实践的“约定”,目的是让不同的编译模块在上述要素的使用上,可以达到兼容,比如汇编程序生成的obj,c语言生成的obj,经过ld组合后,能按照同样的约定,保持一种互兼容性。
ABI 的定义
龙芯针对32位和64位处理器,分别定义了三个基础ABI
32位: ilp32s 、ilp32f 、ilp32d
64位: lp64s 、lp64f 、lp64d
其中 s=soft 软件浮点, f=float 单精度硬件浮点32位fr d=double 双精度硬件浮点64位fr
如此标记ABI,可以看出主要是基于cpu上的寄存器的差异化,因为risc体系结构主要通过寄存器传递参数,也就影响到了函数调用参数传递上的一些区别。
这个abi在编译程序的时候,要作为一个选项参数,命令编译器使用对应的abi,使用寄存器,这个参数也会传递到as和ld工具程序,最终生成应用程序,当然也包括kernel
关于“新旧世界”ABI的兼容性
新旧世界的提法,见诸于一些讨论,兼容性挑战来自,对ABI的定义,发生了一些改变。旧世界的ABI,是基于mips做的第一版移植,它所定义的ABI,更像mips的ABI.
“一些改变”,基于龙芯内部和开源社区的沟通的成果,一些是知识产权的原因,一些是loongarch指令集架构的演变。因为ABI所定义的“各种约定”变化较大,所以才会有“兼容”这个问题。
当“兼容性“变成了大问题时,就变成了新旧两个世界的讨论。
ABI的代码实现
一、事关ELF
loongarch关于elf的定义和操作,主要是在binutils的bfd目录下进行代码实现。loongson要对loongarch定义一些标识,形成abi约定的“元数据”。也就是说当操作系统加载二进制应用程序时,会读取这些元数据,通过abi,正确把程序加载到内存。主要的代码和数据结构有:
二、事关编译
在代码优化过程中,如何安排使用寄存器,会使用ABI的约定。汇编代码生成时,也要正确的使用寄存器、按约定做一些数据布局上的安排,用于参数传递上的优化。主要代码和数据结构:
三、事关链接
在生成可执行二进制文件时,如何解析重定位信息,里面牵扯了很多约定
正是这些约定,在保障一致性上的福利,造就了不同ABI的”区别“
ABI有多神奇
ABI某种程度上,它针对的是处理器产品,针对配置硬件机制的组合,所进行的一种优化,一种新的ABI的提出,总是要针对某种cpu某种应用场景的优化。