Native开发工具之CPU 和架构(三)
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家
一、简介
====
使用原生代码时,硬件很重要。NDK 提供各种 ABI 供您选择,可让您确保针对正确的架构和 CPU 进行编译。
本部分介绍了在编译时如何面向特定的架构和 CPU,如何使用 ARM NEON 扩展指令集,以及在运行时如何使用 cpufeatures 库查询可选功能。
二、ABI 管理
========
不同的 Android 手机使用不同的 CPU,而不同的 CPU 支持不同的指令集。CPU 与指令集的每种组合都有专属的应用二进制接口,即 ABI。ABI 可以非常精确地定义应用的机器代码在运行时如何与系统交互。您必须为应用要使用的每个 CPU 架构指定 ABI。
典型的 ABI 包含以下信息:
-
机器代码应使用的 CPU 指令集。
-
运行时内存存储和加载的字节顺序。
-
可执行二进制文件(例如程序和共享库)的格式,以及它们支持的内容类型。
-
在代码与系统之间传递数据的各种规范。这些规范包括对齐限制,以及系统调用函数时如何使用堆栈和寄存器。
-
运行时可用于机器代码的函数符号列表 - 通常来自非常具体的库集。
本页列举了 NDK 支持的 ABI,并且介绍了每个 ABI 的运行原理。如需 32 位系统上的 ABI 问题列表,请参阅 32 位 ABI 错误
每个 ABI 支持一个或多个指令集。表 1 概述了每个 ABI 支持的指令集。
表 1. ABI 和支持的指令集。
表1
注意:NDK 以前支持 32 位和 64 位 MIPS,但这项支持已在 NDK r17 中移除。
下面提供了关于每个 ABI 的更多详细信息。
armeabi
注意:此 ABI 已在 NDK r17 中移除。
此 ABI 适用于基于 ARM、至少支持 ARMv5TE 指令集的 CPU。详情请参阅以下文档:
AAPCS 标准将 EABI 定义为类似但不同 ABI 的系列。此外,Android 还采用小字节序 ARM GNU/Linux ABI。
此 ABI 不支持硬件辅助的浮点运算。相反,所有浮点运算都使用编译器的 libgcc.a
静态库中的软件辅助函数。
armeabi ABI 支持 ARM 的 Thumb(亦称 Thumb-1)指令集。NDK 默认生成 Thumb 代码,除非您在 Android.mk
文件中使用 LOCAL_ARM_MODE
变量指定不同的行为。
armeabi-v7a
此 ABI 可扩展 armeabi 以包含多个 CPU 扩展指令集。此 Android 特定 ABI 支持的扩展指令包括:
-
Thumb-2 扩展指令集,其性能堪比 32 位 ARM 指令,简洁性类似于 Thumb-1。
-
VFP 硬件 FPU 指令。更具体一点,是指 VFPv3-D16,它除了 ARM 核心中的 16 个 32 位寄存器之外,还包含 16 个专用 64 位浮点寄存器。
v7-a ARM 规范描述的其他扩展指令集,包括高级 SIMD(亦称 NEON)、VFPv3-D32 和 ThumbEE,都是此 ABI 的可选扩展指令集。由于不能保证它们存在,因此系统在运行时应检查扩展指令集是否可用。如果不可用,您必须使用替代代码路径。此检查类似于系统在检查或使用 MMX、SSE2 及 x86 CPU 上其他专用指令集时所执行的检查。
要了解如何执行这些运行时检查,请参阅 cpufeatures
库。此外,如需有关 NDK 支持为 NEON 编译机器代码的信息,请参阅 NEON 支持。
armeabi-v7a
ABI 使用 -mfloat-abi=softfp
开关强制实施以下规则:编译器在函数调用期间必须传递核心寄存器对中的所有双精度值,而不是专用浮点值。系统可以使用 FP 寄存器执行所有内部计算。这样可极大地提高计算速度。
arm64-v8a
此 ABI 适用于基于 ARMv8、支持 AArch64 的 CPU。它还包含 NEON 和 VFPv4 指令集。
如需了解更多信息,请参阅 ARMv8 技术预览,并联系 ARM 进一步了解详情。
x86
此 ABI 适用于支持通常称为“x86”或“IA-32”的指令集的 CPU。此 ABI 的特性包括:
- 指令一般由具有编译器标记的 GCC 生成,如下所示:
-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32
这些标记指向 Pentium Pro 指令集,以及 MMX、SSE、SSE2、SSE3 及 SSSE3 扩展指令集。生成的代码在顶层 Intel 32 位 CPU 之间进行了均衡优化。
如需了解有关编译器标记的更多信息,特别是与性能优化相关的信息,请参阅 GCC x86 性能提示。
- 使用标准 Linux x86 32 位调用规范,与 SVR 使用的规范相反。详情请参阅不同 C++ 编译器和操作系统的调用规范的第 6 部分“寄存器的使用”。
ABI 不含任何其他可选 IA-32 扩展指令集,例如:
-
MOVBE
-
SSE4 的任何变体。
您仍可使用这些扩展指令集,只要您使用运行时功能探测来启用它们,并且为不支持它们的设备提供回退机制。
NDK 工具链假设在函数调用之前进行 16 字节堆栈对齐。默认工具和选项会强制实施此规则。如果编写的是汇编代码,必须确保堆栈对齐,而且其他编译器也遵守此规则。
请参阅以下文档了解更多详情:
x86_64
此 ABI 适用于支持通常称为“x86-64”的指令集的 CPU。它支持 GCC 通常使用以下编译器标记生成的指令:
-march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel
这些标记指向 x86-64 指令集(根据 GCC 文档),以及 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2 和 POPCNT 扩展指令集。生成的代码在顶层 Intel 64 位 CPU 之间进行了均衡优化。
如需了解有关编译器标记的更多信息,特别是与性能优化相关的信息,请参阅 GCC x86 性能。
此 ABI 不含任何其他可选的 x86-64 扩展指令集,例如:
-
MOVBE
-
SHA
-
AVX
-
AVX2
您仍可使用这些扩展指令集,只要您使用运行时功能探测来启用它们,并且为不支持它们的设备提供回退机制。
请参阅以下文档了解更多详情:
为特定 ABI 生成代码
默认情况下,NDK 指向所有非弃用 ABI。您可通过在 Application.mk
文件中设置 APP_ABI
来指向单个 ABI。以下代码段演示了使用 APP_ABI
的几个示例
APP_ABI := arm64-v8a # Target only arm64-v8a
APP_ABI := all # Target all ABIs, including those that are deprecated.
APP_ABI := armeabi-v7a x86_64 # Target only armeabi-v7a and x86_64.
要详细了解您可以为 APP_ABI
变量指定的值,请参阅 Android.mk。
编译系统的默认行为是将每个 ABI 的二进制文件包括在单个 APK(也称为胖 APK)内。与仅包含单个 ABI 的二进制文件的 APK 相比,胖 APK 要大得多;要权衡的是兼容性更广,但 APK 更大。强烈建议您利用拆分 APK 减小 APK 的大小,同时仍保持最大限度的设备兼容性。
在安装时,软件包管理器只解压缩最适合目标设备的机器代码。详情请参阅安装时自动解压缩原生代码。
Android 平台上的 ABI 管理
本部分详细说明了 Android 平台如何管理 APK 中的原生代码。
应用软件包中的原生代码
Play 商店和软件包管理器都希望能在 APK 中符合以下格式的文件路径上找到 NDK 生成的库:
/lib//lib.so
其中,<abi>
是支持的 ABI 下列出的 ABI 名称之一,<name>
是您为 Android.mk
文件中的 LOCAL_MODULE
变量定义库时使用的库名称。由于 APK 文件只是 zip 文件,因此打开它们并确认共享原生库位于该位于的位置很简单。
如果系统在预期位置找不到原生共享库,便无法使用它们。在这种情况下,应用本身必须复制这些库,然后执行 dlopen()
。
在胖 APK 中,每个库位于名称与相应 ABI 匹配的目录下。例如,胖 APK 可能包含:
/lib/armeabi/libfoo.so
/lib/armeabi-v7a/libfoo.so
/lib/arm64-v8a/libfoo.so
/lib/x86/libfoo.so
/lib/x86_64/libfoo.so
注意:搭载 4.0.3 或更早版本、基于 ARMv7 的 Android 设备从 armeabi
目录(而非 armeabi-v7a
目录,如果两个目录都存在)安装原生库。这是因为在 APK 中,/lib/armeabi/
在 /lib/armeabi-v7a/
后面。从 4.0.4 开始,此问题已修复。
Android 平台 ABI 支持
Android 系统在运行时知道它支持哪些 ABI,因为版本特定的系统属性会指示:
-
设备的主要 ABI,与系统映像本身使用的机器代码对应。
-
(可选)与系统映像也支持的其他 ABI 对应的辅助 ABI。
此机制确保系统在安装时从软件包提取最佳机器代码。
为实现最佳性能,应直接针对主要 ABI 进行编译。例如,基于 ARMv5TE 的典型设备只会定义主要 ABI:armeabi
。相反,基于 ARMv7 的典型设备将主要 ABI 定义为 armeabi-v7a
,并将辅助 ABI 定义为 armeabi
,因为它可以运行为每个 ABI 生成的应用原生二进制文件。
64 位设备也支持其 32 位变体。以 arm64-v8a 设备为例,该设备也可以运行 armeabi 和 armeabi-v7a 代码。但请注意,如果应用以 arm64-v8a 为目标,而非依赖于运行 armeabi-v7a 版应用的设备,应用在 64 位设备上的性能要好得多。
许多基于 x86 的设备也可运行 armeabi-v7a
和 armeabi
NDK 二进制文件。对于这些设备,主要 ABI 将是 x86
,辅助 ABI 是 armeabi-v7a
。
安装时自动解压缩原生代码
安装应用时,软件包管理器服务将扫描 APK,并查找以下形式的任何共享库:
lib//lib.so
如果未找到,并且您已定义辅助 ABI,该服务将扫描以下形式的共享库:
lib//lib.so
找到所需的库时,软件包管理器会将它们复制到应用的 data
目录 (data/data/<package_name>/lib/
) 下的 /lib/lib<name>.so
。
如果根本没有共享对象文件,应用也会编译并安装,但在运行时会崩溃。
三、处理CPU功能
=========
ABI:使用预处理器的预定义宏
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
写在最后
对程序员来说,很多技术的学习都是“防御性”的。也就是说,我们是在为未来学习。我们学习新技术的目的,或是为了在新项目中应用,或仅仅是为了将来的面试。但不管怎样,一定不能“止步不前”,不能荒废掉。
![
文章以下内容会给出阿里与美团的面试题(答案+解析)、面试题库、Java核心知识点梳理等,需要这些文档资料的,直接点击我的GitHub免费领取~
是为了将来的面试。但不管怎样,一定不能“止步不前”,不能荒废掉。
[外链图片转存中…(img-MwAc1DF7-1710669835877)]
[外链图片转存中…(img-ukjZRl6d-1710669835877)]
[外链图片转存中…(img-TbbME8Di-1710669835878)]
[外链图片转存中…(img-4ebH0jN6-1710669835878)]
文章以下内容会给出阿里与美团的面试题(答案+解析)、面试题库、Java核心知识点梳理等,需要这些文档资料的,直接点击我的GitHub免费领取~
更多推荐
所有评论(0)