Apa itu antarmuka biner aplikasi (ABI)?


493

Saya tidak pernah mengerti dengan jelas apa itu ABI. Tolong jangan arahkan saya ke artikel Wikipedia. Jika saya bisa memahaminya, saya tidak akan berada di sini memposting posting yang panjang.

Ini adalah pola pikir saya tentang antarmuka yang berbeda:

Remote TV adalah antarmuka antara pengguna dan TV. Ini adalah entitas yang sudah ada, tetapi tidak berguna (tidak menyediakan fungsi apa pun) dengan sendirinya. Semua fungsi untuk masing-masing tombol pada kendali jarak jauh diimplementasikan di perangkat televisi.

Antarmuka: Ini adalah lapisan "entitas yang ada" antara functionalitydan consumerfungsionalitas itu. Antarmuka dengan sendirinya tidak melakukan apa pun. Itu hanya memanggil fungsi yang ada di belakang.

Sekarang tergantung pada siapa pengguna ada berbagai jenis antarmuka.

Command Line Interface (CLI) perintah adalah entitas yang ada, konsumen adalah pengguna dan fungsi di belakang.

functionality: fungsi perangkat lunak saya yang memecahkan beberapa tujuan yang kami uraikan antarmuka ini.

existing entities: perintah

consumer: pengguna

Jendela Antarmuka Pengguna Grafis (GUI) , tombol, dll. Adalah entitas yang ada, dan sekali lagi konsumen adalah pengguna dan fungsionalitas ada di belakang.

functionality: fungsionalitas perangkat lunak saya yang memecahkan beberapa masalah yang kami uraikan antarmuka ini.

existing entities: jendela, tombol dll.

consumer: pengguna

Fungsi antarmuka Pemrograman Aplikasi (API) (atau lebih tepatnya) antarmuka (dalam pemrograman berbasis antarmuka) adalah entitas yang ada, konsumen di sini adalah program lain bukan pengguna, dan lagi fungsionalitas terletak di belakang lapisan ini.

functionality: fungsionalitas perangkat lunak saya yang memecahkan beberapa masalah yang kami uraikan antarmuka ini.

existing entities: fungsi, Antarmuka (array fungsi).

consumer: program / aplikasi lain.

Application Binary Interface (ABI) Di sinilah masalah saya mulai.

functionality: ???

existing entities: ???

consumer: ???

  • Saya telah menulis perangkat lunak dalam berbagai bahasa dan menyediakan berbagai jenis antarmuka (CLI, GUI, dan API), tetapi saya tidak yakin apakah saya pernah menyediakan ABI.

Wikipedia mengatakan:

ABI mencakup rincian seperti

  • tipe data, ukuran, dan perataan;
  • konvensi pemanggilan, yang mengontrol bagaimana argumen fungsi dilewatkan dan mengembalikan nilai yang diambil;
  • nomor panggilan sistem dan bagaimana aplikasi harus membuat panggilan sistem ke sistem operasi;

Detail standar ABI lainnya seperti

  • mangling nama C ++,
  • propagasi pengecualian, dan
  • konvensi pemanggilan antar kompiler pada platform yang sama, tetapi tidak memerlukan kompatibilitas lintas platform.
  • Siapa yang butuh detail ini? Tolong jangan katakan OS. Saya tahu pemrograman perakitan. Saya tahu cara menautkan & memuat berfungsi. Saya tahu persis apa yang terjadi di dalam.

  • Mengapa C ++ name mangling masuk? Saya pikir kita berbicara di tingkat biner. Mengapa bahasa bisa digunakan?

Lagi pula, saya sudah mengunduh [PDF] System V Application Binary Interface Edition 4.1 (1997-03-18) untuk melihat apa tepatnya isinya. Yah, sebagian besar tidak masuk akal.

  • Mengapa ini berisi dua bab (4 & 5) untuk menggambarkan format file ELF ? Bahkan, ini adalah dua bab penting dari spesifikasi itu. Bab-bab selanjutnya adalah "khusus prosesor". Bagaimanapun, saya pikir itu adalah topik yang sama sekali berbeda. Tolong jangan katakan bahwa spesifikasi format file ELF adalah ABI. Itu tidak memenuhi syarat untuk menjadi antarmuka sesuai dengan definisi.

  • Saya tahu, karena kita berbicara pada tingkat rendah seperti itu pasti sangat spesifik. Tapi saya tidak yakin bagaimana itu "instruksi set arsitektur (ISA)" spesifik?

  • Di mana saya dapat menemukan ABI Microsoft Windows?

Jadi, ini adalah pertanyaan utama yang menggangguku.


7
"Tolong jangan katakan, OS" Compiler perlu tahu ABI. Linker perlu mengetahui ABI. Kernel perlu mengetahui ABI untuk mengatur program dalam RAM agar dapat berjalan dengan baik. Adapun C ++ lihat di bawah, ini sengaja mengubah label menjadi omong kosong karena metode overloading dan pribadi, dan linker dan kompiler lain perlu memiliki nama kompatibel mangling untuk bekerja dengannya, dengan kata lain ABI yang sama.
Justin Smith

8
Saya pikir pertanyaannya sangat jelas; menggambarkan dengan tepat apa format jawaban yang diharapkan dan belum ada satu pun jawaban memuaskan yang dapat diterima.
legends2k

3
@ legends2k Pandangan saya tentang masalah ini adalah bahwa OP memang tahu apa itu ABI, tetapi tidak menyadarinya. Sebagian besar programmer tidak akan pernah mendesain atau menyediakan ABI, karena itu adalah pekerjaan para perancang OS / platform.
JesperE

4
@JesperE: Saya setuju dengan maksud Anda. Tapi mungkin OP ingin mengetahuinya dengan jelas, dalam format yang menurutnya cocok, meskipun dia mungkin tidak perlu menyediakan ABI.
legends2k

2
Saya bodoh. Baru-baru ini sambil bekerja dengan semua hal ini. Saya menyadari apa sebenarnya ABI itu. Ya, saya setuju bahwa templat saya salah. Tidak cocok untuk memasukkan ABI ke template saya. Terima kasih @ JasperE. Butuh pengalaman kerja untuk menyadari jawaban Anda.
cakar

Jawaban:


536

Salah satu cara mudah untuk memahami "ABI" adalah membandingkannya dengan "API".

Anda sudah terbiasa dengan konsep API. Jika Anda ingin menggunakan fitur, katakanlah, beberapa perpustakaan atau OS Anda, Anda akan memprogram melawan API. API terdiri dari tipe data / struktur, konstanta, fungsi, dll yang dapat Anda gunakan dalam kode Anda untuk mengakses fungsionalitas komponen eksternal itu.

ABI sangat mirip. Anggap saja sebagai versi kompilasi dari API (atau sebagai API pada tingkat bahasa mesin). Saat Anda menulis kode sumber, Anda mengakses perpustakaan melalui API. Setelah kode dikompilasi, aplikasi Anda mengakses data biner di perpustakaan melalui ABI. ABI mendefinisikan struktur dan metode yang akan digunakan aplikasi terkompilasi Anda untuk mengakses perpustakaan eksternal (seperti halnya API), hanya pada tingkat yang lebih rendah. API Anda menentukan urutan di mana Anda meneruskan argumen ke suatu fungsi. ABI Anda menentukan mekanisme bagaimanaargumen ini diteruskan (register, stack, dll.). API Anda menentukan fungsi mana yang merupakan bagian dari perpustakaan Anda. ABI Anda menentukan bagaimana kode Anda disimpan di dalam file perpustakaan, sehingga program apa pun yang menggunakan perpustakaan Anda dapat menemukan fungsi yang diinginkan dan menjalankannya.

ABI sangat penting dalam hal aplikasi yang menggunakan perpustakaan eksternal. Perpustakaan penuh dengan kode dan sumber daya lainnya, tetapi program Anda harus tahu cara menemukan apa yang dibutuhkan di dalam file perpustakaan. ABI Anda menentukan bagaimana konten perpustakaan disimpan di dalam file, dan program Anda menggunakan ABI untuk mencari melalui file dan menemukan apa yang dibutuhkan. Jika semua yang ada di sistem Anda sesuai dengan ABI yang sama, maka setiap program dapat bekerja dengan file perpustakaan apa pun, tidak peduli siapa yang membuatnya. Linux dan Windows menggunakan ABI yang berbeda, sehingga program Windows tidak akan tahu cara mengakses perpustakaan yang dikompilasi untuk Linux.

Terkadang, perubahan ABI tidak dapat dihindari. Ketika ini terjadi, semua program yang menggunakan pustaka itu tidak akan berfungsi kecuali jika mereka dikompilasi ulang untuk menggunakan pustaka versi baru. Jika ABI berubah tetapi API tidak, maka versi pustaka lama dan baru kadang-kadang disebut "sumber kompatibel". Ini menyiratkan bahwa sementara program yang dikompilasi untuk satu versi pustaka tidak akan bekerja dengan yang lain, kode sumber yang ditulis untuk satu akan bekerja untuk yang lain jika dikompilasi ulang.

Karena alasan ini, pengembang cenderung mencoba menjaga ABI mereka stabil (untuk meminimalkan gangguan). Menjaga ABI stabil berarti tidak mengubah antarmuka fungsi (tipe dan jumlah pengembalian, jenis, dan urutan argumen), definisi tipe data atau struktur data, konstanta yang ditentukan, dll. Fungsi dan tipe data baru dapat ditambahkan, tetapi yang sudah ada harus tetap, sama. Jika, misalnya, perpustakaan Anda menggunakan bilangan bulat 32-bit untuk menunjukkan offset fungsi dan Anda beralih ke bilangan bulat 64-bit, maka kode yang sudah dikompilasi yang menggunakan perpustakaan itu tidak akan mengakses bidang itu (atau yang mengikutinya) dengan benar . Mengakses anggota struktur data akan dikonversi menjadi alamat dan offset memori selama kompilasi dan jika struktur data berubah,

ABI tidak harus sesuatu yang Anda akan berikan secara eksplisit kecuali Anda melakukan pekerjaan desain sistem tingkat sangat rendah. Ini juga tidak khusus untuk bahasa tertentu, karena (misalnya) aplikasi C dan aplikasi Pascal dapat menggunakan ABI yang sama setelah dikompilasi.

Edit:Mengenai pertanyaan Anda tentang bab-bab tentang format file ELF dalam dokumen SysV ABI: Alasan mengapa informasi ini dimasukkan adalah karena format ELF menentukan antarmuka antara sistem operasi dan aplikasi. Saat Anda memberi tahu OS untuk menjalankan suatu program, ia mengharapkan program diformat dengan cara tertentu dan (misalnya) mengharapkan bagian pertama dari biner untuk menjadi header ELF yang berisi informasi tertentu pada offset memori tertentu. Ini adalah bagaimana aplikasi mengkomunikasikan informasi penting tentang dirinya ke sistem operasi. Jika Anda membangun sebuah program dalam format biner non-ELF (seperti a.out atau PE), maka OS yang mengharapkan aplikasi yang diformat ELF tidak akan dapat menafsirkan file biner atau menjalankan aplikasi.

IIRC, Windows saat ini menggunakan format Portable Executable (atau, PE). Ada tautan di bagian "tautan eksternal" halaman Wikipedia dengan informasi lebih lanjut tentang format PE.

Juga, mengenai catatan Anda tentang susunan nama C ++: Saat menemukan fungsi dalam file perpustakaan, fungsi tersebut biasanya dicari berdasarkan namanya. C ++ memungkinkan Anda untuk membebani nama fungsi, jadi nama saja tidak cukup untuk mengidentifikasi suatu fungsi. Kompiler C ++ memiliki cara mereka sendiri untuk berurusan dengan ini secara internal, yang disebut nama mangling . ABI dapat menentukan cara pengkodean nama fungsi standar sehingga program yang dibangun dengan bahasa atau kompiler yang berbeda dapat menemukan apa yang mereka butuhkan. Saat Anda menggunakan extern "c"dalam program C ++, Anda menginstruksikan kompiler untuk menggunakan cara standar untuk merekam nama yang dapat dimengerti oleh perangkat lunak lain.


2
@ Bta, Terima kasih atas jawaban yang bagus. Apakah panggilan konvensi itu semacam ABI? Terima kasih
camino

37
Jawaban bagus. Tapi ini bukan ABI. ABI adalah seperangkat aturan yang menentukan konvensi pemanggilan, dan aturan untuk menyusun struktur. Pascal meneruskan argumen pada stack dengan urutan terbalik dari aplikasi C, jadi kompilator pascal dan C TIDAK mengkompilasi ke ABI yang sama. Standar masing-masing untuk kompiler C dan Pascal secara implisit memastikan bahwa ini akan menjadi kasusnya. Kompiler C ++ tidak dapat mendefinisikan cara "standar" untuk membuat nama, karena tidak ada cara standar. Konvensi susunan nama C ++ tidak kompatibel antara kompiler C ++ ketika ada kompiler C ++ yang bersaing di Windows.
Robin Davies


1
@RobinDavies: Pada platform di mana kompilator Pascal akan memanggil fungsi pop argumen yang diberikan oleh penelepon mereka, kompiler C umumnya akan mendefinisikan cara-cara yang oleh seorang programmer dapat menunjukkan bahwa fungsi-fungsi tertentu harus digunakan, atau harus diharapkan untuk menggunakan, konvensi pemanggilan yang sama seperti konvensi pemanggilan. Kompilator Pascal meskipun kompiler C umumnya akan secara default menggunakan konvensi di mana fungsi yang disebut meninggalkan apa pun yang diletakkan di sana oleh penelepon mereka.
supercat

Dapatkah saya mengatakan file obj yang dihasilkan oleh kompiler C berisi ABI?
Mitu Raj

144

Jika Anda mengetahui perakitan dan cara kerja di level OS, Anda menyesuaikan diri dengan ABI tertentu. ABI mengatur hal-hal seperti bagaimana parameter dilewatkan, di mana nilai kembali ditempatkan. Untuk banyak platform hanya ada satu ABI untuk dipilih, dan dalam kasus-kasus ABI hanya "cara kerja".

Namun, ABI juga mengatur hal-hal seperti bagaimana kelas / objek diletakkan dalam C ++. Ini diperlukan jika Anda ingin dapat melewatkan referensi objek melintasi batas-batas modul atau jika Anda ingin mencampur kode yang dikompilasi dengan kompiler yang berbeda.

Juga, jika Anda memiliki OS 64-bit yang dapat menjalankan binari 32-bit, Anda akan memiliki ABI yang berbeda untuk kode 32-dan 64-bit.

Secara umum, kode apa pun yang Anda tautkan ke executable yang sama harus sesuai dengan ABI yang sama. Jika Anda ingin berkomunikasi antara kode menggunakan ABI yang berbeda, Anda harus menggunakan beberapa bentuk RPC atau protokol serialisasi.

Saya pikir Anda berusaha terlalu keras untuk memeras berbagai jenis antarmuka menjadi serangkaian karakteristik yang tetap. Sebagai contoh, sebuah antarmuka tidak harus dibagi menjadi konsumen dan produsen. Antarmuka hanyalah konvensi tempat dua entitas berinteraksi.

ABI dapat (sebagian) ISA-agnostik. Beberapa aspek (seperti konvensi pemanggilan) bergantung pada ISA, sementara aspek lainnya (seperti tata letak kelas C ++) tidak.

ABI yang terdefinisi dengan baik sangat penting bagi orang yang menulis kompiler. Tanpa ABI yang terdefinisi dengan baik, tidak mungkin menghasilkan kode yang dapat dioperasikan.

EDIT: Beberapa catatan untuk menjelaskan:

  • "Biner" di ABI tidak mengecualikan penggunaan string atau teks. Jika Anda ingin menautkan DLL yang mengekspor kelas C ++, di suatu tempat di dalamnya metode dan jenis tanda tangan harus dikodekan. Di situlah C ++ nama-mangling masuk
  • Alasan mengapa Anda tidak pernah memberikan ABI adalah bahwa sebagian besar programmer tidak akan pernah melakukannya. ABI disediakan oleh orang yang sama merancang platform (yaitu sistem operasi), dan sangat sedikit programmer yang memiliki hak istimewa untuk merancang ABI yang banyak digunakan.

Saya sama sekali tidak yakin bahwa templat saya salah. Karena setiap tempat templat untuk antarmuka ini benar. Jadi, ya saya ingin saya berharap ABI juga cocok dengan template ini tapi bukan itu. PENTING adalah saya masih tidak mengerti. Saya tidak tahu apakah saya sangat bodoh atau sesuatu yang lain tetapi itu tidak masuk ke kepala saya. Saya tidak dapat mewujudkan jawaban dan artikel wiki.
cakar

2
@ jesperE, "ABI mengatur hal-hal seperti bagaimana parameter dilewatkan, di mana nilai pengembalian ditempatkan." mengacu pada "cdecl, stdcall, fastcall, pascal" benar?
camino

3
Iya. Nama yang tepat adalah "konvensi panggilan", yang merupakan bagian dari ABI. en.wikipedia.org/wiki/X86_calling_conventions
JesperE

4
ini adalah jawaban yang benar dan tepat tanpa verbosity (agak berisik )!
Nawaz

Saya sarankan menulis sedikit pertemuan. Ini akan membantu orang memahami ABI dengan cara yang lebih nyata.
KunYu Tsai

40

Anda sebenarnya tidak membutuhkan ABI sama sekali if--

  • Program Anda tidak memiliki fungsi, dan--
  • Program Anda adalah satu yang dapat dieksekusi yang berjalan sendiri (yaitu sistem tertanam) di mana ia benar-benar berjalan dan tidak perlu berbicara dengan hal lain.

Ringkasan yang terlalu disederhanakan:

API: "Ini semua fungsi yang bisa Anda panggil."

ABI: "Ini adalah bagaimana memanggil suatu fungsi."

ABI adalah seperangkat aturan yang dipatuhi oleh kompiler dan penghubung untuk mengkompilasi program Anda sehingga akan berfungsi dengan baik. ABI mencakup banyak topik:

  • Boleh dibilang bagian terbesar dan terpenting dari ABI adalah standar pemanggilan prosedur yang kadang-kadang dikenal sebagai "konvensi pemanggilan". Konvensi panggilan membakukan bagaimana "fungsi" diterjemahkan ke kode assembly.
  • ABI juga menentukan bagaimana nama fungsi yang diekspos di pustaka harus diwakili sehingga kode lain dapat memanggil pustaka tersebut dan mengetahui argumen apa yang harus diloloskan. Ini disebut "nama mangling".
  • ABI juga menentukan jenis tipe data apa yang dapat digunakan, bagaimana mereka harus disejajarkan, dan perincian tingkat rendah lainnya.

Melihat lebih dalam pada konvensi pemanggilan, yang saya anggap sebagai inti dari ABI:

Mesin itu sendiri tidak memiliki konsep "fungsi". Ketika Anda menulis fungsi dalam bahasa tingkat tinggi seperti c, kompiler menghasilkan garis kode perakitan seperti _MyFunction1:. Ini adalah label , yang pada akhirnya akan diselesaikan menjadi alamat oleh assembler. Label ini menandai "awal" dari "fungsi" Anda dalam kode rakitan. Dalam kode tingkat tinggi, ketika Anda "memanggil" fungsi itu, apa yang sebenarnya Anda lakukan menyebabkan CPU beralih ke alamat label itu dan melanjutkan eksekusi di sana.

Dalam persiapan untuk lompat, kompiler harus melakukan banyak hal penting. Konvensi panggilan seperti daftar periksa yang diikuti oleh kompiler untuk melakukan semua hal ini:

  • Pertama, kompiler menyisipkan sedikit kode rakitan untuk menyimpan alamat saat ini, sehingga ketika "fungsi" Anda selesai, CPU dapat melompat kembali ke tempat yang tepat dan melanjutkan eksekusi.
  • Selanjutnya, kompiler menghasilkan kode assembly untuk meneruskan argumen.
    • Beberapa konvensi pemanggilan mendikte bahwa argumen harus diletakkan di atas tumpukan ( dalam urutan tertentu tentu saja).
    • Konvensi lain menyatakan bahwa argumen harus dimasukkan dalam register tertentu ( tergantung pada jenis data mereka tentu saja).
    • Namun, konvensi lain menyatakan bahwa kombinasi spesifik tumpukan dan register harus digunakan.
  • Tentu saja, jika ada sesuatu yang penting dalam register-register sebelumnya, nilai-nilai itu sekarang ditimpa dan hilang selamanya, sehingga beberapa konvensi pemanggilan dapat menentukan bahwa kompiler harus menyimpan beberapa register tersebut sebelum memasukkan argumen di dalamnya.
  • Sekarang kompiler memasukkan instruksi lompatan memberitahu CPU untuk pergi ke label yang dibuat sebelumnya ( _MyFunction1:). Pada titik ini, Anda dapat menganggap CPU sebagai "dalam" fungsi "Anda.
  • Di akhir fungsi, kompiler menempatkan beberapa kode rakitan yang akan membuat CPU menulis nilai kembali di tempat yang benar. Konvensi panggilan akan menentukan apakah nilai balik harus dimasukkan ke dalam register tertentu (tergantung pada jenisnya), atau pada tumpukan.
  • Sekarang saatnya untuk pembersihan. Konvensi panggilan akan menentukan di mana kompiler menempatkan kode perakitan pembersihan.
    • Beberapa konvensi mengatakan bahwa penelepon harus membersihkan tumpukan. Ini berarti bahwa setelah "fungsi" selesai dan CPU melompat kembali ke tempat sebelumnya, kode berikutnya yang akan dieksekusi adalah kode pembersihan yang sangat spesifik.
    • Konvensi lain mengatakan bahwa beberapa bagian tertentu dari kode pembersihan harus berada di akhir "fungsi" sebelum melompat kembali.

Ada banyak ABI / konvensi panggilan yang berbeda. Beberapa yang utama adalah:

  • Untuk CPU x86 atau x86-64 (lingkungan 32-bit):
    • CDECL
    • STDCALL
    • CEPAT
    • VECTORCALL
    • INI
  • Untuk CPU x86-64 (lingkungan 64-bit):
    • SYSTEMV
    • MSNATIF
    • VECTORCALL
  • Untuk CPU ARM (32-bit)
    • AAPCS
  • Untuk CPU ARM (64-bit)
    • AAPCS64

Ini adalah halaman yang bagus yang benar-benar menunjukkan perbedaan dalam perakitan yang dihasilkan saat mengkompilasi ABI yang berbeda.

Hal lain yang perlu diperhatikan adalah bahwa ABI tidak hanya relevan di dalam modul program Anda yang dapat dieksekusi. Ini juga digunakan oleh tautan untuk memastikan program Anda memanggil fungsi perpustakaan dengan benar. Anda memiliki beberapa pustaka bersama yang berjalan di komputer Anda, dan selama kompiler Anda tahu ABI apa yang mereka gunakan masing-masing, ia dapat memanggil fungsi dari mereka dengan benar tanpa meledakkan tumpukan.

Kompiler Anda memahami cara memanggil fungsi pustaka sangat penting. Pada platform yang dihosting (yaitu, di mana OS memuat program), program Anda bahkan tidak bisa berkedip tanpa melakukan panggilan kernel.


19

Antarmuka biner aplikasi (ABI) mirip dengan API, tetapi fungsinya tidak dapat diakses oleh pemanggil di tingkat kode sumber. Hanya representasi biner yang dapat diakses / tersedia.

ABI dapat didefinisikan pada tingkat arsitektur prosesor atau pada tingkat OS. ABI adalah standar yang harus diikuti oleh fase pembuat kode dari kompiler. Standar ditetapkan baik oleh OS atau oleh prosesor.

Fungsi: Menentukan mekanisme / standar untuk membuat panggilan fungsi terlepas dari bahasa implementasi atau kompiler / penghubung / toolchain tertentu. Berikan mekanisme yang memungkinkan JNI, atau antarmuka Python-C, dll.

Entitas yang ada: Fungsi dalam bentuk kode mesin.

Konsumen: Fungsi lain (termasuk satu dalam bahasa lain, dikompilasi oleh kompiler lain, atau ditautkan oleh tautan lain).


Mengapa ABI ditentukan oleh arsitektur? Mengapa OS yang berbeda pada arsitektur yang sama tidak dapat mendefinisikan ABI yang berbeda?
Andreas Haferburg

10

Fungsionalitas: Seperangkat kontrak yang memengaruhi kompiler, penulis majelis, penghubung, dan sistem operasi. Kontrak menentukan bagaimana fungsi diletakkan, di mana parameter dilewatkan, bagaimana parameter dilewatkan, bagaimana fungsi kembali bekerja. Ini umumnya khusus untuk tuple (arsitektur prosesor, sistem operasi).

Entitas yang ada: tata letak parameter, semantik fungsi, alokasi register. Sebagai contoh, arsitektur ARM memiliki banyak ABI (APCS, EABI, GNU-EABI, tidak peduli banyak kasus sejarah) - menggunakan ABI campuran akan menghasilkan kode Anda hanya tidak berfungsi ketika memanggil melintasi batas.

Konsumen: Kompiler, penulis perakitan, sistem operasi, arsitektur khusus CPU.

Siapa yang butuh detail ini? Kompiler, penulis perakitan, penghubung yang melakukan pembuatan kode (atau persyaratan pelurusan), sistem operasi (penanganan interupsi, antarmuka syscall). Jika Anda melakukan pemrograman perakitan, Anda menyesuaikan diri dengan ABI!

C ++ name mangling adalah kasus khusus - itu adalah masalah linker dan penghubung dinamis yang berpusat - jika nama mangling tidak dibakukan, maka penautan dinamis tidak akan berfungsi. Selanjutnya, ABI C ++ disebut hanya itu, ABI C ++. Ini bukan masalah level tautan, melainkan masalah pembuatan kode. Setelah Anda memiliki biner C ++, tidak mungkin membuatnya kompatibel dengan C ++ ABI lain (nama mangling, penanganan perkecualian) tanpa mengkompilasi ulang dari sumber.

ELF adalah format file untuk penggunaan loader dan tautan dinamis. ELF adalah format wadah untuk kode biner dan data, dan dengan demikian menentukan ABI dari sepotong kode. Saya tidak akan menganggap ELF sebagai ABI dalam arti yang ketat, karena PE executable bukan ABI.

Semua ABI adalah set instruksi khusus. ABM ARM tidak akan masuk akal pada prosesor MSP430 atau x86_64.

Windows memiliki beberapa ABI - misalnya, fastcall dan stdcall adalah dua ABI yang umum digunakan. ABI syscall berbeda lagi.


9

Biarkan saya setidaknya menjawab sebagian dari pertanyaan Anda. Dengan sebuah contoh tentang bagaimana ABI Linux memengaruhi panggilan sistem, dan mengapa itu berguna.

Panggilan sistem adalah cara bagi program userspace untuk menanyakan sesuatu kepada kernel. Ini bekerja dengan meletakkan kode numerik untuk panggilan dan argumen dalam register tertentu dan memicu interupsi. Daripada terjadi pergantian ke kernel dan kernel mencari kode numerik dan argumen, menangani permintaan, menempatkan hasilnya kembali ke register dan memicu peralihan kembali ke ruang pengguna. Ini diperlukan misalnya ketika aplikasi ingin mengalokasikan memori atau membuka file (syscalls "brk" dan "open").

Sekarang syscalls memiliki nama pendek "brk", dll. Dan opcodes yang sesuai, ini didefinisikan dalam file header spesifik sistem. Selama opcode ini tetap sama, Anda dapat menjalankan program userland yang dikompilasi sama dengan kernel yang diperbarui tanpa harus mengkompilasi ulang. Jadi Anda memiliki antarmuka yang digunakan oleh biner yang dikompilasi, karenanya ABI.


4

Untuk memanggil kode di pustaka bersama, atau kode panggilan antara unit kompilasi, file objek harus berisi label untuk panggilan. C ++ menguraikan nama-nama label metode untuk menegakkan penyembunyian data dan memungkinkan metode kelebihan beban. Itulah sebabnya Anda tidak dapat mencampur file dari berbagai kompiler C ++ kecuali mereka secara eksplisit mendukung ABI yang sama.


4

Cara terbaik untuk membedakan antara ABI dan API adalah untuk mengetahui mengapa dan untuk apa ia digunakan:

Untuk x86-64 umumnya ada satu ABI (dan untuk x86 32-bit ada set lain):

http://www.x86-64.org/documentation/abi.pdf

https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/140-x86-64_Function_Calling_Conventions/x86_64.html

http://people.freebsd.org/~obrien/amd64-elf-abi.pdf

Linux + FreeBSD + MacOSX mengikutinya dengan beberapa variasi. Dan Windows x64 memiliki ABI sendiri:

http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/

Mengetahui ABI dan mengasumsikan kompiler lain mengikutinya juga, maka binari secara teoritis tahu bagaimana memanggil satu sama lain (perpustakaan khususnya API) dan melewatkan parameter di atas tumpukan atau dengan register dll. Atau register apa yang akan diubah saat memanggil fungsi dll Pada dasarnya pengetahuan ini akan membantu perangkat lunak untuk berintegrasi satu sama lain. Mengetahui urutan tata letak register / stack saya dapat dengan mudah menyatukan berbagai perangkat lunak yang ditulis dalam rakitan bersama tanpa banyak masalah.

Tetapi API berbeda:

Ini adalah nama fungsi tingkat tinggi, dengan argumen yang ditentukan, sehingga jika bagian-bagian perangkat lunak yang berbeda menggunakan API ini, MUNGKIN dapat saling memanggil satu sama lain. Tetapi persyaratan tambahan dari ABI SAMA harus dipatuhi.

Misalnya, Windows dulunya kompatibel dengan POSIX API:

https://en.wikipedia.org/wiki/Windows_Services_for_UNIX

https://en.wikipedia.org/wiki/POSIX

Dan Linux juga sesuai dengan POSIX. Tetapi binari tidak bisa hanya dipindahkan dan dijalankan segera. Tetapi karena mereka menggunakan NAMES yang sama dalam API yang sesuai dengan POSIX, Anda dapat mengambil perangkat lunak yang sama dalam C, mengkompilasi ulangnya di OS yang berbeda, dan segera menjalankannya.

API dimaksudkan untuk memudahkan integrasi perangkat lunak - tahap pra-kompilasi. Jadi setelah kompilasi, perangkat lunak dapat terlihat sangat berbeda - jika ABI berbeda.

ABI dimaksudkan untuk menentukan integrasi perangkat lunak yang tepat pada tingkat biner / perakitan.


Konvensi panggilan x86-64 Windows tidak menggunakan konvensi panggilan SysV yang digunakan semua OS x86-64 lainnya. Linux / OS X / FreeBSD semuanya memiliki konvensi panggilan yang sama, tetapi mereka tidak membagikan ABI lengkap. ABI OS mencakup nomor panggilan sistem. misal freebsd.org/doc/en_US.ISO8859-1/books/developers-handbook/… mengatakan bahwa itu SYS_execveadalah 11 pada linux 32bit, tetapi 59 pada FreeBSD.
Peter Cordes

terima kasih atas komentar Anda, saya telah memodifikasi komentar saya untuk lebih baik menjawab perbedaan antara ABI dan API.
Peter Teoh

Anda masih kehilangan perbedaan antara konvensi panggilan dan ABI lengkap (panggilan sistem dan semuanya). Anda dapat menjalankan beberapa binari FreeBSD di Linux, karena Linux (kernel) menyediakan lapisan kompatibilitas FreeBSD. Meski begitu, ini terbatas pada binari yang tidak mencoba menggunakan bagian apa pun dari FreeBSD ABI yang tidak disediakan oleh Linux. (mis. panggilan sistem FreeBSD saja). Kompatibel dengan ABI berarti Anda dapat menjalankan biner yang sama di kedua sistem, tidak hanya mereka akan melakukan kompilasi yang sama.
Peter Cordes

"Lapisan kompatibilitas FreeBSD", tidak pernah mendengarnya. Bisakah Anda menunjuk ke kode sumber kernel linux yang relevan? Tetapi yang terjadi malah sebaliknya: freebsd.org/doc/en_US.ISO8859-1/books/handbook/linuxemu.html .
Peter Teoh

Itu bukan sesuatu yang saya gunakan. Saya pikir sesuatu seperti itu ada, tapi mungkin tidak lagi. tldp.org/HOWTO/Linux+FreeBSD-6.html mengatakan tidak terawat, dan howto berasal dari 2000. xD. unix.stackexchange.com/questions/172038/... mengkonfirmasi bahwa itu ditinggalkan dan tidak pernah dilakukan kembali (karena tidak ada yang menginginkannya cukup buruk untuk menyelesaikannya). personality(2)dapat diatur PER_BSD. Saya pikir saya ingat melihat personality(PER_LINUX)di stracekeluaran sepanjang waktu, tetapi 64bit yang modern binari Linux tidak melakukan itu lagi.
Peter Cordes

4

Linux shared library contoh ABI minimal runnable

Dalam konteks perpustakaan bersama, implikasi paling penting dari "memiliki ABI stabil" adalah bahwa Anda tidak perlu mengkompilasi ulang program Anda setelah perpustakaan berubah.

Jadi misalnya:

  • jika Anda menjual perpustakaan bersama, Anda menyimpan pengguna Anda gangguan mengkompilasi ulang segala sesuatu yang tergantung pada perpustakaan Anda untuk setiap rilis baru

  • jika Anda menjual program sumber tertutup yang bergantung pada pustaka bersama yang ada dalam distribusi pengguna, Anda bisa merilis dan menguji lebih sedikit prebuilt jika Anda yakin ABI stabil di seluruh versi tertentu dari OS target.

    Ini khususnya penting dalam kasus pustaka standar C, yang banyak tautannya dengan banyak program di sistem Anda.

Sekarang saya ingin memberikan contoh runnable beton minimal ini.

main.c

#include <assert.h>
#include <stdlib.h>

#include "mylib.h"

int main(void) {
    mylib_mystruct *myobject = mylib_init(1);
    assert(myobject->old_field == 1);
    free(myobject);
    return EXIT_SUCCESS;
}

mylib.c

#include <stdlib.h>

#include "mylib.h"

mylib_mystruct* mylib_init(int old_field) {
    mylib_mystruct *myobject;
    myobject = malloc(sizeof(mylib_mystruct));
    myobject->old_field = old_field;
    return myobject;
}

mylib.h

#ifndef MYLIB_H
#define MYLIB_H

typedef struct {
    int old_field;
} mylib_mystruct;

mylib_mystruct* mylib_init(int old_field);

#endif

Kompilasi dan berjalan dengan baik dengan:

cc='gcc -pedantic-errors -std=c89 -Wall -Wextra'
$cc -fPIC -c -o mylib.o mylib.c
$cc -L . -shared -o libmylib.so mylib.o
$cc -L . -o main.out main.c -lmylib
LD_LIBRARY_PATH=. ./main.out

Sekarang, misalkan untuk v2 perpustakaan, kami ingin menambahkan bidang baru untuk mylib_mystructdipanggil new_field.

Jika kami menambahkan bidang sebelumnya old_fieldseperti pada:

typedef struct {
    int new_field;
    int old_field;
} mylib_mystruct;

dan membangun kembali perpustakaan tetapi tidak main.out, maka pernyataan itu gagal!

Ini karena baris:

myobject->old_field == 1

telah menghasilkan perakitan yang mencoba mengakses yang pertama intdari struct, yang sekarang new_fieldbukan yang diharapkan old_field.

Karenanya perubahan ini mematahkan ABI.

Namun, jika kami tambahkan new_fieldsetelah old_field:

typedef struct {
    int old_field;
    int new_field;
} mylib_mystruct;

kemudian perakitan lama yang dihasilkan masih mengakses yang pertama intdari struct, dan program masih bekerja, karena kami menjaga ABI stabil.

Ini adalah versi yang sepenuhnya otomatis dari contoh ini di GitHub .

Cara lain untuk menjaga ABI ini stabil adalah dengan memperlakukannya mylib_mystructsebagai struct buram , dan hanya mengakses ladangnya melalui metode helpers. Ini membuatnya lebih mudah untuk menjaga ABI stabil, tetapi akan menimbulkan overhead kinerja karena kami akan melakukan lebih banyak panggilan fungsi.

API vs ABI

Dalam contoh sebelumnya, menarik untuk dicatat bahwa menambahkan new_fieldsebelumnya old_field, hanya merusak ABI, tetapi bukan API.

Apa artinya ini, adalah bahwa jika kita telah mengkompilasi ulang main.cprogram kita melawan perpustakaan, itu akan berhasil.

Kami juga akan merusak API jika kami mengubah misalnya tanda tangan fungsi:

mylib_mystruct* mylib_init(int old_field, int new_field);

karena dalam kasus itu, main.cakan berhenti kompilasi sama sekali.

API Semantik vs API Pemrograman

Kami juga dapat mengklasifikasikan perubahan API dalam tipe ketiga: perubahan semantik.

API semantik, biasanya merupakan deskripsi bahasa alami dari apa yang seharusnya dilakukan oleh API, biasanya termasuk dalam dokumentasi API.

Karena itu dimungkinkan untuk memecah API semantik tanpa merusak program itu sendiri.

Sebagai contoh, jika kita telah memodifikasi

myobject->old_field = old_field;

untuk:

myobject->old_field = old_field + 1;

maka ini tidak akan merusak pemrograman API, maupun ABI, tetapi main.cAPI semantik akan rusak.

Ada dua cara untuk memeriksa API kontrak secara terprogram:

  • menguji banyak kasus sudut. Mudah dilakukan, tetapi Anda mungkin selalu melewatkannya.
  • verifikasi formal . Sulit dilakukan, tetapi menghasilkan bukti matematis tentang kebenaran, pada dasarnya menyatukan dokumentasi dan tes menjadi cara yang "dapat diverifikasi" oleh manusia / mesin! Selama tidak ada bug dalam deskripsi formal Anda tentu saja ;-)

    Konsep ini terkait erat dengan formalisasi Matematika itu sendiri: /math/53969/what-does-formal-mean/3297537#3297537

Daftar semua yang merusak C / C ++ perpustakaan bersama ABI

TODO: temukan / buat daftar pamungkas:

Contoh minimal Java runnable

Apa kompatibilitas biner di Jawa?

Diuji di Ubuntu 18.10, GCC 8.2.0.


3

ABI harus konsisten antara penelepon dan callee untuk memastikan bahwa panggilan berhasil. Stack use, register use, end-of-rutin stack pop. Semua ini adalah bagian terpenting dari ABI.


3

Ringkasan

Ada berbagai interpretasi dan pendapat kuat dari layer yang tepat yang mendefinisikan ABI (aplikasi binary interface).

Dalam pandangan saya, ABI adalah konvensi subyektif dari apa yang dianggap sebagai platform / diberikan untuk API tertentu. ABI adalah "sisa" dari konvensi yang "tidak akan berubah" untuk API tertentu atau yang akan ditangani oleh lingkungan runtime: eksekutor, alat, penghubung, kompiler, jvm, dan OS.

Mendefinisikan Antarmuka : ABI, API

Jika Anda ingin menggunakan perpustakaan seperti joda-time, Anda harus mendeklarasikan ketergantungan joda-time-<major>.<minor>.<patch>.jar. Perpustakaan mengikuti praktik terbaik dan menggunakan Versi Semantik . Ini mendefinisikan kompatibilitas API pada tiga tingkatan:

  1. Patch - Anda tidak perlu mengubah sama sekali kode Anda. Perpustakaan hanya memperbaiki beberapa bug.
  2. Kecil - Anda tidak perlu mengubah kode sejak ditambahkan
  3. Utama - Antarmuka (API) berubah dan Anda mungkin perlu mengubah kode Anda.

Agar Anda dapat menggunakan rilis utama baru dari perpustakaan yang sama, banyak konvensi lain yang masih harus dihormati:

  • Bahasa biner yang digunakan untuk perpustakaan (dalam kasus Java versi target JVM yang mendefinisikan bytecode Java)
  • Konvensi panggilan
  • Konvensi JVM
  • Menghubungkan konvensi
  • Konvensi Runtime Semua ini didefinisikan dan dikelola oleh alat yang kami gunakan.

Contohnya

Studi kasus Jawa

Sebagai contoh, Java menstandarkan semua konvensi ini, bukan dalam alat, tetapi dalam spesifikasi JVM formal. Spesifikasi memungkinkan vendor lain untuk menyediakan seperangkat alat yang berbeda yang dapat menampilkan pustaka yang kompatibel.

Java menyediakan dua studi kasus menarik lainnya untuk ABI: Versi Scala dan mesin virtual Dalvik .

Mesin virtual Dalvik memecahkan ABI

VM Dalvik membutuhkan jenis bytecode yang berbeda dari bytecode Java. Perpustakaan Dalvik diperoleh dengan mengkonversi bytecode Java (dengan API yang sama) untuk Dalvik. Dengan cara ini Anda bisa mendapatkan dua versi dari API yang sama: ditentukan oleh yang asli joda-time-1.7.2.jar. Kita bisa memanggilku joda-time-1.7.2.jardan joda-time-1.7.2-dalvik.jar. Mereka menggunakan ABI yang berbeda untuk Java vms standar yang berorientasi pada stack: Oracle, IBM, Java terbuka atau lainnya; dan ABI kedua adalah yang di sekitar Dalvik.

Rilis berturut-turut Scala tidak kompatibel

Scala tidak memiliki kompatibilitas biner antara versi minor Scala: 2.X. Untuk alasan ini API yang sama "io.reactivex" %% "rxscala"% "0.26.5" memiliki tiga versi (di masa mendatang lebih banyak): untuk Scala 2.10, 2.11 dan 2.12. Apa yang diubah? Saya tidak tahu untuk saat ini , tetapi binari tidak kompatibel. Mungkin versi terbaru menambahkan hal-hal yang membuat perpustakaan tidak dapat digunakan di mesin virtual lama, mungkin hal-hal yang berkaitan dengan menghubungkan / memberi nama / konvensi parameter.

Rilis berturut-turut Java tidak kompatibel

Java juga memiliki masalah dengan rilis utama JVM: 4,5,6,7,8,9. Mereka hanya menawarkan kompatibilitas ke belakang. Jvm9 tahu bagaimana menjalankan kode yang dikompilasi / ditargetkan ( -targetopsi javac ) untuk semua versi lain, sementara JVM 4 tidak tahu bagaimana menjalankan kode yang ditargetkan untuk JVM 5. Semua ini sementara Anda memiliki satu joda-library. Ketidakcocokan ini terbang di bawah radar berkat solusi yang berbeda:

  1. Versi semantik: ketika perpustakaan menargetkan JVM lebih tinggi, mereka biasanya mengubah versi utama.
  2. Gunakan JVM 4 sebagai ABI, dan Anda aman.
  3. Java 9 menambahkan spesifikasi tentang bagaimana Anda bisa memasukkan bytecode untuk JVM bertarget spesifik di perpustakaan yang sama.

Mengapa saya mulai dengan definisi API?

API dan ABI hanyalah konvensi tentang bagaimana Anda mendefinisikan kompatibilitas. Lapisan bawah bersifat umum sehubungan dengan semantik tingkat tinggi. Itu sebabnya mudah untuk membuat beberapa konvensi. Jenis konvensi pertama adalah tentang penyelarasan memori, pengkodean byte, konvensi pemanggilan, pengkodean endian besar dan kecil, dll. Di atasnya Anda mendapatkan konvensi yang dapat dieksekusi seperti yang dijelaskan, menghubungkan konvensi, kode byte menengah seperti yang digunakan oleh Java atau LLVM IR digunakan oleh GCC. Ketiga Anda mendapatkan konvensi tentang cara menemukan perpustakaan, cara memuatnya (lihat Java classloaders). Ketika Anda semakin tinggi dan semakin tinggi dalam konsep Anda memiliki konvensi baru yang Anda anggap sebagai yang diberikan. Itu sebabnya mereka tidak berhasil sampai ke versi semantik . Mereka tersirat atau runtuh dalamVersi: kapan. Kita dapat mengubah versi semantik dengan <major>-<minor>-<patch>-<platform/ABI>. Ini adalah apa yang sebenarnya terjadi sudah: Platform sudah merupakan rpm, dll, jar(JVM bytecode), war(JVM + web server), apk, 2.11(khusus Scala versi) dan sebagainya. Ketika Anda mengatakan APK, Anda sudah membicarakan bagian ABI tertentu dari API Anda.

API dapat porting ke ABI yang berbeda

Level teratas dari abstraksi (sumber yang ditulis dengan API tertinggi dapat dikompilasi ulang / porting ke abstraksi level bawah lainnya.

Katakanlah saya memiliki beberapa sumber untuk rxscala. Jika alat Scala diubah, saya dapat mengkompilasi ulang untuk itu. Jika perubahan JVM saya bisa memiliki konversi otomatis dari mesin lama ke yang baru tanpa mengganggu konsep tingkat tinggi. Sementara porting mungkin sulit akan membantu klien lain. Jika sistem operasi baru dibuat menggunakan kode assembler yang sama sekali berbeda, penerjemah dapat dibuat.

API porting lintas bahasa

Ada API yang porting dalam berbagai bahasa seperti aliran reaktif . Secara umum mereka mendefinisikan pemetaan untuk bahasa / platform tertentu. Saya berpendapat bahwa API adalah spesifikasi utama yang secara formal didefinisikan dalam bahasa manusia atau bahkan bahasa pemrograman tertentu. Semua "pemetaan" lainnya adalah ABI dalam arti tertentu, selain API lebih dari ABI biasa. Hal yang sama terjadi dengan antarmuka REST.


1

Singkatnya dan dalam filosofi, hanya hal-hal sejenis yang dapat berjalan dengan baik, dan ABI dapat dilihat sebagai jenis perangkat lunak yang bekerja bersama.


1

Saya juga berusaha memahami jawaban ABI dan JesperE yang sangat membantu.

Dari perspektif yang sangat sederhana, kita dapat mencoba memahami ABI dengan mempertimbangkan kompatibilitas biner.

KDE wiki mendefinisikan perpustakaan sebagai biner yang kompatibel "jika sebuah program yang terhubung secara dinamis ke versi perpustakaan sebelumnya terus berjalan dengan versi perpustakaan yang lebih baru tanpa perlu mengkompilasi ulang." Untuk lebih lanjut tentang tautan dinamis, lihat Menghubungkan statis vs menghubungkan dinamis

Sekarang, mari kita coba untuk melihat hanya aspek paling mendasar yang diperlukan untuk sebuah perpustakaan menjadi kompatibilitas biner (dengan asumsi tidak ada perubahan kode sumber ke perpustakaan):

  1. Arsitektur set instruksi yang kompatibel / terbelakang (instruksi prosesor, struktur file register, pengaturan tumpukan, tipe akses memori, bersama dengan ukuran, tata letak, dan penyelarasan tipe data dasar yang dapat diakses langsung oleh prosesor)
  2. Konvensi panggilan yang sama
  3. Konvensi mangling nama yang sama (ini mungkin diperlukan jika mengatakan program Fortran perlu memanggil beberapa fungsi perpustakaan C ++).

Tentu, ada banyak detail lain tetapi ini sebagian besar juga mencakup ABI.

Lebih khusus untuk menjawab pertanyaan Anda, dari yang di atas, kami dapat menyimpulkan:

Fungsi ABI: kompatibilitas biner

entitas yang ada: program / perpustakaan / OS yang ada

konsumen: perpustakaan, OS

Semoga ini membantu!


1

Antarmuka biner aplikasi (ABI)

Kegunaan:

  • Terjemahan dari model programmer ke tipe data domain sistem yang mendasarinya, ukuran, pelurusan, konvensi pemanggilan, yang mengontrol bagaimana argumen fungsi dilewatkan dan mengembalikan nilai yang diambil; nomor panggilan sistem dan bagaimana aplikasi harus membuat panggilan sistem ke sistem operasi; skema penyusunan nama kompiler bahasa tingkat tinggi, propagasi pengecualian, dan konvensi pemanggilan antar kompiler pada platform yang sama, tetapi tidak memerlukan kompatibilitas lintas-platform ...

Entitas yang ada:

  • Blok logis yang secara langsung berpartisipasi dalam pelaksanaan program: ALU, register tujuan umum, register untuk memori / I / O pemetaan I / O, dll ...

konsumen:

  • Tautan pengolah bahasa, assembler ...

Ini diperlukan oleh siapa pun yang harus memastikan bahwa membangun rantai alat bekerja secara keseluruhan. Jika Anda menulis satu modul dalam bahasa assembly, yang lain dengan Python, dan bukannya boot-loader Anda sendiri ingin menggunakan sistem operasi, maka modul "aplikasi" Anda bekerja melintasi batas "biner" dan memerlukan persetujuan "antarmuka" seperti itu.

C ++ nama mangling karena file objek dari berbagai bahasa tingkat tinggi mungkin diperlukan untuk ditautkan dalam aplikasi Anda. Pertimbangkan untuk menggunakan pustaka standar GCC membuat panggilan sistem ke Windows yang dibangun dengan Visual C ++.

ELF adalah salah satu harapan yang mungkin dari tautan dari file objek untuk interpretasi, meskipun JVM mungkin memiliki beberapa ide lain.

Untuk aplikasi Windows RT Store, coba cari ARM ABI jika Anda benar-benar ingin membuat beberapa rantai alat bekerja bersama.


1

Istilah ABI digunakan untuk merujuk pada dua konsep yang berbeda tetapi terkait.

Ketika berbicara tentang kompiler itu merujuk pada aturan yang digunakan untuk menerjemahkan dari konstruksi level sumber ke konstruksi biner. Seberapa besar tipe datanya? bagaimana cara kerja tumpukan? bagaimana cara meneruskan parameter ke fungsi? register mana yang harus disimpan oleh penelepon vs callee?

Ketika berbicara tentang perpustakaan itu merujuk ke antarmuka biner yang disajikan oleh perpustakaan yang dikompilasi. Antarmuka ini adalah hasil dari sejumlah faktor termasuk kode sumber perpustakaan, aturan yang digunakan oleh kompiler dan dalam beberapa kasus definisi diambil dari perpustakaan lain.

Perubahan pada pustaka dapat mematahkan ABI tanpa merusak API. Pertimbangkan misalnya perpustakaan dengan antarmuka seperti.

void initfoo(FOO * foo)
int usefoo(FOO * foo, int bar)
void cleanupfoo(FOO * foo)

dan pemrogram aplikasi menulis kode seperti

int dostuffwithfoo(int bar) {
  FOO foo;
  initfoo(&foo);
  int result = usefoo(&foo,bar)
  cleanupfoo(&foo);
  return result;
}

Pemrogram aplikasi tidak peduli tentang ukuran atau tata letak FOO, tetapi aplikasi biner berakhir dengan ukuran hard disk yang dikodekan. Jika pemrogram perpustakaan menambahkan bidang tambahan ke foo dan seseorang menggunakan perpustakaan biner baru dengan aplikasi biner lama maka perpustakaan dapat membuat dari batas akses memori.

OTOH jika pembuat perpustakaan telah mendesain API seperti mereka.

FOO * newfoo(void)
int usefoo(FOO * foo, int bar)
void deletefoo((FOO * foo, int bar))

dan pemrogram aplikasi menulis kode seperti

int dostuffwithfoo(int bar) {
  FOO * foo;
  foo = newfoo();
  int result = usefoo(foo,bar)
  deletefoo(foo);
  return result;
}

Maka aplikasi biner tidak perlu tahu apa-apa tentang struktur FOO, yang semuanya bisa disembunyikan di dalam perpustakaan. Harga yang Anda bayar untuk itu adalah bahwa operasi tumpukan terlibat.


0

ABI- Application Binary Interfaceadalah tentang komunikasi kode mesin dalam runtime antara dua bagian program biner seperti - aplikasi, pustaka, OS ... ABImenjelaskan bagaimana benda disimpan dalam memori dan bagaimana fungsinya disebut ( calling convention)

Contoh API dan ABI yang bagus adalah ekosistem iOS dengan bahasa Swift .

  • Application- Saat Anda membuat aplikasi menggunakan berbagai bahasa. Misalnya Anda dapat membuat aplikasi menggunakan Swiftdan Objective-C[Mixing Swift and Objective-C]

  • Application - OS- runtime - Swift runtimedan standard librariesmerupakan bagian dari OS dan tidak boleh dimasukkan ke dalam setiap bundel (misalnya aplikasi, kerangka kerja). Ini sama seperti penggunaan Objective-C

  • Library- Module Stabilitycase - waktu kompilasi - Anda akan dapat mengimpor framework yang dibangun dengan versi lain dari kompiler Swift. Ini berarti aman untuk membuat biner sumber tertutup (pra-bangun) yang akan dikonsumsi oleh versi kompiler yang berbeda ( .swiftinterfacedigunakan bersama .swiftmodule) dan Anda tidak akan mendapatkan

    Module compiled with _ cannot be imported by the _ compiler
    
  • Library- Library Evolutionkasing

    1. Kompilasi waktu - jika ketergantungan diubah, klien tidak harus dikompilasi ulang.
    2. Runtime - pustaka sistem atau kerangka kerja dinamis dapat ditukar dengan yang baru.

[API vs ABI]

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.