Android ABI

تستخدم أجهزة Android المختلفة وحدات معالجة مركزية (CPU) مختلفة، وبالتالي تتوافق جميعها مع أجهزة ومجموعات التعليمات. لكل مجموعة من وحدة المعالجة المركزية (CPU) ومجموعة التعليمات الخاصة بها واجهة التطبيق الثنائية (ABI). يتضمن واجهة التطبيق الثنائية (ABI) المعلومات التالية:

  • هي مجموعة تعليمات وحدة المعالجة المركزية (CPU) (والإضافات) التي يمكن استخدامها.
  • انتهاء صلاحية تخزين الذاكرة وتحميلها في وقت التشغيل دائمًا ما يكون Android الصغيرة.
  • اصطلاحات تمرير البيانات بين التطبيقات والنظام، بما في ذلك وقيود المحاذاة وكيف يستخدم النظام المكدس عند استدعاء الدوال.
  • تنسيق الملفات الثنائية القابلة للتنفيذ، مثل البرامج والمكتبات المشتركة، وأنواع المحتوى التي تتيحها يستخدم Android دائمًا تنسيق ELF. لمزيد من المعلومات، المعلومات، راجع الواجهة الثنائية تطبيق ELF System V
  • كيفية تشويه أسماء C++. لمزيد من المعلومات، يُرجى مراجعة عامة/Itanium C++ ABI.

تلخص هذه الصفحة واجهات التطبيق الثنائية (ABI) التي تدعمها NDK، وتقدّم معلومات. حول كيفية عمل كل واجهة تطبيق ثنائية (ABI).

يمكن أن تشير واجهة التطبيق الثنائية (ABI) أيضًا إلى واجهة برمجة التطبيقات الأصلية التي تتوافق معها المنصة. بالنسبة إلى قائمة بأنواع مشاكل واجهة التطبيق الثنائية التي تؤثر على أنظمة 32 بت، راجع أخطاء ABI 32 بت

واجهات التطبيق الثنائية (ABI) المتوافقة

الجدول 1. واجهات التطبيق الثنائية (ABI) ومجموعات التعليمات المتوافقة

ABI مجموعات التعليمات المتوافقة ملاحظات
armeabi-v7a
  • أرميبي
  • رائع 2
  • نيون
  • غير متوافق مع الأجهزة التي تتضمّن ARMv5/v6.
    arm64-v8a
  • معيار AArch64
  • فقط مع Armv8.0
    x86
  • x86 (IA-32)
  • فريق MMX
  • SSE/2/3
  • معيار SSSE3
  • لا يتوافق أي من ملفات MOVBE أو SSE4.
    x86_64
  • X86- 64
  • فريق MMX
  • SSE/2/3
  • معيار SSSE3
  • SSE4.1 ، 4.2
  • بروتوكول POPCNT
  • الإصدار الكامل x86-64-v1 ولكن فقط x86-64-v2 (بدون CMPXCHG16B أو LAHF-SAHF).

    ملاحظة: كان تنسيق ARMv5 متوافقًا مع NDK سابقًا. و32 بت و64 بت، ولكن لم تتم إتاحة واجهات التطبيق الثنائية (ABI) هذه في الإصدار 17 من NDK.

    armeabi-v7a

    إنّ واجهة التطبيق الثنائية (ABI) هذه مخصّصة لوحدات المعالجة المركزية التي تعمل بتقنية ARM بسرعة 32 بت. ويشمل ذلك كلاً من أعجبني 2 ونيون.

    للحصول على معلومات عن أجزاء واجهة التطبيق الثنائية (ABI) التي لا تقتصر على Android، يُرجى الاطّلاع على واجهة التطبيق الثنائية (ABI) لبنية ARM

    تنشئ أنظمة التصميم التابعة لـ NDK رمز Thumb-2 تلقائيًا ما لم تستخدم LOCAL_ARM_MODE في Android.mk لمدة ndk-build أو ANDROID_ARM_MODE عند ضبط CMake.

    للحصول على مزيد من المعلومات حول تاريخ Neon، يمكنك الاطّلاع على دعم Neon.

    لأسباب سابقة، يستخدم واجهة التطبيق الثنائية (ABI) هذه -mfloat-abi=softfp مما يؤدي إلى عرض كل float. القيم التي سيتم تمريرها في سجلات الأعداد الصحيحة وسيتم تمرير جميع قيم double في أزواج سجلات الأعداد الصحيحة عند إجراء استدعاءات الدوال. على الرغم من الاسم، تؤثر فقط في اصطلاح النقطة العائمة: سيظل المحول البرمجي استخدام تعليمات النقطة العائمة للأجهزة في الحساب.

    تستخدم واجهة ABI هذه long double 64 بت (IEEE ثنائية64 مثل double).

    Arm64-v8a

    إنّ واجهة التطبيق الثنائية (ABI) هذه مخصّصة لوحدات المعالجة المركزية التي تعمل بتقنية ARM بسرعة 64 بت.

    الاطّلاع على مجموعة التجربة التعرّف على البنية للحصول على تفاصيل كاملة لأجزاء واجهة التطبيق الثنائية (ABI) غير المتعلّقة بنظام التشغيل Android. مجموعة التجربة أيضًا بعض النصائح بشأن النقل في تطوير Android 64 بت:

    يمكنك استخدام دوال نيون في الرموز C وC++ للاستفادة من إضافة SIMD المتقدمة. تشير رسالة الأشكال البيانية دليل مبرمِجين النيون لأسلحة Armv8-A يوفر المزيد من المعلومات حول أساسيات النيون وبرمجة النيون بشكل عام.

    على Android، يتم تخصيص سجل x18 الخاص بالنظام الأساسي ShadowCallStack ويجب ألا يتأثر بكودك. الإصدارات الحالية من Clang الافتراضية هي باستخدام خيار -ffixed-x18 على Android، لذا ما لم تكن تكتب باليد (أو برنامج تجميع قديم جدًا) فلا داعي للقلق بشأن هذا الأمر.

    تستخدم واجهة التطبيق الثنائية (ABI) هذه long double 128 بت (IEEE dual128).

    ×86

    إنّ واجهة التطبيق الثنائية (ABI) هذه مخصّصة لوحدات المعالجة المركزية التي تتيح مجموعة التعليمات المعروفة باسم "x86". "i386"، أو "IA-32".

    يتضمن واجهة التطبيق الثنائية (ABI) في Android مجموعة التعليمات الأساسية بالإضافة إلى MMX SSE، SSE2، SSE3 SSSE3 إضافات.

    لا يتضمّن واجهة التطبيق الثنائية (ABI) أيّ مجموعة تعليمات اختيارية أخرى من بنية IA-32. مثل MOVBE أو أي من متغيرات SSE4. لا يزال بإمكانك استخدام هذه الإضافات، ما دمت تستخدم أداة التحقق من الميزات في بيئة التشغيل وتمكينها، وتوفير إجراءات احتياطية للأجهزة التي لا تتوافق معها.

    تفترض سلسلة أدوات NDK محاذاة مكدس بحجم 16 بايت قبل استدعاء الدالة. تتيح الأدوات خيارات فرض هذه القاعدة. إذا كنت تكتب كود التجميع، فيجب التأكد من الحفاظ على المحاذاة والتأكد من أن برامج التجميع الأخرى تتبع هذه القاعدة أيضًا.

    يمكنك الاطّلاع على المستندات التالية للحصول على مزيد من التفاصيل:

    يستخدم واجهة التطبيق الثنائية (ABI) long double 64 بت (IEEE dual64 مثل double، وليس أكثر long double مشترك مع Intel 80 بت فقط).

    ×86_64

    إنّ واجهة التطبيق الثنائية (ABI) هذه مخصّصة لوحدات المعالجة المركزية التي تتيح مجموعة التعليمات المُشار إليها عادةً باسم. "x86-64".

    يتضمن واجهة التطبيق الثنائية (ABI) في Android مجموعة التعليمات الأساسية بالإضافة إلى MMX، SSE، SSE2، SSE3، SSSE3، SSE4.1، SSE4.2، تعليمات POPCNT.

    لا تتضمّن واجهة التطبيق الثنائية (ABI) أيّ مجموعة تعليمات اختيارية أخرى من النوع x86-64. مثل MOVBE أو SHA أو أي من صيغ AVX. لا يزال بإمكانك استخدام هذه الإضافات، ما دمت تستخدم أداة التحقق من ميزات بيئة التشغيل وتمكينها، وتوفير إجراءات احتياطية للأجهزة التي لا تتوافق معها.

    يمكنك الاطّلاع على المستندات التالية للحصول على مزيد من التفاصيل:

    تستخدم واجهة التطبيق الثنائية (ABI) هذه long double 128 بت (IEEE dual128).

    إنشاء رمز لواجهة التطبيق الثنائية (ABI) المحدّدة

    قاعدة مخروطية

    تعمل منصة Gradle (سواء تم استخدامها عبر Android Studio أو من سطر الأوامر) على إنشاء جميع واجهات التطبيق الثنائية (ABI) التي لم يتم إيقافها نهائيًا. لتقييد مجموعة واجهات التطبيق الثنائية (ABI) التي التطبيق، استخدم abiFilters. على سبيل المثال، لإنشاء واجهات التطبيق الثنائية (ABI) 64 بت، يجب ضبط الإعدادات التالية في build.gradle:

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

    لعبة ndk-build

    تعمل دالة ndk-build على جميع واجهات التطبيق الثنائية (ABI) التي لم يتم إيقافها نهائيًا. يمكنك استهداف واجهات تطبيقات ثنائية (ABI) محدّدة عن طريق ضبط APP_ABI في ملف Application.mk. تشير رسالة الأشكال البيانية يعرض المقتطف التالي بعض الأمثلة على استخدام APP_ABI:

    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، يمكنك الاطّلاع على Application.mk.

    إنشاء تصميمات الإعلانات

    باستخدام CMake، أنت تنشئ لواجهة ABI واحدة في كل مرة وعليك تحديد واجهة التطبيق الثنائية (ABI) الخاصة بك. بشكل صريح. ويمكنك إجراء ذلك باستخدام المتغير ANDROID_ABI الذي يجب أن يكون المحدد في سطر الأوامر (لا يمكن تعيينه في CMakeLists.txt). بالنسبة مثال:

    $ cmake -DANDROID_ABI=arm64-v8a ...
    $ cmake -DANDROID_ABI=armeabi-v7a ...
    $ cmake -DANDROID_ABI=x86 ...
    $ cmake -DANDROID_ABI=x86_64 ...
    

    بالنسبة إلى العلامات الأخرى التي يجب تمريرها إلى CMake للإنشاء باستخدام NDK، راجع دليل CMake

    السلوك الافتراضي لنظام التصميم هو تضمين البرامج الثنائية لكل واجهة تطبيق ثنائية (ABI). في حزمة APK واحدة، تُعرف أيضًا باسم حِزمة APK fat. حزمة APK تتضمّن دهونًا أكبر بكثير أو أكثر من واحد يحتوي فقط على البرامج الثنائية لواجهة التطبيق الثنائية (ABI) واحدة فقط؛ المفاضلة تكتسب توافقًا أوسع، ولكن على حساب حزمة APK الأكبر حجمًا. من المهم جدًا ننصحك بالاستفادة من حِزم التطبيقات أو تقسيمات حِزم APK من أجل: تقليل حجم حِزم APK مع الحفاظ على أقصى عدد مسموح به من الأجهزة التوافق.

    في وقت التثبيت، يقوم مدير الحزم بفك ضغط الحزم رمز الجهاز للجهاز المستهدف. لمعرفة التفاصيل، يُرجى الاطّلاع على الاستخراج التلقائي لبيانات الرمز الأصلي في وقت التثبيت.

    إدارة واجهات التطبيق الثنائية (ABI) على نظام Android الأساسي

    يقدّم هذا القسم تفاصيل حول كيفية إدارة نظام Android الأساسي للإعلانات المدمجة مع المحتوى. في حزم APK.

    الرموز البرمجية الأصلية في حِزم التطبيقات

    يتوقع كل من متجر Play ومدير الحزم العثور على العناصر التي تم إنشاؤها المكتبات على مسارات الملفات داخل حزمة APK التي تتطابق مع النمط التالي:

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

    <abi> هو أحد أسماء واجهات التطبيق الثنائية (ABI) المُدرجة ضمن واجهات التطبيق الثنائية (ABI) المتوافقة، و<name> هو اسم المكتبة كما حددته لـ LOCAL_MODULE في الملف Android.mk. منذ ملفات APK هي مجرد ملفات ZIP، يسهل فتحها والتأكد من أن الملفات الأصلية المشتركة والمكتبات في أماكنها.

    إذا لم يعثر النظام على المكتبات المشتركة الأصلية في المكان الذي يتوقع أن تظهر فيها، فلن يتمكن من استخدام معهم. وفي هذه الحالة، يجب على التطبيق نفسه نسخ المكتبات، إجراء dlopen()

    في ملف APK fat، تتوفّر كل مكتبة ضمن دليل يتطابق اسمه مع واجهة ABI مقابل. على سبيل المثال، قد يحتوي ملف APK غني بالدهون على ما يلي:

    /lib/armeabi/libfoo.so
    /lib/armeabi-v7a/libfoo.so
    /lib/arm64-v8a/libfoo.so
    /lib/x86/libfoo.so
    /lib/x86_64/libfoo.so
    

    ملاحظة: أجهزة Android المستندة إلى ARMv7 والتي تعمل بالإصدار 4.0.3 أو الإصدارات الأقدم تثبيت المكتبات الأصلية من دليل armeabi بدلاً من armeabi-v7a في حالة وجود كلا الدليلين. وذلك لأن /lib/armeabi/ يأتي بعد /lib/armeabi-v7a/ في حزمة APK. تم حل هذه المشكلة من الإصدار 4.0.4.

    دعم واجهة التطبيق الثنائية (ABI) لنظام Android الأساسي

    في وقت التشغيل، يعرف نظام Android واجهات التطبيق الثنائية(ABI) المتوافقة معه، وذلك لأنّ النظام الخاص بالإصدار تشير الخصائص إلى:

    • واجهة التطبيق الثنائية (ABI) الأساسية للجهاز والتي تتوافق مع رمز الجهاز المستخدَم في صورة النظام نفسها.
    • بشكل اختياري واجهات التطبيق الثنائية (ABI) الثانوية، التي تتوافق مع واجهات التطبيق الثنائية (ABI) الأخرى التي يصورها النظام يدعمها أيضًا.

    وتضمن هذه الآلية أن يستخرج النظام أفضل رمز للجهاز من الحزمة في وقت التثبيت.

    ولتحقيق أفضل أداء، عليك التجميع مباشرةً لواجهة التطبيق الثنائية (ABI) الأساسية. على سبيل المثال، سيحدد الجهاز النموذجي المستند إلى ARMv5TE واجهة التطبيق الثنائية (ABI) الأساسية فقط: armeabi. على النقيض من ذلك، في العادة، يحدّد الجهاز المستند إلى ARMv7 واجهة التطبيق الثنائية (ABI) الأساسية على أنّها armeabi-v7a والواجهة الثانوية. واحدة مثل armeabi، لأنها تستطيع تشغيل البرامج الثنائية الأصلية التي تم إنشاؤها لكل منها.

    تتوافق الأجهزة التي تعمل بالإصدار 64 بت أيضًا مع متغيرات 32 بت. استخدام أجهزة Arm64-v8a وكمثال، يمكن للجهاز أيضًا تشغيل الرمزين armeabi وarmeabi-v7a. ملاحظة: إلا أن التطبيق سيعمل بشكل أفضل بكثير على الأجهزة التي تعمل بالإصدار 64 بت إذا تستهدف Arm64-v8a بدلاً من الاعتماد على الجهاز الذي يعمل بإصدار armeabi-v7a من تطبيقك.

    يمكن أيضًا على العديد من الأجهزة المستندة إلى x86 تشغيل البرامج الثنائية التي تعمل على armeabi-v7a وarmeabi NDK. بالنسبة لهذه الأجهزة، سيكون واجهة التطبيق الثنائية (ABI) الأساسية هي x86، والثاني هو armeabi-v7a.

    يمكنك فرض تثبيت حزمة APK لواجهة ABI محدّدة. هذا مفيد للاختبار. استخدِم الأمر التالي:

    adb install --abi abi-identifier path_to_apk
    

    الاستخراج التلقائي للرمز الأصلي أثناء التثبيت

    عند تثبيت تطبيق ما، تفحص خدمة مدير الحزم حزمة APK، وتبحث عن أي المكتبات المشتركة للنموذج:

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

    في حال عدم العثور على أي منها وتحديد واجهة تطبيق ثنائية (ABI) ثانوية، تبحث الخدمة عن مكتبات مشتركة النموذج:

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

    عندما يعثر على المكتبات التي يبحث عنها، يقوم مدير الحزم بنسخ إلى /lib/lib<name>.so، ضمن دليل المكتبة الأصلي للتطبيق (<nativeLibraryDir>/). تسترد المقتطفات التالية nativeLibraryDir:

    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 );
    

    إذا لم يكن هناك ملف كائن مشترك على الإطلاق، فسيتم إنشاء التطبيق وتثبيته، ولكن يتعطل في وقت التشغيل.

    ARMv9: تمكين PAC وBTI لـ C/C++

    سيؤدي تفعيل PAC/BTI إلى توفير الحماية ضد بعض متجهات الهجوم. تحمي PAC عناوين الإرجاع عن طريق توقيعها بطريقة مشفّرة في واجهة برمجة تطبيقات والتحقق من استمرار تسجيل الدخول إلى عنوان الإرجاع بشكل صحيح الخاتمة تمنع BTI الانتقال إلى مواقع عشوائية في رمزك من خلال طلب أن كل هدف فرع يعد تعليمات خاصة لا علاقة لها بأي شيء باستثناء إلى المعالج أنه لا مانع من الوصول إلى هناك.

    يستخدم Android تعليمات PAC/BTI التي لا تضيف أي شيء إلى المعالجات القديمة لا تدعم التعليمات الجديدة. سيكون لدى الأجهزة التي تتضمّن معالجات PAC/BTI فقط الأجهزة التي تتضمّن معالجات ARMv9 غير أنّه يمكنك تشغيل الرمز نفسه على الأجهزة التي تتضمّن معالجات ARMv8 أيضًا، فلا حاجة إلى نُسخ مختلفة من مكتبتك حتى على أجهزة ARMv9، لا ينطبق PAC/BTI إلا إلى رمز 64 بت.

    سيؤدي تفعيل PAC/BTI إلى زيادة طفيفة في حجم الرمز، وعادةً ما تبلغ 1%.

    راجع تعرّف على بنية "ذراع" - توفير الحماية لـ البرامج المعقّدة (PDF) للحصول على شرح تفصيلي حول هدف PAC/BTI لمتجهات الهجوم، وكيف تعمل الحماية.

    إجراء التغييرات

    لعبة ndk-build

    يمكنك ضبط LOCAL_BRANCH_PROTECTION := standard في كل وحدة من وحدات Android.mk.

    إنشاء فيديوهات Shorts

    استخدام "target_compile_options($TARGET PRIVATE -mbranch-protection=standard)" لكل هدف في CMakeLists.txt.

    أنظمة تصميم أخرى

    اجمع الرمز الخاص بك باستخدام -mbranch-protection=standard. لا تعمل هذه العلامة إلا عند التجميع لواجهة Arm64-v8a ABI. لست بحاجة إلى استخدام هذه العلامة عند المرتبطة.

    تحديد المشاكل وحلّها

    لسنا على دراية بأي مشاكل تتعلق بدعم التجميع من أجل PAC/BTI، ولكن:

    • احرص على عدم خلط الرمز BTI والرموز الأخرى غير BTI عند الربط، لأنّ ذلك النتيجة إلى مكتبة لم يتم تفعيل حماية BTI فيها. يمكنك استخدام llvm-readelf للتحقق مما إذا كانت المكتبة الناتجة تتضمن ملاحظة BTI أم لا.
    $ 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 (الإصدار السابق 1.1.1i) على خطأ في أداة التجميع المكتوبة بخط اليد تؤدي إلى إخفاقات PAC. عليك الترقية إلى مجموعة OpenSSL الحالية.

    • تنشئ الإصدارات القديمة من بعض أنظمة إدارة الحقوق الرقمية للتطبيقات رمزًا برمجيًا ينتهك PAC/BTI متطلبات المشروع. إذا كنت تستخدم إدارة الحقوق الرقمية للتطبيق وظهرت لك مشاكل عند تفعيل PAC/BTI، يمكنك التواصل مع مورِّد إدارة الحقوق الرقمية للحصول على إصدار ثابت.