Farklı Android cihazlar farklı CPU'lar kullanır ve bu da farklı yapılandırma kümelerini destekler. Her CPU ve talimat grubu kombinasyonunun kendi Uygulama İkili Arayüzü (ABI) vardır. ABI aşağıdaki bilgileri içerir:
- Kullanılabilecek CPU talimatı grubu (ve uzantıları).
- Belleğin uç noktası, çalışma zamanında depolanır ve yüklenir. Android her zaman küçük
- Düzenleme kısıtlamaları da dahil olmak üzere, uygulamalar ile sistem arasında veri iletmeye yönelik yöntemler ile işlevleri çağırırken sistemin yığını nasıl kullandığı ve nasıl kaydolduğuyla ilgili ayarlar.
- Programlar ve paylaşılan kitaplıklar gibi yürütülebilir ikili programların biçimi ve destekledikleri içerik türleri. Android her zaman ELF'yi kullanır. Daha fazla bilgi için ELF System V Uygulama İkili Arayüzü bölümüne bakın.
- C++ adları nasıl karıştırılır? Daha fazla bilgi için Genel/Itanyum C++ ABI bölümüne bakın.
Bu sayfa, NDK'nın desteklediği ABI'ları sıralar ve her ABI'nın nasıl çalıştığı hakkında bilgi sağlar.
ABI, platform tarafından desteklenen yerel API'yi de belirtebilir. 32 bit sistemleri etkileyen bu tür ABI sorunlarının listesi için 32 bit ABI hataları bölümünü inceleyin.
Desteklenen ABI'lar
Tablo 1. ABI'lar ve desteklenen talimat grupları.
ABI | Desteklenen Talimat Kümeleri | Notlar |
---|---|---|
armeabi-v7a |
|
ARMv5/v6 cihazlarıyla uyumlu değildir. |
arm64-v8a |
Yalnızca Armv8.0. | |
x86 |
MOVBE veya SSE4 desteklenmiyor. | |
x86_64 |
|
Yalnızca x86-64-v1. |
Not: NDK daha önce ARMv5 (armeabi) ile 32 bit ve 64 bit MIPS'yi destekliyordu. Ancak bu ABI'ler için destek NDK r17'de kaldırılmıştır.
armeabi-v7a
Bu ABI, 32 bit ARM CPU'lar içindir. Thumb-2 ve Neon (VFP) donanım puanı talimatlarını, özellikle 66 bitlik kayan 14 bit noktalı kayda sahip VFPv3-D16 içerir.
ABI'nin Android'e özel olmayan bölümleri hakkında bilgi edinmek için ARM Mimarisi için Uygulama İkili Arabirimi (ABI) bölümüne bakın.
NDK'nin derleme sistemleri, C'yi kMake'i yapılandırırken Android.mk
için ya da ANDROID_ARM_MODE
için kullanmadığınız sürece varsayılan olarak Thumb-2 kodu oluşturur.LOCAL_ARM_MODE
Gelişmiş SIMD (Neon) ve VFPv3-D32 dahil diğer uzantılar isteğe bağlıdır. Daha fazla bilgi edinmek için Neon Destek Ekibi ile iletişime geçin.
Bu ABI, derleyicinin işlev çağrıları yaparken tam sayı kayıtlarındaki tüm float
değerlerini ve tam sayı kayıt çiftlerindeki tüm double
değerlerini iletmesi gereken kuralı uygulamak için -mfloat-abi=softfp
yöntemini kullanır. Bu yalnızca arama kuralını etkiler. Derleyici, yine donanım kayan nokta talimatlarını kullanır.
Bu ABI, 64 bit long double
(IEEE ikili programı ile double
aynıdır).
kol 64-v8a
Bu ABI, 64 bit ARM CPU'lar içindir.
ABI'nin Android'e özel olmayan bölümleriyle ilgili tüm ayrıntılar için Arm'un Mimariyi Öğrenin sayfasına göz atın. Arm, 64 bit Android Geliştirme konusunda da taşıma tavsiyeleri sunar.
Gelişmiş SIMD uzantısından yararlanmak için C ve C++ kodunda Neon içgüdüleri kullanabilirsiniz. Neon Programer's Armv8-A Kılavuzu, genel olarak Neon içgörü ve Neon programlama hakkında daha fazla bilgi sağlar.
Android'de, platforma özel x18 kaydı ShadowCallStack için ayrılmıştır ve kodunuza dokunulmamalıdır. Clang'ın mevcut sürümlerinde Android'de varsayılan olarak -ffixed-x18
seçeneği kullanılmaktadır. Bu nedenle, elle yazılmış bir derleyici (veya çok eski bir derleyici) yoksa bu konuda endişelenmeniz gerekmez.
Bu ABI, 128 bitlik bir long double
kullanır (IEEE ikili programı128).
x86
Bu ABI, yaygın olarak "x86", "i386" veya "IA-32" olarak bilinen talimat grubunu destekleyen CPU'lara yöneliktir.
Android'in ABI sürümü temel talimat grubunun yanı sıra MMX, SSE, SSE2, SSE3 ve SSSE3 uzantılarını içerir.
ABI, MOVBE gibi isteğe bağlı diğer IA-32 talimat grubu uzantılarını veya SSE4 varyantlarını içermez. Bu uzantıları, çalışma zamanı özellik provizyonunu kullandığınız ve bunları desteklemeyen cihazlar için yedeklediğiniz sürece kullanabilirsiniz.
NDK araç zinciri, işlev çağrısından önce 16 baytlık yığın hizalamasını varsayar. Varsayılan araçlar ve seçenekler bu kuralı uygular. Montaj kodunu yazıyorsanız, yığın hizalamayı korumanız ve diğer derleyicilerin de bu kurala uymasını sağlamanız gerekir.
Daha fazla bilgi için aşağıdaki dokümanlara bakın:
- Farklı C++ derleyicileri ve işletim sistemleri için arama kuralları
- Intel IA-32 Intel Mimari Yazılım Geliştiricisi Kılavuzu, 2. Cilt: Talimat Grubu Referansı
- Intel IA-32 Intel Mimari Yazılım Geliştiricisi Kılavuzu, 3. Cilt: Sistem Programlama Rehberi
- Sistem V Uygulama İkilisi Arayüz: Intel386 İşlemci Mimarisi Eki
Bu ABI, 64 bitlik bir long double
(IEEE ikili programı ile double
ile aynı olan ve yalnızca 80 bitlik yalnızca Intel'e ait long double
değil) kullanır.
x86_64
Bu ABI, genellikle "x86-64" olarak bilinen talimat grubunu destekleyen CPU'lar içindir.
Android'in ABI; temel talimat grubunun yanı sıra MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2 ve POPCNT talimatı içerir.
ABI; MOVBE, SHA gibi isteğe bağlı x86-64 talimat grubu uzantılarını veya AVX varyantlarını içermez. Bu uzantıları, çalışma zamanı özelliği araştırmasını kullandığınız ve bu uzantıları desteklemeyen cihazlar için yedeklediğiniz sürece kullanabilirsiniz.
Daha fazla bilgi için aşağıdaki dokümanlara bakın:
- Farklı C++ derleyicileri ve işletim sistemleri için çağrı kuralları
- Intel64 ve IA-32 Mimari Yazılım Geliştiricisi Kılavuzu, 2. Cilt: Eğitim Grubu Referans
- Intel64 ve IA-32 Intel Mimari Yazılım Geliştiricisi Manuel Birim 3: Sistem Programlama
Bu ABI, 128 bitlik bir long double
kullanır (IEEE ikili programı128).
Belirli bir ABI için kod oluşturma
Gradle
Gradle (Android Studio aracılığıyla veya komut satırından kullanılır), varsayılan olarak kullanımdan kaldırılmayan tüm ABI'lar için derleme yapar. Uygulamanızın desteklediği ABI grubunu kısıtlamak için abiFilters
kullanın. Örneğin, yalnızca 64 bit ABI'lar için derleme yapmak üzere build.gradle
cihazınızda aşağıdaki yapılandırmayı ayarlayın:
android {
defaultConfig {
ndk {
abiFilters 'arm64-v8a', 'x86_64'
}
}
}
-in-build
Varsayılan olarak kullanımdan kaldırılmayan tüm ABI'ler için ndk-build derlemeleri. Application.mk dosyanızda APP_ABI
öğesini ayarlayarak belirli bir ABI'yi hedefleyebilirsiniz. Aşağıdaki snippet'te APP_ABI
kullanımıyla ilgili birkaç örnek verilmiştir:
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
için belirtebileceğiniz değerler hakkında daha fazla bilgiyi Application.mk bölümünde bulabilirsiniz.
CMake
CMake ile aynı anda tek bir ABI için derleme yapabilirsiniz. ABI'nizi açık bir şekilde belirtmeniz gerekir. Bu işlemi ANDROID_ABI
değişkeniyle yaparsınız. Bu değişken, komut satırında belirtilmelidir (CMakeLists.txt dosyanızda ayarlanamaz). Örneğin:
$ cmake -DANDROID_ABI=arm64-v8a ...
$ cmake -DANDROID_ABI=armeabi-v7a ...
$ cmake -DANDROID_ABI=x86 ...
$ cmake -DANDROID_ABI=x86_64 ...
NDK ile derlemek için CMake'e iletilmesi gereken diğer işaretler için CMake kılavuzuna bakın.
Derleme sisteminin varsayılan davranışı, her ABI için ikili programları tek bir APK'ya (yağmur APK'sı olarak da bilinir) eklemektir. Yağ APK'sı yalnızca tek bir ABI'nin ikili programlarını içeren APK'dan önemli ölçüde daha büyüktür, karşılığındaki değer daha büyük bir APK'ya dayansa da daha büyük uyumluluk elde eder. Bir yandan maksimum uygulama uyumluluğunu korurken APK'larınızın boyutunu küçültmek için App Bundle'dan veya APK Bölmeleri'nden yararlanmanızı önemle tavsiye ederiz.
Yükleme sırasında paket yöneticisi, hedef cihaz için yalnızca en uygun makine kodunu açar. Ayrıntılar için Yükleme sırasında yerel kodun otomatik olarak çıkarılması bölümünü inceleyin.
Android platformunda ABI yönetimi
Bu bölümde, Android platformunun APK'larda yerel kodu nasıl yönettiği hakkında ayrıntılı bilgi verilmektedir.
Uygulama paketlerindeki yerel kod
Hem Play Store hem de Paket Yöneticisi, APK'daki dosya yollarında aşağıdaki kalıpla eşleşen NDK tarafından oluşturulan kitaplıkları bulmayı bekler:
/lib/<abi>/lib<name>.so
Burada <abi>
, Desteklenen ABI'ler altında listelenen ABI adlarından biridir. <name>
ise Android.mk
dosyasındaki LOCAL_MODULE
değişkeni için tanımladığınız kitaplık adıdır. APK dosyaları yalnızca sıkıştırılmış dosyalar olduğundan, bunları açmak ve paylaşılan yerel kitaplıkların ait oldukları yer olduğunu onaylamak kolay değildir.
Sistem, beklediği yerel yerel kitaplıkları bulamazsa bunları kullanamaz. Böyle bir durumda uygulamanın kitaplıkları kopyalaması ve ardından dlopen()
işlemi gerçekleştirmesi gerekir.
Yağlı APK'larda her kitaplık adı, ilgili ABI ile eşleşen bir dizin altında bulunur. Örneğin, yağlı bir APK şunları içerebilir:
/lib/armeabi/libfoo.so /lib/armeabi-v7a/libfoo.so /lib/arm64-v8a/libfoo.so /lib/x86/libfoo.so /lib/x86_64/libfoo.so
Not: 4.0.3 veya önceki sürümleri çalıştıran ARMv7 tabanlı Android cihazlar, her iki dizin de varsa armeabi-v7a
dizini yerine armeabi
dizininden yerel kitaplıkları yükler. Bunun nedeni, APK'da /lib/armeabi/
etiketinin
/lib/armeabi-v7a/
sonrasında gelmesidir. Bu sorun, 4.0.4 sürümünden sonra düzeltilmiştir.
Android platformu ABI desteği
Derlemeye özel sistem özellikleri şunları gösterdiği için Android sistemi, çalışma zamanında hangi ABI'leri desteklediğini bilir:
- Sistemin kendisinde kullanılan makine koduna karşılık gelen, cihazın birincil ABI'sı.
- İsteğe bağlı olarak, sistem görüntüsünün desteklediği diğer ABI'ye karşılık gelen ikincil ABI'lar.
Bu mekanizma, yükleme sırasında sistemin paketten en iyi makine kodunu almasını sağlar.
En iyi performans için doğrudan birincil ABI için derleme yapmanız gerekir. Örneğin, tipik bir ARMv5TE tabanlı cihaz yalnızca birincil ABI'yı (armeabi
) tanımlar. Buna karşılık, ARMv7 tabanlı tipik bir cihaz birincil ABI'yi armeabi-v7a
ve ikincil cihazı armeabi
olarak tanımlar. Bunun nedeni, bu cihazın her biri için oluşturulan yerel yerel ikili programları çalıştırabilmesidir.
64 bit cihazlar, 32 bit varyantlarını da destekler. Örneğin, arm64-v8a cihazları kullanarak armeabi ve armeabi-v7a kodunu çalıştırabilirsiniz. Ancak uygulamanızın 64 bit v8a'yı hedeflemesi durumunda uygulamanızın armeabi-v7a sürümünü çalıştıran cihaza güvenmek yerine 64 bit cihazlarda çok daha iyi performans göstereceğini unutmayın.
x86 tabanlı pek çok cihaz armeabi-v7a
ve armeabi
NDK ikili programlarını da çalıştırabilir. Bu tür cihazlarda birincil ABI x86
, ikincisi ise armeabi-v7a
olur.
Belirli bir ABI için APK'yı zorunlu olarak yükleyebilirsiniz. Bu, test için faydalıdır. Aşağıdaki komutu kullanın:
adb install --abi abi-identifier path_to_apk
Yükleme sırasında yerel kodun otomatik olarak ayıklanması
Bir uygulama yüklenirken paket yöneticisi hizmeti, APK'yı tarar ve formun paylaşılan kitaplıklarını arar:
lib/<primary-abi>/lib<name>.so
Herhangi bir kod bulunmazsa ve ikincil bir ABI tanımladıysanız hizmet şu biçimdeki paylaşılan kitaplıkları tarar:
lib/<secondary-abi>/lib<name>.so
Aradığı kitaplıkları bulduğunda paket yöneticisi, bunları uygulamanın yerel kitaplık dizininin (<nativeLibraryDir>/
) altındaki /lib/lib<name>.so
klasörüne kopyalar. Aşağıdaki snippet'ler nativeLibraryDir
kodunu alır:
Kotlin
import android.content.pm.PackageInfo import android.content.pm.ApplicationInfo import android.content.pm.PackageManager ... val ainfo = this.applicationContext.packageManager.getApplicationInfo( "com.domain.app", PackageManager.GET_SHARED_LIBRARY_FILES ) Log.v(TAG, "native library dir ${ainfo.nativeLibraryDir}")
Java
import android.content.pm.PackageInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; ... ApplicationInfo ainfo = this.getApplicationContext().getPackageManager().getApplicationInfo ( "com.domain.app", PackageManager.GET_SHARED_LIBRARY_FILES ); Log.v( TAG, "native library dir " + ainfo.nativeLibraryDir );
Paylaşılan nesne dosyası yoksa uygulama derlenip yüklenir ancak çalışma zamanında kilitlenir.
ARMv9: C/C++ için PAC ve BTI'yi etkinleştirme
PAC/BTI'yi etkinleştirmek bazı saldırı vektörlerine karşı koruma sağlar. PAC, iade adreslerini bir işlevin protokolünde kriptografik olarak imzalayarak ve iade adresinin epilog'da hâlâ doğru şekilde imzalanıp imzalanmadığını kontrol ederek korur. BTI, her bir dal hedefin özel bir talimat olmasını zorunlu kılarak kodunuza rastgele yerlere gitmeyi önler. Bunun için işlemciye yalnızca varış noktasının uygun olduğunu söylemesi gerekir.
Android, yeni talimatları desteklemeyen eski işlemcilerde hiçbir şey yapmayan PAC/BTI talimatlarını kullanır. PAC/BTI koruması yalnızca ARMv9 cihazlarında bulunur, ancak aynı kodu ARMv8 cihazlarda da çalıştırabilirsiniz: Kitaplığınızın birden fazla varyantı olması gerekmez. ARMv9 cihazlarda bile PAC/BTI yalnızca 64 bit kod için geçerlidir.
PAC/BTI'yi etkinleştirmek kod boyutunda küçük bir artışa (genellikle %1) neden olur.
PAC/BTI hedefinin saldırı vektörleri ve korumanın işleyişi hakkında ayrıntılı bilgi edinmek için Arm'un Mimariyi öğrenme - Karmaşık yazılımlara karşı koruma sağlama bölümüne (PDF) bakın.
Derleme değişiklikleri
-in-build
Android.mk dosyanızın her modülünde LOCAL_BRANCH_PROTECTION := standard
değerini ayarlayın.
CMake
CMakeLists.txt dosyanızdaki her hedef için target_compile_options($TARGET PRIVATE -mbranch-protection=standard)
kullanın.
Diğer derleme sistemleri
Kodunuzu -mbranch-protection=standard
kullanarak derleyin. Bu işaret yalnızca arm64-v8a ABI için derleme yaparken çalışır. Bağlantı oluştururken bu işareti kullanmanız gerekmez.
Sorun giderme
PAC/BTI için derleyici desteği konusunda herhangi bir sorun olduğunun farkında değiliz. Ancak:
- Bağlantı oluştururken BTI ile BTI olmayan kodları karıştırmamaya dikkat edin. Bu işlem, BTI korumasının etkin olmadığı bir kitaplıkta görünür. Sonuçta kullandığınız kitaplıkta BTI notu olup olmadığını kontrol etmek için llvm-readelf'i kullanabilirsiniz.
$ llvm-readelf --notes LIBRARY.so [...] Displaying notes found in: .note.gnu.property Owner Data size Description GNU 0x00000010 NT_GNU_PROPERTY_TYPE_0 (property note) Properties: aarch64 feature: BTI, PAC [...] $
OpenSSL'nin eski sürümlerinde (1.1.1i'den önceki), elle oluşturulan bir derlemede PAC hatalarına neden olan bir hata vardır. Geçerli OpenSSL sürümüne geçin.
Bazı uygulama DRM sistemlerinin eski sürümleri, PAC/BTI gereksinimlerini ihlal eden kod oluşturur. Uygulama DRM'sini kullanıyorsanız ve PAC/BTI'yi etkinleştirirken sorunlarla karşılaşırsanız sabit bir sürüm için DRM sağlayıcınızla iletişime geçin.