অ্যান্ড্রয়েড এবিআই (original) (raw)

বিভিন্ন অ্যান্ড্রয়েড ডিভাইস বিভিন্ন সিপিইউ ব্যবহার করে, যা বিভিন্ন নির্দেশ সেট সমর্থন করে। CPU এবং নির্দেশ সেটের প্রতিটি সংমিশ্রণের নিজস্ব অ্যাপ্লিকেশন বাইনারি ইন্টারফেস (ABI) রয়েছে। একটি ABI নিম্নলিখিত তথ্য অন্তর্ভুক্ত করে:

এই পৃষ্ঠাটি NDK সমর্থন করে এমন ABIগুলিকে গণনা করে এবং প্রতিটি ABI কীভাবে কাজ করে সে সম্পর্কে তথ্য সরবরাহ করে।

ABI প্ল্যাটফর্ম দ্বারা সমর্থিত নেটিভ API-কেও উল্লেখ করতে পারে। 32-বিট সিস্টেমগুলিকে প্রভাবিত করে এমন ABI সমস্যাগুলির একটি তালিকার জন্য, 32-বিট ABI বাগগুলি দেখুন।

সমর্থিত ABI

সারণি 1. ABI এবং সমর্থিত নির্দেশ সেট।

এবিআই সমর্থিত নির্দেশ সেট নোট
armeabi-v7a আরমেবি থাম্ব-2 নিয়ন ARMv5/v6 ডিভাইসের সাথে বেমানান।
arm64-v8a AArch64 শুধুমাত্র Armv8.0।
x86 x86 (IA-32) এমএমএক্স SSE/2/3 SSSE3 MOVBE বা SSE4 এর জন্য কোন সমর্থন নেই।
x86_64 x86-64 এমএমএক্স SSE/2/3 SSSE3 SSE4.1, 4.2 POPCNT CMPXCHG16B লাহফ-সাহফ সম্পূর্ণ x86-64-v2

দ্রষ্টব্য: ঐতিহাসিকভাবে NDK ARMv5 (armeabi), এবং 32-bit এবং 64-bit MIPS সমর্থিত, কিন্তু NDK r17-এ এই ABI-এর সমর্থন সরিয়ে দেওয়া হয়েছে।

armeabi-v7a

এই ABI 32-বিট ARM CPU-এর জন্য। এর মধ্যে রয়েছে থাম্ব-২ এবং নিয়ন।

এবিআই-এর যে অংশগুলি অ্যান্ড্রয়েড-নির্দিষ্ট নয় সেগুলি সম্পর্কে তথ্যের জন্য, এআরএম আর্কিটেকচারের জন্য অ্যাপ্লিকেশন বাইনারি ইন্টারফেস (এবিআই) দেখুন

NDK-এর বিল্ড সিস্টেমগুলি ডিফল্টরূপে Thumb-2 কোড তৈরি করে যদি না আপনি ndk-build-এর জন্য আপনার Android.mkLOCAL_ARM_MODE ব্যবহার করেন বা CMake কনফিগার করার সময় ANDROID_ARM_MODE ব্যবহার না করেন।

নিয়নের ইতিহাস সম্পর্কে আরও তথ্যের জন্য, নিয়ন সমর্থন দেখুন।

ঐতিহাসিক কারণে, এই ABI -mfloat-abi=softfp ব্যবহার করে যার ফলে সমস্ত float মান পূর্ণসংখ্যা রেজিস্টারে পাস করা হয় এবং ফাংশন কল করার সময় সমস্ত double মান পূর্ণসংখ্যা রেজিস্টার জোড়ায় পাস করা হয়। নাম থাকা সত্ত্বেও, এটি শুধুমাত্র ফ্লোটিং পয়েন্ট কলিং কনভেনশনকে প্রভাবিত করে: কম্পাইলার এখনও গাণিতিকের জন্য হার্ডওয়্যার ফ্লোটিং পয়েন্ট নির্দেশাবলী ব্যবহার করবে।

এই ABI একটি 64-বিট long double ব্যবহার করে ( IEEE binary64 একই double )।

arm64-v8a

এই ABI 64-বিট ARM CPU-এর জন্য।

ABI-এর যে অংশগুলি Android-নির্দিষ্ট নয় সেগুলির সম্পূর্ণ বিবরণের জন্য Arm's Learn the Architecture দেখুন। আর্ম 64-বিট অ্যান্ড্রয়েড ডেভেলপমেন্টে কিছু পোর্টিং পরামর্শও দেয়।

অ্যাডভান্সড SIMD এক্সটেনশনের সুবিধা নিতে আপনি C এবং C++ কোডে নিয়ন ইন্ট্রিনসিক ব্যবহার করতে পারেন। Armv8-A-এর জন্য নিয়ন প্রোগ্রামার গাইড সাধারণভাবে নিয়ন অন্তর্নিহিত এবং নিয়ন প্রোগ্রামিং সম্পর্কে আরও তথ্য প্রদান করে।

অ্যান্ড্রয়েডে, প্ল্যাটফর্ম-নির্দিষ্ট x18 রেজিস্টার ShadowCallStack-এর জন্য সংরক্ষিত এবং আপনার কোড দ্বারা স্পর্শ করা উচিত নয়। ক্ল্যাং-এর বর্তমান সংস্করণগুলি অ্যান্ড্রয়েডে -ffixed-x18 বিকল্প ব্যবহার করার জন্য ডিফল্ট, তাই আপনার হাতে লেখা অ্যাসেম্বলার (বা খুব পুরানো কম্পাইলার) না থাকলে আপনাকে এই বিষয়ে চিন্তা করতে হবে না।

এই ABI একটি 128-বিট long double ( IEEE binary128 ) ব্যবহার করে।

x86

এই ABI সিপিইউ-এর জন্য নির্দেশনা সেট সমর্থন করে যা সাধারণত "x86", "i386", বা "IA-32" নামে পরিচিত।

অ্যান্ড্রয়েডের ABI-তে বেস ইন্সট্রাকশন সেট এবং MMX , SSE , SSE2 , SSE3 , এবং SSSE3 এক্সটেনশন অন্তর্ভুক্ত রয়েছে৷

ABI অন্য কোনো ঐচ্ছিক IA-32 নির্দেশনা সেট এক্সটেনশন যেমন MOVBE বা SSE4 এর কোনো রূপ অন্তর্ভুক্ত করে না। আপনি এখনও এই এক্সটেনশনগুলি ব্যবহার করতে পারেন, যতক্ষণ না আপনি রানটাইম বৈশিষ্ট্য-প্রোবিং ব্যবহার করেন তাদের সক্ষম করতে, এবং যে ডিভাইসগুলিকে সমর্থন করে না তাদের জন্য ফলব্যাক প্রদান করে৷

NDK টুলচেন একটি ফাংশন কলের আগে 16-বাইট স্ট্যাক প্রান্তিককরণ অনুমান করে। ডিফল্ট সরঞ্জাম এবং বিকল্পগুলি এই নিয়ম প্রয়োগ করে। আপনি যদি অ্যাসেম্বলি কোড লিখছেন, তাহলে আপনাকে অবশ্যই স্ট্যাক অ্যালাইনমেন্ট বজায় রাখা নিশ্চিত করতে হবে এবং নিশ্চিত করতে হবে যে অন্যান্য কম্পাইলাররাও এই নিয়ম মেনে চলে।

আরও বিস্তারিত জানার জন্য নিম্নলিখিত নথিগুলি পড়ুন:

এই ABI একটি 64-বিট long double ব্যবহার করে ( IEEE binary64 double মতোই, এবং আরও সাধারণ 80-বিট ইন্টেল-শুধুমাত্র long double নয়)।

x86_64

এই ABI CPU-এর জন্য নির্দেশনা সেট সমর্থন করে যা সাধারণত "x86-64" হিসাবে উল্লেখ করা হয়।

অ্যান্ড্রয়েড-এর ABI-তে বেস নির্দেশনা সেট প্লাস MMX , SSE , SSE2 , SSE3 , SSSE3 , SSE4.1 , SSE4.2 , এবং POPCNT নির্দেশ অন্তর্ভুক্ত রয়েছে৷

ABI অন্য কোনো ঐচ্ছিক x86-64 নির্দেশ সেট এক্সটেনশন যেমন MOVBE, SHA, বা AVX-এর কোনো রূপ অন্তর্ভুক্ত করে না। আপনি এখনও এই এক্সটেনশনগুলি ব্যবহার করতে পারেন, যতক্ষণ না আপনি রানটাইম ফিচার প্রোবিং এগুলিকে সক্রিয় করতে ব্যবহার করেন এবং যে ডিভাইসগুলিকে সমর্থন করে না তাদের জন্য ফলব্যাক প্রদান করেন৷

আরও বিস্তারিত জানার জন্য নিম্নলিখিত নথিগুলি পড়ুন:

এই ABI একটি 128-বিট long double ( IEEE binary128 ) ব্যবহার করে।

একটি নির্দিষ্ট ABI-এর জন্য কোড তৈরি করুন

গ্রেডল

গ্রেডল (এন্ড্রয়েড স্টুডিওর মাধ্যমে বা কমান্ড লাইন থেকে ব্যবহার করা হোক না কেন) ডিফল্টরূপে সমস্ত অ-বঞ্চিত ABI-এর জন্য তৈরি করে। আপনার অ্যাপ্লিকেশন সমর্থন করে এমন ABI-এর সেট সীমাবদ্ধ করতে, abiFilters ব্যবহার করুন। উদাহরণস্বরূপ, শুধুমাত্র 64-বিট ABI-এর জন্য তৈরি করতে, আপনার build.gradle এ নিম্নলিখিত কনফিগারেশন সেট করুন:

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

ndk-বিল্ড

ndk-build ডিফল্টরূপে সমস্ত অ-বঞ্চিত ABI-এর জন্য তৈরি করে। আপনি আপনার Application.mk ফাইলে APP_ABI সেট করে একটি নির্দিষ্ট ABI কে টার্গেট করতে পারেন। নিম্নলিখিত স্নিপেটটি 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 ...

NDK-এর সাথে তৈরি করার জন্য অন্যান্য পতাকাগুলির জন্য যা অবশ্যই CMake-এ পাস করতে হবে, CMake গাইড দেখুন।

বিল্ড সিস্টেমের ডিফল্ট আচরণ হল প্রতিটি ABI-এর জন্য বাইনারিগুলিকে একটি একক APK, যা একটি ফ্যাট APK নামেও পরিচিত। একটি মোটা APK একটি একক ABI-এর জন্য শুধুমাত্র বাইনারি ধারণকারী একটি থেকে উল্লেখযোগ্যভাবে বড়; ট্রেডঅফ বৃহত্তর সামঞ্জস্যতা অর্জন করছে, কিন্তু একটি বড় APK এর খরচে। এটি দৃঢ়ভাবে সুপারিশ করা হয় যে আপনি ডিভাইসের সর্বাধিক সামঞ্জস্য বজায় রেখে আপনার APKগুলির আকার কমাতে অ্যাপ বান্ডেল বা APK স্প্লিটগুলির সুবিধা গ্রহণ করুন৷

ইনস্টলেশনের সময়, প্যাকেজ ম্যানেজার টার্গেট ডিভাইসের জন্য শুধুমাত্র সবচেয়ে উপযুক্ত মেশিন কোড আনপ্যাক করে। বিস্তারিত জানার জন্য, ইনস্টল করার সময় নেটিভ কোডের স্বয়ংক্রিয় নিষ্কাশন দেখুন।

অ্যান্ড্রয়েড প্ল্যাটফর্মে ABI ব্যবস্থাপনা

এই বিভাগে Android প্ল্যাটফর্ম কীভাবে APK-এ নেটিভ কোড পরিচালনা করে সে সম্পর্কে বিশদ বিবরণ প্রদান করে।

অ্যাপ প্যাকেজে নেটিভ কোড

প্লে স্টোর এবং প্যাকেজ ম্যানেজার উভয়ই নিম্নোক্ত প্যাটার্নের সাথে মিলে যাওয়া APK-এর ভিতরে ফাইলপাথগুলিতে NDK-উত্পন্ন লাইব্রেরিগুলি খুঁজে পাওয়ার আশা করে:

/lib//lib.so

এখানে, <abi> সমর্থিত ABIs-এর অধীনে তালিকাভুক্ত ABI নামগুলির মধ্যে একটি, এবং <name> হল লাইব্রেরির নাম যেমন আপনি এটিকে Android.mk ফাইলে LOCAL_MODULE ভেরিয়েবলের জন্য সংজ্ঞায়িত করেছেন। যেহেতু APK ফাইলগুলি শুধুমাত্র জিপ ফাইল, তাই সেগুলি খোলা এবং নিশ্চিত করা তুচ্ছ ব্যাপার যে শেয়ার করা নেটিভ লাইব্রেরিগুলি যেখানে সেগুলি রয়েছে৷

যদি সিস্টেমটি নেটিভ শেয়ার্ড লাইব্রেরি খুঁজে না পায় যেখানে এটি তাদের প্রত্যাশা করে, এটি সেগুলি ব্যবহার করতে পারে না। এই ধরনের ক্ষেত্রে, অ্যাপটিকে নিজেই লাইব্রেরিগুলি অনুলিপি করতে হবে এবং তারপরে dlopen() সম্পাদন করতে হবে।

একটি মোটা APK-এ, প্রতিটি লাইব্রেরি একটি ডিরেক্টরির অধীনে থাকে যার নাম একটি সংশ্লিষ্ট 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

দ্রষ্টব্য: ARMv7-ভিত্তিক অ্যান্ড্রয়েড ডিভাইসগুলি 4.0.3 বা তার আগের চলমান থাকলে armeabi-v7a ডিরেক্টরির পরিবর্তে armeabi ডিরেক্টরি থেকে নেটিভ লাইব্রেরি ইনস্টল করে যদি উভয় ডিরেক্টরিই বিদ্যমান থাকে। কারণ APK-এ /lib/armeabi/ /lib/armeabi-v7a/ armeabi/ আসে। এই সমস্যাটি 4.0.4 থেকে ঠিক করা হয়েছে।

অ্যান্ড্রয়েড প্ল্যাটফর্ম ABI সমর্থন

অ্যান্ড্রয়েড সিস্টেম রানটাইমে জানে যে এটি কোন ABI(গুলি) সমর্থন করে, কারণ বিল্ড-নির্দিষ্ট সিস্টেম বৈশিষ্ট্যগুলি নির্দেশ করে:

এই প্রক্রিয়াটি নিশ্চিত করে যে সিস্টেমটি ইনস্টলেশনের সময় প্যাকেজ থেকে সেরা মেশিন কোড বের করে।

সেরা পারফরম্যান্সের জন্য, আপনাকে প্রাথমিক ABI-এর জন্য সরাসরি কম্পাইল করা উচিত। উদাহরণস্বরূপ, একটি সাধারণ ARMv5TE-ভিত্তিক ডিভাইস শুধুমাত্র প্রাথমিক ABI: armeabi সংজ্ঞায়িত করবে। বিপরীতে, একটি সাধারণ, ARMv7-ভিত্তিক ডিভাইস প্রাথমিক ABI-কে armeabi-v7a হিসাবে এবং সেকেন্ডারিটিকে armeabi হিসাবে সংজ্ঞায়িত করবে, যেহেতু এটি তাদের প্রত্যেকের জন্য তৈরি করা অ্যাপ্লিকেশন নেটিভ বাইনারি চালাতে পারে।

64-বিট ডিভাইসগুলি তাদের 32-বিট রূপগুলিকে সমর্থন করে। উদাহরণ হিসেবে arm64-v8a ডিভাইস ব্যবহার করে, ডিভাইসটি armeabi এবং armeabi-v7a কোডও চালাতে পারে। মনে রাখবেন, যাইহোক, আপনার অ্যাপ্লিকেশানটি 64-বিট ডিভাইসে অনেক ভালো পারফর্ম করবে যদি এটি আপনার অ্যাপ্লিকেশানের armeabi-v7a সংস্করণে চলমান ডিভাইসের উপর নির্ভর না করে arm64-v8a কে লক্ষ্য করে।

অনেক x86-ভিত্তিক ডিভাইস armeabi-v7a এবং armeabi NDK বাইনারি চালাতে পারে। এই ধরনের ডিভাইসগুলির জন্য, প্রাথমিক ABI হবে x86 , এবং দ্বিতীয়টি, armeabi-v7a

আপনি একটি নির্দিষ্ট ABI-এর জন্য জোর করে একটি apk ইনস্টল করতে পারেন। এটি পরীক্ষার জন্য দরকারী। নিম্নলিখিত কমান্ড ব্যবহার করুন:

adb install --abi abi-identifier path_to_apk

ইনস্টল করার সময় নেটিভ কোডের স্বয়ংক্রিয় নিষ্কাশন

একটি অ্যাপ্লিকেশন ইনস্টল করার সময়, প্যাকেজ ম্যানেজার পরিষেবা APK স্ক্যান করে, এবং ফর্মের যে কোনো ভাগ করা লাইব্রেরি খোঁজে:

lib//lib.so

যদি কোনটি পাওয়া না যায়, এবং আপনি একটি মাধ্যমিক ABI সংজ্ঞায়িত করেন, তাহলে ফর্মের ভাগ করা লাইব্রেরির জন্য পরিষেবা স্ক্যান করে:

lib//lib.so

যখন এটি লাইব্রেরিগুলি খুঁজে পায় যেগুলি এটি খুঁজছে, প্যাকেজ ম্যানেজার সেগুলিকে /lib/lib<name>.so এ অনুলিপি করে, অ্যাপ্লিকেশনটির নেটিভ লাইব্রেরি ডিরেক্টরি ( <nativeLibraryDir>/ ) এর অধীনে। নিম্নলিখিত স্নিপেটগুলি nativeLibraryDir পুনরুদ্ধার করে:

কোটলিন

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}")

জাভা

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: C/C++ এর জন্য PAC এবং BTI সক্ষম করা

PAC/BTI সক্ষম করা কিছু আক্রমণ ভেক্টরের বিরুদ্ধে সুরক্ষা প্রদান করবে। PAC একটি ফাংশনের প্রোলগে ক্রিপ্টোগ্রাফিকভাবে সাইন ইন করে এবং রিটার্ন অ্যাড্রেসটি এখনও এপিলগে সঠিকভাবে সাইন করা হয়েছে কিনা তা পরীক্ষা করে ফেরত ঠিকানাগুলিকে রক্ষা করে। বিটিআই আপনার কোডের অবাধ অবস্থানে ঝাঁপিয়ে পড়তে বাধা দেয় যে প্রতিটি শাখার লক্ষ্য একটি বিশেষ নির্দেশ যা প্রসেসরকে বলে যে সেখানে অবতরণ করা ঠিক আছে।

অ্যান্ড্রয়েড PAC/BTI নির্দেশাবলী ব্যবহার করে যা নতুন নির্দেশাবলী সমর্থন করে না এমন পুরানো প্রসেসরগুলিতে কিছুই করে না। শুধুমাত্র ARMv9 ডিভাইসে PAC/BTI সুরক্ষা থাকবে, কিন্তু আপনি ARMv8 ডিভাইসেও একই কোড চালাতে পারেন: আপনার লাইব্রেরির একাধিক রূপের প্রয়োজন নেই। এমনকি ARMv9 ডিভাইসেও, PAC/BTI শুধুমাত্র 64-বিট কোডে প্রযোজ্য।

PAC/BTI সক্ষম করার ফলে কোডের আকার সামান্য বৃদ্ধি পাবে, সাধারণত 1%।

আক্রমণ ভেক্টর PAC/BTI টার্গেট এবং কীভাবে সুরক্ষা কাজ করে তার বিস্তারিত ব্যাখ্যার জন্য আর্মস আর্কিটেকচার শিখুন - জটিল সফ্টওয়্যার ( পিডিএফ ) এর জন্য সুরক্ষা প্রদান করুন।

পরিবর্তনগুলি তৈরি করুন

ndk-বিল্ড

আপনার Android.mk-এর প্রতিটি মডিউলে LOCAL_BRANCH_PROTECTION := standard সেট করুন।

সিমেক

আপনার CMakeLists.txt-এ প্রতিটি লক্ষ্যের জন্য target_compile_options($TARGET PRIVATE -mbranch-protection=standard) ব্যবহার করুন।

অন্যান্য বিল্ড সিস্টেম

-mbranch-protection=standard ব্যবহার করে আপনার কোড কম্পাইল করুন। arm64-v8a ABI-এর জন্য কম্পাইল করার সময় এই পতাকাটি শুধুমাত্র কাজ করে। লিঙ্ক করার সময় আপনাকে এই পতাকা ব্যবহার করতে হবে না।

সমস্যা সমাধান

আমরা PAC/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 [...] $