APP開發實戰170-ABI管理和SO檔案的使用簡介

xjbclz發表於2017-05-13

23ABI管理

23.1 ABI簡介

不同Android裝置使用不同的CPU,因此支援不同的指令集。CPU與指令集的每種組合都有其自己的應用二進位制介面(或 ABI)。 ABI可以非常精確地定義應用的機器程式碼在執行時如何與系統互動。開發者必須為應用要使用的每個 CPU架構指定ABI。                                                      

典型的ABI 包含以下資訊:

機器程式碼應使用的 CPU 指令集。

執行時記憶體儲存和載入的位元組順序。

可執行二進位制檔案(例如程式和共享庫)的格式,以及它們支援的內容型別。

用於解析內容與系統之間資料的各種約定。這些約定包括對齊限制,以及系統如何使用堆疊和在呼叫函式時註冊。

執行時可用於機器程式碼的函式符號列表 - 通常來自非常具體的庫集。

(Android系統採用小位元組序 ARM GNU/Linux ABI)

23.2 支援的ABI

每個 ABI 支援一個或多個指令集,下表是每個 ABI 支援的指令集概:

ABI

支援的指令集

說明

armeabi

ARMV5TE 和更高版本

  Thumb-1

無硬浮點。

armeabi-v7a

  armeabi

  Thumb-2

  VFPv3-D16

  其他(可選)

與 ARMv5、v6 裝置不相容。

arm64-v8a

  AArch-64

x86

  x86 (IA-32)

  MMX

  SSE/2/3

  SSSE3

不支援 MOVBE 或 SSE4。

x86_64

  x86-64

  MMX

  SSE/2/3

  SSSE3

  SSE4.1、4.2

  POPCNT

mips

MIPS32r1 及更高版本

使用硬浮點

mips64

  MIPS64r6

(1)armeabi

此 ABI 適用於基於 ARM、至少支援 ARMv5TE 指令集的 CPU,不支援硬體輔助的浮點計算。相反,所有浮點運算都使用編譯器 libgcc.a 靜態庫中的軟體幫助程式函式。

此ABI 支援 ARM 的 Thumb(亦稱 Thumb-1)指令集。NDK 預設生成 Thumb 程式碼,除非在 Android.mk 檔案中使用 LOCAL_ARM_MODE 變數指定不同的行為。

 

(2)armeabi-v7a

此ABI可擴充套件 armeabi 以包含多個 CPU 指令集擴充套件,包括:

Thumb-2 指令集擴充套件,其效能堪比 32 位 ARM 指令,簡潔性類似於 Thumb-1。

VFP 硬體 FPU 指令。更具體一點,包括 VFPv3-D16,它除了 ARM 核心中的 16 個 32 位暫存器之外,還包含 16 個專用 64 位浮點暫存器。

v7-a ARM 規格描述的其他擴充套件,包括 高階 SIMD(亦稱 NEON)、VFPv3-D32 和 ThumbEE,都是此 ABI 可選的。

 

(3)arm64-v8a

此 ABI 適用於基於 ARMv8、支援 AArch64 的 CPU。它還包含 NEON 和 VFPv4 指令集。

(4)x86

此ABI 適用於支援通常稱為“x86”或“IA-32”的指令集的 CPU。

 

(5)x86_64

此ABI 適用於支援通常稱為“x86-64”的指令集的 CPU。

 

(6)mips

此ABI 適用於基於 MIPS、至少支援 MIPS32r1指令集的 CPU。

 

(7)mips64

此ABI 適用於 MIPS64 R6。

23.3 為特定ABI生成程式碼

預設情況下,NDK 為 armeabi ABI生成機器程式碼。但可以通過向 Application.mk檔案新增以下行生成 ARMv7-a 相容的機器程式碼:

APP_ABI := armeabi-v7a

要為兩個或更多不同的 ABI 構建機器程式碼,請使用空格作為分隔符。例如:

APP_ABI := armeabi armeabi-v7a

此設定指示 NDK 為機器程式碼構建兩個版本:此行中所列的每個 ABI 一個。

構建多個機器程式碼版本時,構建系統會將庫複製到應用專案路徑,並最終將它們封裝到 APK 中,從而建立一個胖二進位制檔案。 胖二進位制檔案大於只包含一個系統的機器程式碼的二進位制檔案;權衡方式是相容性更廣,但 APK 更大。

在安裝時,軟體包管理器只解包最適合目標裝置的機器程式碼。

23.4 Android平臺上的ABI管理

Android的軟體包管理器預期在 APK中符合以下模式的檔案路徑上查詢 NDK 生成的庫:

/lib/<abi>/lib<name>.so

這裡的 <abi> 是支援的ABI 下面列出的 ABI 名稱之一,<name> 是為 Android.mk檔案中的 LOCAL_MODULE 變數定義庫時使用的庫名稱。 由於 APK檔案只是 zip 檔案,因此開啟它們並確認它們屬於哪些共享原生庫很簡單。

如果系統在預期位置找不到原生共享庫,便無法使用它們。 在這種情況下,應用本身必須複製這些庫,然後執行 dlopen()。

在胖二進位制檔案中,每個庫位於其名稱與相應 ABI 匹配的目錄下。例如,胖二進位制檔案可能包含:

/lib/armeabi/libfoo.so

/lib/armeabi-v7a/libfoo.so

/lib/arm64-v8a/libfoo.so

/lib/x86/libfoo.so

/lib/x86_64/libfoo.so

/lib/mips/libfoo.so

/lib/mips64/libfoo.so

23.5 Android平臺ABI支援

Android 系統在執行時知道它支援哪些 ABI,因為版本特定的系統屬性會指示:

裝置的主要ABI,與系統映像本身使用的機器程式碼對應。

可選的輔助ABI,與系統映像也支援的另一個ABI 對應。

此機制確保系統在安裝時從軟體包提取最佳機器程式碼。

為實現最佳效能,應直接針對主要 ABI 進行編譯。例如,基於 ARMv5TE 的典型裝置只會定義主要 ABI:armeabi。相反,基於 ARMv7 的典型裝置將主要ABI定義為 armeabi-v7a,而將輔助ABI定義為 armeabi,因為它可以執行為每個 ABI 生成的應用原生二進位制檔案。

許多基於 x86 的裝置也可執行 armeabi-v7a 和 armeabi NDK 二進位制檔案。對於這些裝置,主要 ABI將是 x86,輔助ABI是 armeabi-v7a。

基於 MIPS 的典型裝置只定義主要 ABI:mips。

23.6 安裝時自動解壓縮原生程式碼

安裝應用時,軟體包管理器服務將掃描 APK,查詢以下形式的任何共享庫:

lib/<primary-abi>/lib<name>.so

如果未找到,並且已定義輔助 ABI,該服務將掃描以下形式的共享庫:

lib/<secondary-abi>/lib<name>.so

找到所需的庫時,軟體包管理器會將它們複製到應用的 data 目錄 (data/data/<package_name>/lib/)下的 /lib/lib<name>.so。

如果根本沒有共享物件檔案,應用也會構建並安裝,但在執行時會崩潰。

相關文章