糖尿病康复,内容丰富有趣,生活中的好帮手!
糖尿病康复 > 细谈ABI

细谈ABI

时间:2024-08-15 14:14:21

相关推荐

细谈ABI

细谈ABI

ABI (Application Binary interface)API与ABI的区别 影响ABI兼容性的因素硬件 - 如处理器操作系统编译器语言层面 - C++ 总结参考资料

ABI (Application Binary interface)

ABI (Application Binray interface): 应用程序二进制接口,描述了应用程序和操作系统之间,一个应用和它的库之间,或应用的组成部分之间的低接口。

API与ABI的区别

ABI从名字上看是二进制接口,而二进制文件再linuxELF文件类型表示,windowsPE-COFF文件类型表示。

二进制文件的生成是通过编译器或者链接器,那么APIABI都是谁需要去遵循这个规则呢,如下面的代码假设它将会被编译成一个myso动态库,你可以将它当成一个API

int Add(int a, int b) {return a + b;}

下面是你的应用程序, 我们称它未main

int main(void) {int c = Add(3, 2);return 0;}

API:库的使用者可能需要去遵循这个接口规范,Add函数的参数个数以及参数类型等等。ABI:main使用到了Add这个API,这个API包含再一个myso动态库里面,现在设计到一个符号寻找机制,即编译器需要去myso动态库里面寻找Add这个符号,那符号的命名规则不一致会导致什么结果?如gcc1.0版本的符号命名规则是再函数前面加一个_,即最后Add符号名称_Add,gcc2.0版本的符号命名规则是再函数后面加一个_, 即最后Add符号名称Add_。思考一个问题,myso是利用gcc1.0版本编译,main使用gcc2.0版本编译,会出现是什么问题? 编译器会提示你Add_符号未定义,这里说的符号导出规则也就是属于ABI兼容问题。

结论 :影响你API不兼容的可能是你使用的API新增了参数。影响ABI不兼容的可能仅仅就是编译器版本不同,一个是源码层面,一个是编译器层面(即编译器生成的二进程), 当然编译器仅仅只是一个方面。

影响ABI兼容性的因素

硬件 - 如处理器

思考一个非常简单的问题,最近Apple发布了最新款Mac笔记本,号称可以直接使用iPhoneipad的应用,怎么做到的?这个就是一个二进制兼容问题,Apple再最新的Mac笔记本上放弃了之前一直使用的intel芯片,从而采用自研的M1芯片,这个M1的自研芯片架构就是ARM架构和苹果A系列芯片架构一样,从而才有可能实现二进制级别的兼容。

二进制里面包含了指令和数据,而CPU有一个核心作用就是处理指令,不同架构的CPU指令集都不同,从而产生的二进制也会不同,例如你在代码中调用了print函数,最终在X86生成的二进制文件的一条指令是call 0x1234, 但是在ARM处理器下它可能没有call指令,它的跳转指令可能是jar

操作系统

为什么不同系统不能兼容同一个已编译的可执行二进制文件(假设再统一架构)?

一、二进制文件类型

一个可执行的二进制文件包含的不仅仅是机制指令,还包括各种数据、程序运行资源。

如上面提到的二进制文件类型:

windows -PE-COFFlinux -ELFmacos -MACH-O

它们的二进制文件格式各不相同,导致windows无法解析linux下的ELF文件格式,从而无法完成可执行文件在执行之前的一系列初始化操作,如ELF文件头中就包含了:

二、程序库不同(API)

文件操作、输入输出、内存申请释放、任务调度等都需要用到特定操作系统的特定库。

编译器

C++函数签名:函数签名的目的就是让编译器能够根据对应的签名规则生成一个符号,编译器根据这个符号来识别和处理函数,函数签名包含了一个函数的信息,其中包括

函数名参数类型参数个数类名名称空间

int Function(int i);

上面的代码再gccvc编译器生成之后的符号:

gcc : _Z8Functionivc++: ?Function@@YAHH@Z

你会发现gcc和vc++的函数签名规则都不一样,那gcc编译的库vc++能够找到它的符号吗,答案肯定是不行的,就算是相同版本的gcc也一样可能出现二进制不兼容,如gcc4.9版本C++ string,list符号命名和gcc5.1之后的符号命名都是不同的gcc5.1上会增加__cxx11,所以一样会产生gcc4.9编译的库,再gcc5.1上使用不了(符号未定义,如果使用了string,list)

语言层面 - C++

内置类型的大小以及对齐方式(如大端、小端)。

structunion、数组等的存储方式和内存分布。

函数调用方式,比如参数入栈顺序、返回值如何保持等。

堆栈的分布方式,比如参数和局部变量再堆栈里的位置,参数传递方法等。

继承类体系的内存分布,如基类、虚基类再继承类中的位置等。

指向成员函数的指针的内存分布,如何传递this指针

如何调用虚函数,vtable的内容和分布形式,vtable指针再object中的位置等。

templte如何实例化

外部符号的修饰

全局对象的构造和析构

异常的产生和捕获机制

RTTI如何实现

等等

总结

想要保持二进制兼容相较于API兼容来说要难上许多,并且影响ABI兼容的因素也非常多从硬件到操作系统再到编译器,编程语言等,并且难以统一,本文也只是浅析了ABI兼容问题,如果你是一个公共组件的开发者,相信你还需要更加深入ABI兼容问题,如阅读LSB (Linux Standard Base)

彩蛋

参考资料

C++ binary compatibility between Visual Studio , , and

Mach-O文件格式

为什么不同系统不能兼容同一个已编译的可执行二进制文件?

Application binary interface

What is an application binary interface (ABI)?

如果觉得《细谈ABI》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。