第七章 ARM 反汇编基础(二)(Android ARM EABI)

Android ARM EABI

  • 不同的 Android 手机使用的 CPU 不同,其使用的指令集也可能不同。每种 CPU 与指令集的组合都有自己的应用二进制接口(Application Binary Interface, ABI)
  • ABI 可非常精确地定义应用的机器代码在运行时如何与系统进行交互
  • 嵌入式设备的 ABI 称嵌入式应用二进制接口(Embedded application binary interface, EABI)
  • 典型的 EABI 包含如下信息:
    • 机器代码使用的 CPU 指令集
    • 运行时内存存储和加载的字节顺序
    • 可执行二进制文件(如程序和共享库)的格式,及其支持的内容类型
    • 用于解析内容与系统间数据的各种约定。这些约定包括对齐限制,以及系统如何使用堆栈、如何在调用函数时进行注册
    • 运行时可用于机器代码的函数符号列表
  • 基于 ARM 的 EABI 称“ARM EABI”
  • Android 除了支持 ARM EABI,还支持 x86 EABI 与 MIPS EABI
  • 此处只讨论 Android 平台支持的 ARM EABI

armeabi

  • 在 armeabi-v7a 前,Android NDK 支持的 ARM EABI 称“armeabi”。armeabi 支持 ARM(ARMv5/v6)和 Thumb 两种指令集。当时的 ARM 处理器不支持硬件浮点指令集,多媒体运算指令采用的是软件模拟,ARM 处理器的性能相对低下,支持的指令集也相对较少
  • armeabi 定义了(但不限于)以下内容:
    • ARM 架构的过程调用标准
    • ARM 架构的 ELF 文件格式
    • ARM 架构的 ABI
    • ARM 架构的基本平台 ABI
    • ARM 架构的 C 库 ABI
    • ARM 架构的 C++ ABI
    • ARM 架构的运行时 ABI
    • ELF 的 System V ABI
  • 查看 Android NDK 中的编译工具链,可知它们的命名方式与普通的工具链有所不同
    第七章 ARM 反汇编基础(二)(Android ARM EABI)
    • 工具的名称都有“arm-linux-androideabi-”前缀,这么长不利于手工输入
    • 目前 Android 官方已然改进,在 Android DNK 的 RoadMap 中可看到:从 Android NDK r16 开始,会使用与 Clang 编译器配套的 libc++ 库作为默认的 STL 库,Android NDK r17 会移除 Android NDK 中的 gcc 工具链,将 LLVM 的 Clang 编译器作为唯一的官方开发编译器
    • 目前 Android NDK 中的 Clang 编译器命名与其他平台上的命名规则一致,没有“arm-linux-androideabi-”前缀,不同架构使用的工具会放在以架构名命名的目录

armeabi-v7a

  • armeabi-v7a 扩展了 armeabi,包含多个 CPU 指令集扩展
  • Android 特定的 EABI 支持的指令扩展包括如下内容:
    • Thumb-2 指令集扩展:性能堪比 32 位 ARM 指令,简洁性类似之前 16 位的 Thumb 指令集,同时支持 16 位和 32 位指令集的混合使用
    • VFP 硬件 FPU 指令:包括 VFPv3-D16,除了 ARM 核心中的 16 个 32 位寄存器,还包含 16 个专用的 64 位浮点寄存器。这也是 Android ARM EABI 首次支持硬件指令级别的浮点运算
  • armeabi-v7a 还描述了其他扩展,包括高级 SIMD(也称“NEON”)、VFPv3-D32、ThumbEE,但这些扩展都是可选的。由于不能保证它们存在,系统在运行时应检查扩展是否可用,若扩展不可用,则必须使用软替代方案。此检查类似系统在检查或是用 MMX、SSE2、x86 CPU 上其他专用指令集时所进行的检查
  • armeabi-v7a ABI 允许通过“-mfloat-abi=softfp”开关强制使用软件形式来模拟浮点运算,如此设置后,编译器在函数调用中就会使用两个相邻的通用寄存器存放双精度值,而不会使用专用的浮点寄存器。此情况通常发生在早期 armeabi-v7a 规格的处理器上,新的硬件设备为适应设备运行时的性能需求,通常会提供浮点指令扩展支持,允许系统使用 FP 寄存器执行所有的内部计算,这极大地提高了计算效率
  • 注意:
    • armeabi-v7a 虽支持 armeabi,但与 ARMv5/v6 设备不兼容,这就是使用 Android NDK 编译原生代码设置 ABI 支持时,若要兼容 ARMv5/v6 系统的处理器,不仅要设置 armeabi-v7a,还要指定 armeabi 的原因
    • 但就市场情况看,ARMv5/v6 系列处理器只会在 Android 4.0 以下版本的手机中使用,若设备要兼容新版本的 Android 系统,并要进行 APK 体积优化,可考虑去掉对 armeabi 架构的支持

arm64-v8a

  • arm64-v8a 从 Android 5.0 开始引入
  • 它支持全新的 AArch64 架构,同时兼容 armeabi-v7a 并将其并入 AArch32 架构
  • 新规格下的 VFP 扩展升级到了 v4 版本,NEON 指令集扩展成为必选项
  • 64 位 arm64-v8a 规格的处理器支持 AArch64 和 AArch32 两种运行模式
    • AArch64 模式下,所有代码数据寻址采用 64 位地址空间,寄存器也采用 64 位的
    • AArch32 模式为 32 位,在此模式下代码数据寻址和寄存器的使用与之前一样,采用 32 位的
  • 由于 arm64-v8a 对 armeabi-v7a 完整兼容,在对 APK 进行文件体积优化时可考虑牺牲 64 位代码的运行效率,在 Android 中选取 ABI 支持时只选择 armeabi-v7a。如此设置编译出的 APK,安装时会选取 armeabi-v7a 目录下的 so 作为运行时加载使用的库