Android ABI'lar

Farklı Android cihazlar farklı CPU'lar kullanır. Bu da farklı talimat gruplarını destekler. Her CPU ve talimat kümesi kombinasyonunun kendi Uygulama İkili Arabirimi (ABI) vardır. ABI, aşağıdaki bilgileri içerir:

  • Kullanılabilen CPU talimat grubu (ve uzantılar).
  • Çalışma zamanında bellek depolama ve yükleme bitişi. Android her zaman küçük endian bir iştir.
  • Hizalama kısıtlamaları da dahil olmak üzere uygulamalar ile sistem arasında veri aktarımı yapma kuralları ve sistemin, işlevleri çağırırken yığını nasıl kullandığını ve nasıl kaydettiğini öğrenin.
  • 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 Arabirimi bölümüne bakın.
  • C++ adlarının nasıl karıştırıldığı. Daha fazla bilgi için Genel/Itanyum C++ ABI sayfasına bakın.

Bu sayfada, NDK'nın desteklediği ABI'ler sıralanmakta ve her bir ABI'nin çalışma şekli hakkında bilgi sağlanmaktadır.

ABI, platform tarafından desteklenen yerel API'ye de işaret edebilir. 32 bit sistemleri etkileyen bu tür ABI sorunlarının listesi için 32 bit ABI hataları bölümüne bakın.

Desteklenen ABI'ler

Tablo 1. ABI'ler ve desteklenen talimat grupları.

ABI Desteklenen Talimat Grupları Notlar
armeabi-v7a
  • Armeabi
  • Beğen-2
  • Neon
  • ARMv5/v6 cihazlarla uyumlu değildir.
    arm64-v8a
  • AArch64
  • Yalnızca Armv8.0.
    x86
  • X86 (IA-32)
  • AAX
  • SSE/2/3
  • SSSE3
  • MOVBE veya SSE4 için destek yoktur.
    x86_64
  • 86-64
  • AAX
  • SSE/2/3
  • SSSE3
  • SSE4.1, 4,2
  • POPCNT
  • Yalnızca x86-64-v1.

    Not: NDK, geçmişte ARMv5 (armeabi) ile 32 bit ve 64 bit MIPS'yi destekliyordu ancak bu ABI'ler için destek NDK r17'de kaldırıldı.

    armeabi-v7a

    Bu ABI, 32 bit ARM CPU'lar içindir. Thumb-2 ve Neon'u içerir.

    ABI'nın Android'e özel olmayan bölümleri hakkında bilgi edinmek için ARM Mimarisi için Uygulama İkili Arabirimi (ABI) sayfasına bakın.

    NDK'nın derleme sistemleri, CMake'i yapılandırırken Android.mk içinde LOCAL_ARM_MODE, CMake'ı yapılandırırken ANDROID_ARM_MODE kullanmazsanız varsayılan olarak Thumb-2 kodu oluşturur.

    Neon'un geçmişi hakkında daha fazla bilgi edinmek için Neon Desteği sayfasını ziyaret edin.

    Geçmişteki nedenlerden dolayı bu ABI, -mfloat-abi=softfp işlevini kullanarak tüm float değerlerinin tam sayı kayıtlarında geçirilmesine ve tüm double değerlerinin işlev çağrıları yapılırken tam sayı kayıt çiftlerinde geçirilmesine 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 bitlik bir long double (double ile aynı IEEE ikili programı64) kullanır.

    kol64-v8a

    Bu ABI, 64 bit ARM CPU'lar içindir.

    ABI'nın Android'e özel olmayan bölümlerinin tüm ayrıntıları için Arm'ın Mimariyi Öğrenme sayfasına bakın. Arm, ayrıca 64 bit Android Geliştirme konusunda bazı taşıma önerileri de sunmaktadır.

    Gelişmiş SIMD uzantısından yararlanmak için C ve C++ kodunda Neon intrinsics özelliğini kullanabilirsiniz. Neon Programmer's Guide for Armv8-A (Arv8-A İçin Neon Programcı Kılavuzu) belgesinde, genel olarak Neon iç yapısı ve Neon programlama hakkında daha fazla bilgi yer alır.

    Android'de, platforma özel x18 kaydı ShadowCallStack için ayrılmıştır ve kodunuza dokunulmamalıdır. Clang'ın mevcut sürümleri, Android'de varsayılan olarak -ffixed-x18 seçeneğini kullanır. Bu nedenle, elle yazabileceğiniz bir derleyiciniz (veya çok eski bir derleyiciniz) yoksa bu konuda endişelenmeniz gerekmez.

    Bu ABI, 128 bitlik bir long double (IEEE ikili programı128) kullanır.

    86 kat

    Bu ABI, genellikle "x86", "i386" veya "IA-32" olarak bilinen talimat grubunu destekleyen CPU'lar içindir.

    Android'in ABI'sı, temel talimat grubunun 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 IA-32 talimat grubu uzantıları içermez. Bu uzantıları etkinleştirmek için çalışma zamanı özellik kontrolü kullandığınız ve bunları desteklemeyen cihazlar için yedekler sağladığınız sürece bunları kullanmaya devam edebilirsiniz.

    NDK araç zinciri, işlev çağrısından önce 16 baytlık yığın hizalamasının olduğunu varsayar. Varsayılan araçlar ve seçenekler bu kuralı uygular. Derleme 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 belgeleri inceleyin:

    Bu ABI, 64 bitlik bir long double kullanır (IEEE ikili programı64 double ile aynıdır ve daha yaygın olan 80 bit Intel-yalnızca Intel long double ile aynı değildir).

    x86_64

    Bu ABI, genellikle "x86-64" olarak adlandırılan talimat grubunu destekleyen CPU'lar içindir.

    Android'in ABI'sı, temel talimat grubunun yanı sıra MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2 ve POPCNT talimatını içerir.

    ABI; MOVBE, SHA veya AVX'in herhangi bir varyantı gibi isteğe bağlı diğer x86-64 talimat grubu uzantılarını içermez. Bu uzantıları, etkinleştirmek için çalışma zamanı özellik kontrolü kullandığınız ve bunları desteklemeyen cihazlar için yedekler sağladığınız sürece bunları kullanmaya devam edebilirsiniz.

    Daha fazla bilgi için aşağıdaki belgeleri inceleyin:

    Bu ABI, 128 bitlik bir long double (IEEE ikili programı128) kullanır.

    Belirli bir ABI için kod oluşturma

    Gradle

    Gradle (ister Android Studio üzerinden ister komut satırından kullanılsın), varsayılan olarak kullanımdan kaldırılmamış tüm ABI'ler için derleme yapar. Uygulamanızın desteklediği ABI grubunu kısıtlamak için abiFilters değerini kullanın. Örneğin, yalnızca 64 bit ABI'ler için derleme yapmak üzere build.gradle dosyanızda aşağıdaki yapılandırmayı ayarlayın:

    android {
        defaultConfig {
            ndk {
                abiFilters 'arm64-v8a', 'x86_64'
            }
        }
    }
    

    ndk-build

    Varsayılan olarak kullanımdan kaldırılmayan tüm ABI'ler için ndk-build derlemeleri. Application.mk dosyanızda APP_ABI değerini ayarlayarak belirli bir ABI'leri hedefleyebilirsiniz. Aşağıdaki snippet'te APP_ABI kullanımına dair 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 bilgiyi Application.mk adresinde bulabilirsiniz.

    CMake

    CMake ile, bir seferde tek bir ABI için derlersiniz 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 derlemek amacıyla 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 eklemektir. Bu, şişman APK olarak da bilinir. Şişman bir APK, tek bir ABI için yalnızca ikili programları içeren bir APK'dan çok daha büyüktür; bunun karşılığında daha fazla uyumluluk sağlanır, ancak bunun karşılığında daha büyük bir APK gerekir. Maksimum cihaz uyumluluğunu korurken APK'larınızın boyutunu küçültmek için Uygulama Paketleri 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 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ğine dair ayrıntılar sağlanmaktadır.

    Uygulama paketlerindeki yerel kod

    Hem Play Store hem de Paket Yöneticisi, aşağıdaki kalıpla eşleşen APK içindeki dosya yollarında NDK tarafından oluşturulan kitaplıkları bulmayı bekler:

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

    Burada <abi>, Desteklenen ABI'ler başlığı altında listelenen ABI adlarından biridir. <name> ise kitaplığın, Android.mk dosyasında LOCAL_MODULE değişkeni için tanımladığınız adıdır. APK dosyaları sadece zip dosyaları olduğundan, bunları açmak ve paylaşılan yerel kitaplıkların ait oldukları yerde olduklarını onaylamak çok önemlidir.

    Sistem, beklendiği yerde yerel paylaşılan kitaplıkları bulamazsa bunları kullanamaz. Böyle bir durumda, uygulamanın kendisi kitaplıkları kopyalamalı ve ardından dlopen() işlemi yapmalıdır.

    Yağ APK'sında her kitaplık, adı karşılık gelen bir ABI ile eşleşen bir dizin altında bulunur. Örneğin, şişman 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 daha eski 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/ kelimesinin APK'da /lib/armeabi-v7a/ kısmından sonra gelmesidir. Bu sorun 4.0.4 sürümünde düzeltilmiştir.

    Android platformu ABI desteği

    Derlemeye özel sistem özellikleri aşağıdakileri gösterdiğinden Android sistemi, çalışma zamanında hangi ABI'leri desteklediğini bilir:

    • Sistem görüntüsünün 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 de desteklediği diğer ABI'lere karşılık gelen ikincil ABI'ler.

    Bu mekanizma, sistemin yükleme sırasında paketten en iyi makine kodunu çıkarmasını sağlar.

    En iyi performansı elde etmek istiyorsanız doğrudan birincil ABI için derleme yapmanız gerekir. Örneğin, ARMv5TE tabanlı tipik bir cihaz yalnızca birincil ABI'yi tanımlar: armeabi. Buna karşılık, ARMv7 tabanlı tipik bir cihaz, birincil ABI'yi armeabi-v7a ve ikincil ABI'yı armeabi olarak tanımlar. Bunun nedeni, her biri için oluşturulan uygulama yerel ikili kodlarını çalıştırabilmesidir.

    64 bit cihazlar, 32 bit varyantlarını da destekler. Örnek olarak arm64-v8a cihazları ele alındığında, cihaz armeabi ve armeabi-v7a kodunu da çalıştırabilir. Ancak uygulamanızın arm64-v8a'yı hedeflemesi yerine 64 bit cihazlarda çok daha iyi performans göstereceğini unutmayın.

    x86 tabanlı cihazların çoğu, armeabi-v7a ve armeabi NDK ikili programlarını da çalıştırabilir. Bu tür cihazlar için birincil ABI x86, ikinci ABI ise armeabi-v7a olur.

    Belirli bir ABI için apk'yi zorunlu olarak yükleyebilirsiniz. Bu, test için yararlıdır. Şu komutu kullanın:

    adb install --abi abi-identifier path_to_apk
    

    Yükleme sırasında yerel kodun otomatik olarak çıkarılması

    Bir uygulamayı yüklerken, paket yöneticisi hizmeti APK'yı tarar ve formun paylaşılan kitaplıklarını arar:

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

    Hiçbiri bulunmazsa ve ikincil bir ABI tanımladıysanız hizmet, şu biçimde paylaşılan kitaplıklar için tarama yapar:

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

    Paket yöneticisi, aradığı kitaplıkları bulduğunda bunları uygulamanın yerel kitaplık dizini (<nativeLibraryDir>/) altındaki /lib/lib<name>.so konumuna kopyalar. Aşağıdaki snippet'ler nativeLibraryDir bilgisini 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 );
    

    Hiçbir paylaşılan nesne dosyası yoksa uygulama derlenir ve yüklenir ancak çalışma zamanında kilitlenir.

    ARMv9: C/C++ için PAC ve BTI'yi etkinleştirme

    PAC/BTI'nın etkinleştirilmesi bazı saldırı vektörlerine karşı koruma sağlar. PAC, iade adreslerini işlevin prolog'unda kriptografik olarak imzalayarak ve dönüş adresinin hâlâ epilogda doğru şekilde imzalanıp imzalanmadığını kontrol ederek korur. BTI, her dal hedefinin işlemciye oraya gitmenin sorun olmadığını söylemekten başka bir işlevi olmayan özel bir talimat olmasını gerektirerek kodunuzdaki rastgele konumlara atlamayı önler.

    Android, yeni talimatları desteklemeyen eski işlemcilerde hiçbir işlem 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ına gerek yoktur. ARMv9 cihazlarda bile PAC/BTI yalnızca 64 bit kod için geçerlidir.

    PAC/BTI'nın etkinleştirilmesi kod boyutunda küçük bir artışa (genellikle %1) neden olur.

    PAC/BTI hedefi saldırı vektörleri ve korumanın işleyiş şekliyle ilgili ayrıntılı bir açıklama için Arm'ın Mimariyi öğrenme - Karmaşık yazılımlar için koruma sağlama (PDF) bölümüne bakın.

    Derleme değişiklikleri

    ndk-build

    Android.mk'nizin her modülünde LOCAL_BRANCH_PROTECTION := standard 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

    -mbranch-protection=standard kullanarak kodunuzu 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 sorun olduğunu bilmiyoruz ancak:

    • Bağlama işlemi sırasında BTI ile BTI olmayan kodları karıştırmamaya dikkat edin. Aksi takdirde BTI korumasının etkinleştirilmediği bir kitaplık ortaya çıkar. Elde ettiğiniz kitaplıkta BTI notu olup olmadığını kontrol etmek için llvm-readelf 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 sürümler), elle yazılmış derleyicide PAC hatalarına neden olan bir hata vardır. Mevcut OpenSSL'ye geçin.

    • Bazı uygulama DRM sistemlerinin eski sürümleri, PAC/BTI gereksinimlerini ihlal eden kodlar oluşturur. Uygulama DRM kullanıyorsanız ve PAC/BTI'yı etkinleştirirken sorunlarla karşılaşıyorsanız düzeltilmiş bir sürüm için DRM tedarikçi firmanızla iletişime geçin.