在上篇文章,ARM架构认知 ,我们提到了ABI这个概念,今天再进一步认识一下这个东东。
1> 认识ABI区分API
API(application programming interface):应用程序接口,又称为应用编程接口。是指编程过程中程序(函数)调用层面的接口,是软件系统不同组成部分衔接的约定。API定义了源码接口,通过这些接口,软件的一个部分可以在源代码级与另一个部分通信。API保证了“源码兼容”。
ABI(application binary interface):应用程序二进制接口。字面可以看出,是二进制层面的接口,和具体CPU架构及OS强相关,ABI主要关注调用约定、字节序、寄存器使用、系统调用、链接、库的行为以及二进制目标格式。例如,调用约定,定义了函数如何调用,参数如何传递,分别保留和使用哪些寄存器,调用方如何获取返回值。ABI定义特定体系结构上两个或多个软件之间的低级二进制接口,定义了应用程序如何与自身交互、应用程序如何与内核交互以及应用程序如何与库交互。ABI保证了“二进制兼容(binary compatibility)”。
2> Arm架构ABI
结合之前文章,我们知道 不同的CPU又会有不同的架构,支持不同的指令集,所以CPU与指令集的每种组合势必都会有专属的ABI。
针对ARM体系结构的ABI(应用程序二进制接口)就是一组规范,对应有一系列标准。在ARM ABI一系列标准中,一些是开放标准,一些是特定于ARM体系结构的标准,这些标准控制着基于ARM体系结构的一组执行环境(从裸机到如ARM Linux一类的主要操作系统)中的二进制文件和开发工具的相互操作。
这些接口包括 ARM过程调用标准(APCS)、ARM ELF、ARM DWARF、基础平台ABI(BPABI)、C++ ABI、异常处理ABI、运行时ABI 和 C库ABI。
Arm架构的ABI示意图和一些相关标准:

3> Android ABI
不同的Android(linux)设备可能会使用不同的CPU,所以也会有不同的ABI; ABI具体包含以下信息:
确立了可使用的CPU指令集(和扩展指令集);如果Android是移植在ARM架构的CPU上,则必须按照ARM架构指令集的ABI一系列规则办事才行。
确立了运行时内存存储和加载的字节顺序;Android始终采用的是小端序(little-endian)。ARM支持大端和小端的内存存储方式,可选可配置。(大小端也是找工作基本会碰到的面试或笔试题,后面会专门出一篇文章讲讲^^)。
确立了在应用和系统之间传递数据的规范(包括对齐限制),以及系统调用函数时如何使用堆栈和寄存器。
确立了可执行二进制文件(例如程序和共享库)的格式,以及它们支持的内容类型;Android 始终使用 ELF。
如何重整 C++ 名称。

Android支持的ABI举例(如之前文章 ARM架构认知 提到的):
armeabi-v7a:此ABI适用于基于32位ARM的CPU。Android 变体包含 Thumb-2 和 VFP 硬件浮点指令(具体而言就是 VFPv3-D16),其中包含 16 个专用 64 位浮点寄存器。
arm64-v8a:此ABI适用于基于ARMv8-A的CPU。支持 64 位 AArch64 架构。它包含高级 SIMD (Neon) 架构扩展指令集。
我们在进行android开发有关so适配时应该要注意:
CPU 大部分都会向前兼容,比如 ARMv7 的 CPU 除了支持 armeabi-v7a,也支持 armeabi,ARMv8 的 CPU 支持 armeabi,armeabi-v7a,arm64-v8a 三种 ABI。
系统优先选择对应 ABI 文件夹下的 so,比如 ARMv7 的设备,会优先选择 armeabi-v7a 下的 so 进行加载。如果文件夹存在,且 so 存在,则正常加载;如果是文件夹存在,so不存在,则会在运行时崩溃;如果文件夹不存在,则会去 armeabi 文件夹下找 so。
如果使用了兼容的 so,因为兼容可能对于性能会带来一定损失。建议对于每个 ABI 下的so,要么全部支持,要不都不支持。

行文不易,
看到即缘分,点击“在看”,长按关注,一起进步!




