Android ABI'lar

Farklı Android cihazlar, farklı talimat setlerini destekleyen farklı CPU'lar kullanır. Her CPU ve talimat grubu kombinasyonunun kendi Uygulama İkili Arabirimi (ABI) vardır. ABI’da aşağıdaki bilgiler yer alır:

  • Kullanılabilen CPU talimat grubu (ve uzantılar).
  • Çalışma zamanında bellek depolama ve yükleme işlemlerinin bitiş değeri. Android her zaman küçük bir yaratıktır.
  • Hizalama kısıtlamaları da dahil olmak üzere uygulamalar ile sistem arasında veri geçirme kuralları ve sistemin, işlevleri çağırırken yığını kullanma ve kaydetme yöntemi.
  • 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/Itanium C++ ABI bölümüne bakın.

Bu sayfada, NDK'nın desteklediği ABI'ler listelenmekte ve her ABI'nin nasıl çalıştığı hakkında bilgi verilmektedir.

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üne bakın.

Desteklenen ABI'ler

Tablo 1. ABI'ler ve desteklenen talimat setleri.

ABI Desteklenen Talimat Setleri Notlar
armeabi-v7a
  • Armeabi
  • Küçük-2
  • VFPv3-D16
  • 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 yok.
    x86_64
  • x86-64
  • AAX
  • SSE/2/3
  • SSSE3
  • SSE4.1, 4,2
  • POPCN
  • Yalnızca x86-64-v1.

    Not: NDK, geçmişte ARMv5'i (armeabi) ve 32 bit ile 64 bit MIPS'yi destekliyordu ancak bu ABI'lere yönelik destek NDK r17'de kaldırılmıştı.

    Armeabi-v7a

    Bu ABI, 32 bit ARM CPU'lar içindir. Bu sürüm, Thumb-2 ve Neon (VFP) donanım kayan nokta talimatlarını, özellikle de 16 özel 64 bit kayan nokta kaydına sahip VFPv3-D16'yı içerir.

    ABI'nın Android'e özel olmayan bölümleri hakkında bilgi almak isterseniz ARM Mimarisi için Uygulama İkili Arabirimi (ABI) bölümüne bakın

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

    Gelişmiş SIMD (Neon) ve VFPv3-D32 gibi diğer uzantılar isteğe bağlıdır. Daha fazla bilgi için Neon Desteği sayfasını inceleyin.

    Bu ABI, işlev çağrıları yaparken derleyicinin tam sayı kayıtlarındaki tüm float değerlerini ve tam sayı kaydı çiftlerindeki tüm double değerlerini geçirmesi gerektiğini belirten kuralı uygulamak için -mfloat-abi=softfp kullanır. Bu yalnızca çağrı kuralını etkiler. Derleyici, donanım kayan nokta talimatlarını kullanmaya devam edecektir.

    Bu ABI, 64 bitlik bir long double (double ile aynı IEEE ikili64) kullanır.

    kol64-v8a

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

    ABI'nın Android'e özel olmayan kısımlarının tüm ayrıntıları için Arm'un Mimariyi Öğrenme adlı makalesine bakın. Arm, 64 bit Android Geliştirme konusunda da bazı taşıma önerileri sunuyor.

    Gelişmiş SIMD uzantısından yararlanmak için C ve C++ kodunda Neon yerleşik özelliklerini kullanabilirsiniz. Neon Programcı'nın Armv8-A Kılavuzu'nda, genel olarak Neon yapıları ve Neon programlaması hakkında daha fazla bilgi yer alır.

    Android'de, platforma özel x18 kaydı ShadowCallStack için ayrılmıştır ve kodunuza dokunmamalıdır. 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şelenmeniz gerekmez.

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

    86 x

    Bu ABI, genellikle "x86", "i386" veya "IA-32" olarak bilinen talimat grubunu 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 diğer isteğe bağlı IA-32 talimat setleri uzantısını içermez. Etkinleştirmek için çalışma zamanı özellik durum kontrolünden yararlandığı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ı 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 ayrıntılı bilgi için aşağıdaki belgelere bakın:

    Bu ABI, 64 bit bir long double kullanır (double ile aynı olan ve daha yaygın olarak kullanılan 80 bit Intel'in yalnızca long double ile aynı olan IEEE ikili programı64).

    x86_64

    Bu ABI, genellikle "x86-64" olarak adlandırılan talimat grubunu 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 talimatını içerir.

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

    Daha ayrıntılı bilgi için aşağıdaki belgelere bakın:

    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ılmayan 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'
            }
        }
    }
    

    NK-build

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

    Yapay Zeka

    CMake ile, aynı anda tek bir ABI için derleme yaparsınız ve ABI'nızı açık bir şekilde belirtmeniz gerekir. Bu işlemi 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 için CMake'e iletilmesi gereken diğer işaretler için CMake rehberine bakın.

    Derleme sisteminin varsayılan davranışı, her ABI için ikili programları tek bir APK'ya (şişman APK olarak da bilinir) eklemektir. Şişman bir APK, tek bir ABI için yalnızca ikili programları içeren 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'ya karşılık gelir. Maksimum cihaz uyumluluğunu korurken 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 çıkarma bölümünü inceleyin.

    Android platformunda ABI yönetimi

    Bu bölümde, Android platformunun APK'lardaki yerel kodu nasıl yönettiğiyle ilgili ayrıntılar yer almaktadır.

    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 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, yerel paylaşılan kitaplıkları beklediği yerde bulamazsa bunları kullanamaz. Böyle bir durumda, uygulamanın kendisi kitaplıkları kopyalayıp dlopen() işlemini gerçekleştirmelidir.

    Yağlı bir APK'da her kitaplık, adı karşılık gelen bir 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 daha eski bir sürümü çalıştıran ARMv7 tabanlı Android cihazlar, her iki dizin de mevcutsa yerel kitaplıkları armeabi-v7a dizini yerine armeabi dizininden yükler. Çünkü /lib/armeabi/, APK'da /lib/armeabi-v7a/ kısmından sonra gelir. 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'si.
    • İ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 için 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. Çünkü cihaz, her biri için oluşturulan uygulama yerel ikili programlarını çalıştırabilir.

    64 bit cihazlar, 32 bit varyantlarını da destekler. Örnek olarak arm64-v8a cihazlarını kullanarak armeabi ve armeabi-v7a kodunu da çalıştırabilirsiniz. Bununla birlikte, uygulamanızın arm64-v8a sürümünü hedefliyorsa uygulamanızın armeabi-v7a sürümünü çalıştıran cihaza bağlı kalması yerine 64 bit cihazlarda çok daha iyi performans göstereceğini unutmayın.

    x86 tabanlı birçok cihaz, armeabi-v7a ve armeabi NDK ikililerini de çalıştırabilir. Bu tür cihazlar için birincil ABI x86, ikinci ABI ise armeabi-v7a olur.

    Belirli bir ABI için APK'yı zorunlu 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 kodu otomatik olarak çıkarma

    Bir uygulama yüklenirken paket yöneticisi hizmeti APK'yı tarar ve biçimde paylaşılan kitaplıkları 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 öğesine 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ç paylaşılan nesne dosyası yoksa uygulama derlenir ve yüklenir ancak çalışma zamanında kilitlenir.

    ARMv9: C/C++ için PAC ve BTI'yı 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 imzalayıp iade adresinin epilog'da hâlâ doğru şekilde oturum açmış olup olmadığını kontrol ederek korur. BTI, her dal hedefinin işlemciye oraya gitmenin sorun yaşanmadığını söylemekten başka işlevi olmayan özel bir talimat olmasını zorunlu kılarak kodunuzda rastgele konumlara atlamayı önler.

    Android, yeni talimatları desteklemeyen eski işlemcilerde hiçbir işlem yapmayan PAC/BTI talimatları 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'nın hedeflediği saldırı vektörleri ve korumanın işleyiş şekliyle ilgili ayrıntılı bir açıklama için Arm'un Mimariyi öğrenin - Karmaşık yazılımlar için koruma sağlama (PDF) bölümüne bakın.

    Yapı değişiklikleri

    NK-build

    Android.mk dosyanızın her modülünde LOCAL_BRANCH_PROTECTION := standard ayarlayın.

    Yapay Zeka

    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ği ile ilgili herhangi bir sorun olduğunu bilmiyoruz ancak:

    • Bağlarken BTI ile BTI olmayan kodları karıştırmamaya dikkat edin. Bu işlem BTI korumasının etkinleştirilmediği bir kitaplık oluşturur. Ortaya çıkan kitaplığınızda 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 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çinizle iletişime geçin.