Farklı Android cihazlar farklı CPU'lar kullanır, bu da farklı talimat setlerini destekler. Her CPU ve talimat seti kombinasyonunun kendi Uygulama İkili Arayüzü (ABI) vardır. ABI aşağıdaki bilgileri içerir:
- Kullanılabilen CPU talimat grubu (ve uzantıları).
- Çalışma zamanında depolanan bellek ve yüklemelerin sabitliği. Android her zaman küçük endian'dır.
- Uygulamalar ile sistem arasında veri aktarımı için kullanılan kurallar (hizalama kısıtlamaları ve sistemin işlevleri çağırırken yığını ve kayıtları nasıl kullandığı dahil).
- Programlar ve paylaşılan kitaplıklar gibi yürütülebilir ikili dosyaların biçimi ve destekledikleri içerik türleri. Android her zaman ELF kullanır. Daha fazla bilgi için ELF System V Uygulama İkili Arabirimi bölümüne bakın.
- C++ adlarının nasıl bozulduğunu gösteren resim. Daha fazla bilgi için Genel/Itanium C++ ABI başlıklı makaleyi inceleyin.
Bu sayfada, NDK'nın desteklediği ABI'ler listelenmekte ve her ABI'nin işleyiş şekli hakkında bilgi verilmektedir.
ABI, platform tarafından desteklenen yerel API'yi de ifade edebilir. 32 bit sistemleri etkileyen bu tür ABI sorunlarının listesi için 32 bit ABI hataları başlıklı makaleyi inceleyin.
Desteklenen ABI'lar
ABI | Desteklenen Talimat Grupları | Notlar |
---|---|---|
armeabi-v7a |
|
ARMv5/v6 cihazlarla uyumlu değildir. |
arm64-v8a |
Yalnızca Armv8.0. | |
x86 |
MOVBE veya SSE4 desteklenmez. | |
x86_64 |
|
Tam x86-64-v1, ancak yalnızca kısmi x86-64-v2 (LAHF-SAHF yok). |
Not: NDK geçmişte ARMv5 (armeabi) ve 32 bit ile 64 bit MIPS'i desteklemesine rağmen 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 da bu kapsamdadır.
ABI'nın Android'e özgü 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'nın derleme sistemleri, ndk-build için Android.mk
dosyanızda LOCAL_ARM_MODE
veya CMake'i yapılandırırken ANDROID_ARM_MODE
kullanmadığınız sürece varsayılan olarak Thumb-2 kodu oluşturur.
Neon'un geçmişi hakkında daha fazla bilgi için Neon Destek sayfasına bakın.
Geçmiş nedenlerden dolayı bu ABI, -mfloat-abi=softfp
kullanır. Bu da işlev çağrıları yapılırken tüm float
değerlerinin tam sayı kaydedicilerinde ve tüm double
değerlerinin tam sayı kaydedici çiftlerinde iletilmesine neden olur. Adına rağmen bu, yalnızca kayan nokta çağrı kuralını etkiler: Derleyici, aritmetik için donanım kayan nokta talimatlarını kullanmaya devam eder.
Bu ABI, 64 bit bir long double
kullanır (IEEE ikili programı64 double
ile aynıdır).
arm64-v8a
Bu ABI, 64 bit ARM CPU'lar içindir.
ABI'nin Android'e özgü olmayan bölümleriyle ilgili tüm ayrıntılar için Arm'ın Mimariyi Öğrenin başlıklı makalesine bakın. Arm, 64 bit Android Geliştirme bölümünde bazı taşıma önerileri de sunar.
Gelişmiş SIMD uzantısından yararlanmak için C ve C++ kodunda Neon iç işlevlerini kullanabilirsiniz. Neon Programcı Kılavuzu for Armv8-A'da genel olarak Neon intrinsics ve Neon programlama hakkında daha fazla bilgi sunulmaktadır.
Android'de platforma özgü x18 kaydedicisi ShadowCallStack için ayrılmıştır ve kodunuz tarafından değiştirilmemelidir. Clang'ın mevcut sürümleri Android'de varsayılan olarak -ffixed-x18
seçeneğini kullanır. Bu nedenle, elle yazılmış bir derleyiciniz (veya çok eski bir derleyiciniz) yoksa bu konuda endişelenmenize gerek yoktur.
Bu ABI, 128 bit bir long double
(IEEE ikili 128) kullanır.
x86
Bu ABI, genellikle "x86", "i386" veya "IA-32" olarak bilinen talimat setini destekleyen CPU'lar içindir.
Android'in ABI'si, temel talimat setinin yanı sıra MMX, SSE, SSE2, SSE3 ve SSSE3 uzantılarını içerir.
ABI, MOVBE veya SSE4'ün herhangi bir varyantı gibi isteğe bağlı başka hiçbir IA-32 talimat grubu uzantısı içermez. Bu uzantıları etkinleştirmek için çalışma zamanı özellik incelemesini kullandığınız ve bunları desteklemeyen cihazlar için yedekler sağladığınız sürece bu uzantıları kullanmaya devam edebilirsiniz.
NDK araç zinciri, işlev çağrısından önce 16 baytlık yığın hizalaması olduğunu varsayar. Varsayılan araçlar ve seçenekler bu kuralı zorunlu kılar. Birleştirme kodu yazıyorsanız yığın hizalamasını koruduğunuzdan ve diğer derleyicilerin de bu kurala uyduğundan emin olmanız gerekir.
Daha fazla bilgi için aşağıdaki dokümanlara bakın:
- Farklı C++ derleyicileri ve işletim sistemleri için çağrı sözleşmeleri
- Intel IA-32 Intel Architecture Software Developer's Manual, Volume 2: Instruction Set Reference
- Intel IA-32 Intel Architecture Software Developer's Manual, Volume 3: System Programming Guide
- System V Uygulama İkili Arayüzü: Intel386 İşlemci Mimarisi Ek
Bu ABI, 64 bit bir long double
kullanır (IEEE ikili programı64 double
ile aynıdır ve daha yaygın olan 80 bit yalnızca Intel long double
sürümü değildir).
x86_64
Bu ABI, genellikle "x86-64" olarak adlandırılan talimat setini destekleyen CPU'lar içindir.
Android'in ABI'si, temel talimat setinin yanı sıra MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2 ve POPCNT talimatlarını içerir.
ABI, MOVBE, SHA veya AVX'nin herhangi bir varyantı gibi isteğe bağlı başka x86-64 talimat seti uzantıları içermez. Bu uzantıları etkinleştirmek için çalışma zamanında özellik araştırması kullandığınızda ve bunları desteklemeyen cihazlar için yedek seçenekler sağladığınızda kullanmaya devam edebilirsiniz.
Daha fazla bilgi için aşağıdaki belgelere bakın:
- Farklı C++ derleyicileri ve işletim sistemleri için çağrı kuralları
- Intel64 ve IA-32 Mimarileri Yazılım Geliştirici Kılavuzu, Cilt 2: Komut Kümesi Referansı
- Intel64 ve IA-32 Intel Architecture Yazılım Geliştirici Kılavuzu Cilt 3: Sistem Programlama
Bu ABI, 128 bitlik bir long double
(IEEE binary128) kullanır.
Belirli bir ABI için kod oluşturma
Gradle
Gradle (ister Android Studio aracılığıyla ister komut satırından olsun), varsayılan olarak kullanımdan kaldırılmamış tüm ABI'ler için derleme oluşturur. Uygulamanızın desteklediği ABI grubunu kısıtlamak için abiFilters
öğesini kullanın. Örneğin, yalnızca 64 bit ABI'ler için derleme yapmak istiyorsanız build.gradle
'ünüzde aşağıdaki yapılandırmayı ayarlayın:
android {
defaultConfig {
ndk {
abiFilters 'arm64-v8a', 'x86_64'
}
}
}
ndk-build
ndk-build derlemeleri için varsayılan olarak kullanımdan kaldırılmamış tüm ABI'ler kullanılır. Application.mk dosyanızda APP_ABI
ayarlayarak belirli ABI'leri hedefleyebilirsiniz. Aşağıdaki snippet'te, APP_ABI
kullanımıyla ilgili birkaç örnek gösterilmektedir:
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 bilgi için Application.mk dosyasına bakın.
CMake
CMake ile, aynı anda tek bir ABI için derleme yaparsınız ve ABI'nızı açık bir şekilde belirtmeniz gerekir. Bunu, komut satırında belirtilmesi gereken ANDROID_ABI
değişkeniyle yaparsınız (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 derleme yapmak için CMake'e iletilmesi gereken diğer işaretler için CMake kılavuzuna bakın.
Derleme sisteminin varsayılan davranışı, her ABI'nin ikili dosyalarını büyük APK olarak da bilinen tek bir APK'ya dahil etmektir. Büyük APK, yalnızca tek bir ABI'nin ikili dosyalarını içeren APK'dan önemli ölçüde daha büyüktür. Bu durumda, daha geniş uyumluluk elde edilir ancak APK daha büyük olur. Maksimum cihaz uyumluluğundan ödün vermeden APK'larınızın boyutunu küçültmek için App Bundle veya APK Bölmelerinden yararlanmanız önemle tavsiye edilir.
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 kodu otomatik olarak ayıklama bölümünü inceleyin.
Android platformunda ABI yönetimi
Bu bölümde, Android platformunun APK'lardaki 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şturulmuş kitaplıklar bulmayı bekler:
/lib/<abi>/lib<name>.so
Burada <abi>
, Desteklenen ABI'ler altında listelenen ABI adlarından biridir ve <name>
, Android.mk
dosyasındaki LOCAL_MODULE
değişkeni için tanımladığınız şekilde kitaplığın adıdır. APK dosyaları yalnızca ZIP dosyaları olduğundan, bunları açmak ve paylaşılan yerel kitaplıkların ait oldukları yerde olduğunu onaylamak çok kolaydır.
Sistem, beklediği yerde paylaşılan yerel kitaplıkları bulamazsa bu kitaplıkları kullanamaz. Bu durumda, uygulamanın kitaplıkları kopyalayıp dlopen()
işlemini gerçekleştirmesi gerekir.
Büyük 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 mevcutsa yerel kitaplıkları armeabi-v7a
dizini yerine armeabi
dizininden yükler. Bunun nedeni, /lib/armeabi/
'ün APK'da /lib/armeabi-v7a/
'ten sonra gelmesidir. Bu sorun 4.0.4 sürümünde düzeltilmiştir.
Android platformu ABI desteği
Derlemeye özgü sistem özellikleri aşağıdakileri belirttiğinden Android sistemi, çalışma zamanında hangi ABI'leri desteklediğini bilir:
- Sistem görüntüsünde kullanılan makine koduna karşılık gelen, cihazın birincil ABI'si.
- İsteğe bağlı olarak, sistem görüntüsünün desteklediği diğer ABI'ye karşılık gelen ikincil ABI'ler.
Bu mekanizma, sistemin kurulum sırasında paketten en iyi makine kodunu çıkarmasını sağlar.
En iyi performans için doğrudan birincil ABI için derlemeniz gerekir. Örneğin, tipik bir ARMv5TE tabanlı cihaz yalnızca birincil ABI'yi tanımlar: armeabi
. Buna karşılık, ARMv7 tabanlı tipik bir cihaz, her biri için oluşturulan uygulama yerel ikili programlarını çalıştırabildiğinden, birincil ABI'yı armeabi-v7a
ve ikincil ABI'yı armeabi
olarak tanımlar.
64 bit cihazlar, 32 bit varyantlarını da destekler. Örnek olarak arm64-v8a cihazları kullanacak olursak cihaz, armeabi ve armeabi-v7a kodunu da çalıştırabilir. Bununla birlikte, uygulamanızın armeabi-v7a sürümünü çalıştıran cihaza güvenmek yerine arm64-v8a'yı hedeflediği takdirde 64 bit cihazlarda çok daha iyi performans göstereceğini unutmayın.
Birçok x86 tabanlı cihaz, armeabi-v7a
ve armeabi
NDK ikililerini de çalıştırabilir. Bu tür cihazlarda birincil ABI x86
, ikinci ABI ise armeabi-v7a
olur.
Belirli bir ABI için APK'yı zorla yükleyebilirsiniz. Bu işlem, test için yararlı olabilir. 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ı
Paket yöneticisi hizmeti, bir uygulamayı yüklerken APK'yı tarar ve aşağıdaki biçimdeki paylaşılan kitaplıkları arar:
lib/<primary-abi>/lib<name>.so
Hiçbiri bulunamazsa ve ikincil bir ABI tanımladıysanız hizmet aşağıdaki biçime sahip 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 dizinindeki (<nativeLibraryDir>/
) /lib/lib<name>.so
klasörüne kopyalar. Aşağıdaki snippet'ler nativeLibraryDir
öğesini 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 );
Ortak nesne dosyası yoksa uygulama derlenip yüklenir ancak çalışma zamanında kilitlenir.
ARMv9: C/C++ için PAC ve BTI'yı etkinleştirme
PAC/BTI'yi etkinleştirmek, bazı saldırı vektörlerine karşı koruma sağlar. PAC, işlevin prologunda kriptografik olarak imzalayarak ve epilogda dönüş adresinin hâlâ doğru şekilde imzalandığını kontrol ederek dönüş adreslerini korur. BTI, her şube hedefinin, işleyene oraya varmanın uygun olduğunu söylemekten başka bir şey yapmayan özel bir talimat olmasını zorunlu kılarak kodunuzda rastgele konumlara atlamayı önler.
Android, yeni talimatları desteklemeyen eski işlemcilerde hiçbir şey yapmayan PAC/BTI talimatlarını kullanır. Yalnızca ARMv9 cihazlarda PAC/BTI koruması bulunur ancak aynı kodu ARMv8 cihazlarda da çalıştırabilirsiniz. Bu durumda kitaplığınızın birden fazla varyantına gerek yoktur. ARMv9 cihazlarda bile PAC/BTI yalnızca 64 bit kod için geçerlidir.
PAC/BTI'yi etkinleştirmek, kod boyutunda genellikle %1 oranında küçük bir artışa neden olur.
PAC/BTI hedefi saldırı vektörleri ve korumanın işleyiş şekli hakkında ayrıntılı bilgi edinmek için Arm'ın Mimariyi öğrenme - Karmaşık yazılımlar için koruma sağlama (PDF) adlı kursuna bakabilirsiniz.
Derleme değişiklikleri
ndk-kurum
Android.mk dosyanızı 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ğiyle ilgili herhangi bir sorunla karşılaşmadık ancak:
- BTI korumasının etkin olmadığı bir kitaplık elde edileceğinden, bağlantı oluştururken BTI ile BTI olmayan kodları karıştırmamaya dikkat edin. Elde ettiğiniz kitaplıkta BTI notunun 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 öncesi), elle yazılmış derleyicide PAC hatalarına neden olan bir hata vardır. Mevcut OpenSSL sürümüne yükseltin.
Bazı uygulama DRM sistemlerinin eski sürümleri, PAC/BTI şartlarını ihlal eden kodlar oluşturur. Uygulama DRM'si kullanıyorsanız ve PAC/BTI'yi etkinleştirirken sorun yaşıyorsanız düzeltilmiş bir sürüm için DRM tedarikçinizle iletişime geçin.