Android ABI'lar

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

Tablo 1. ABI'ler ve desteklenen talimat kümeleri.

ABI Desteklenen Talimat Grupları Notlar
armeabi-v7a
  • Ermeabi
  • Beğeni-2
  • Neon
  • ARMv5/v6 cihazlarla uyumlu değildir.
    arm64-v8a
  • AArch64
  • Yalnızca Armv8.0.
    x86
  • x86 (IA-32)
  • MMX
  • SSE/2/3
  • SSSE3
  • MOVBE veya SSE4 desteklenmez.
    x86_64
  • x86-64
  • MİKS
  • SSE/2/3
  • SSSE3
  • SSE4.1, 4.2
  • POPCNT
  • CMPXCHG16B
  • 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:

    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:

    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.