Co to jest interfejs binarny aplikacji (ABI)?

Nigdy nie rozumiałem, czym jest ABI. Proszę nie wskazywać mi artykułu na Wikipedii. Gdybym mógł to zrozumieć, nie byłoby mnie tutaj, publikując tak długi post.

Oto mój sposób myślenia o różnych interfejsach:

[14]}pilot TV jest interfejsem między Użytkownikiem a telewizorem. Jest to istniejący byt, ale bezużyteczny (nie zapewnia żadnej funkcjonalności) sam w sobie. Cała funkcjonalność każdego z tych przycisków na pilocie jest zaimplementowana w telewizorze gotowi.

Interface: jest to warstwa "istniejącego bytu" pomiędzy functionality i consumer tego funkcjonalność. Interfejs sam w sobie to nic nie robi. To po prostu wywołuje funkcjonalność z tyłu.

Teraz zależy kto tam jest użytkownikiem są różne rodzaje interfejsów.

Command Line Interface (CLI) polecenia są istniejącymi encjami, konsumentem jest użytkownik i funkcjonalność leży w tyle.

functionality: moje oprogramowanie funkcjonalność, która rozwiązuje niektóre cel, do którego opisujemy ten interfejs.

existing entities: komendy

consumer: user

Graficzny interfejs użytkownika (GUI) okno, przyciski itp. czy istniejące podmioty, i znowu konsument jest użytkownikiem a funkcjonalność leży w tyle.

functionality: moje oprogramowanie funkcjonalność, która rozwiązuje niektóre cel, do którego opisujemy ten interfejs.

existing entities: okno, przyciski itd..

consumer: user

Application Programming Interface (API) functions or to be bardziej poprawne, interfejsy (w programowanie oparte na interfejsach) są istniejących podmiotów, konsument tutaj jest kolejny program nie jest użytkownikiem i znowu za tą warstwą kryje się funkcjonalność.

functionality: moje oprogramowanie funkcjonalność, która rozwiązuje niektóre cel, do którego opisujemy ten interfejs.

existing entities: Funkcje, Interfejsy (tablica funkcji).

consumer: inny program/aplikacja.

Application Binary Interface (ABI) tutaj zaczyna się mój problem.

functionality: ???

existing entities: ???

consumer: ???

  • pisałem oprogramowanie w różnych językach i dostarczałem różnego rodzaju interfejsy( CLI, GUI i API), ale nie jestem pewien, czy kiedykolwiek dostarczyłem jakieś ABI.

Wikipedia says:

Abis Pokrywa szczegóły, takie jak

  • typ danych, rozmiar i wyrównanie;
  • konwencja wywołująca, która kontroluje sposób, w jaki argumenty funkcji są przekazywane i zwracane wartości;
  • numery wywołań systemowych i jak aplikacja powinna wykonywać połączenia systemowe do systemu operacyjnego;

Inne ABIs standaryzują szczegóły, takie jak

  • nazwa C++,
  • rozmnażanie WYJĄTKÓW, oraz
  • wywołanie konwencji pomiędzy kompilatorami na tej samej platformie, ale czy nie wymaga cross-platform kompatybilność.
  • Komu potrzebne są te szczegóły? Proszę, nie mów o OS. Znam się na programowaniu. Wiem, jak działa łączenie i ładowanie. Wiem, co dokładnie dzieje się w środku.

  • Dlaczego pojawiła się nazwa C++ mangling? Myślałem, że mówimy na poziomie binarnym. Dlaczego przychodzą języki?

W każdym razie, mam Pobierz [PDF] System V Application Binary Interface Edition 4.1 (1997-03-18) aby zobaczyć, co dokładnie zawiera. Większość nie miała sensu.

  • Dlaczego zawiera dwa rozdziały (4 i 5) opisujące format pliku ELF ? W rzeczywistości są to jedyne dwa znaczące rozdziały tej specyfikacji. Pozostałe rozdziały są "specyficzne dla procesora". W każdym razie myślałem, że to zupełnie inny temat. Proszę. nie mów, że specyfikacja formatu pliku ELF to ABI. Nie kwalifikuje się do interfejsu zgodnie z definicją.

  • Wiem, że skoro mówimy na tak niskim poziomie, musi to być bardzo konkretne. Ale nie jestem pewien, jak to jest" instruction set architecture (Isa) " specyficzne?

  • Gdzie mogę znaleźć ABI Microsoft Windows?

Więc to są najważniejsze pytania, które mnie dręczą.

Author: Peter Mortensen, 2010-01-31

14 answers

Jednym z łatwych sposobów na zrozumienie "ABI" jest porównanie go do"API".

Jesteś już zaznajomiony z koncepcją API. Jeśli chcesz korzystać z funkcji, powiedzmy, jakiejś biblioteki lub systemu operacyjnego, użyjesz interfejsu API. API składa się z typów danych/struktur, stałych, funkcji itp., które można wykorzystać w kodzie, aby uzyskać dostęp do funkcjonalności tego zewnętrznego komponentu.

ABI jest bardzo podobny. Pomyśl o tym jak o skompilowanej wersji API (lub jak o API w języku maszynowym poziom). Kiedy piszesz kod źródłowy, uzyskujesz dostęp do biblioteki za pośrednictwem interfejsu API. Po skompilowaniu kodu aplikacja uzyskuje dostęp do danych binarnych w bibliotece za pośrednictwem ABI. ABI definiuje struktury i metody, których skompilowana aplikacja będzie używać do uzyskiwania dostępu do zewnętrznej biblioteki (tak jak API), tylko na niższym poziomie.

ABIs są ważne, jeśli chodzi o aplikacje korzystające z zewnętrznych bibliotek. Jeśli program jest zbudowany do korzystania z określonej biblioteki i tej biblioteki jest później aktualizowany, nie chcesz ponownie skompilować tej aplikacji (i z punktu widzenia użytkownika końcowego, możesz nie mieć źródła). Jeśli zaktualizowana biblioteka używa tego samego ABI, Twój program nie będzie musiał się zmieniać. Interfejs do biblioteki (który jest wszystkim, na czym naprawdę zależy twojemu programowi) jest taki sam, mimo że wewnętrzne działanie mogło się zmienić. Dwie wersje biblioteki, które mają ten sam ABI, są czasami nazywane "kompatybilnymi binarnie", ponieważ mają ten sam niski poziom interfejs (powinieneś być w stanie wymienić starą wersję na nową i nie mieć większych problemów).

Czasami zmiany ABI są nieuniknione. Gdy tak się stanie, wszelkie programy korzystające z tej biblioteki nie będą działać, chyba że zostaną ponownie skompilowane w celu użycia nowej wersji biblioteki. Jeśli ABI zmienia się, ale API Nie, wtedy stare i nowe wersje bibliotek są czasami nazywane "kompatybilnymi źródłami". Oznacza to, że podczas gdy program skompilowany dla jednej wersji biblioteki nie będzie działał w przypadku drugiego, kod źródłowy napisany dla jednego będzie działał dla drugiego, jeśli zostanie ponownie skompilowany.

Z tego powodu autorzy bibliotek starają się utrzymać stabilność ABI (aby zminimalizować zakłócenia). Utrzymanie stabilności ABI oznacza brak zmiany interfejsów funkcji (typ i liczba zwracanych danych, typy i kolejność argumentów), definicji typów danych lub struktur danych, zdefiniowanych stałych itp. Można dodawać nowe funkcje i typy danych, ale istniejące muszą pozostać takie same. Jeśli rozszerzysz, powiedzmy, 16-bitowe dane pole structure do 32-bitowego pola, wtedy już skompilowany kod, który używa tej struktury danych, nie będzie miał poprawnego dostępu do tego pola (lub żadnego podążającego za nim). Dostęp do elementów struktury danych jest konwertowany na adresy pamięci i przesunięcia podczas kompilacji, a jeśli struktura danych się zmieni, przesunięcia te nie będą wskazywać na to, czego oczekuje kod, a wyniki są nieprzewidywalne w najlepszym wypadku.

ABI niekoniecznie jest czymś, co wyraźnie podasz chyba, że oczekujesz, że ludzie połączą się z Twoim kodem za pomocą assembly. Nie jest to również specyficzne dla języka, ponieważ (na przykład) aplikacja C i aplikacja Pascal będą używać tego samego ABI po ich skompilowaniu.

Edit: jeśli chodzi o twoje pytanie dotyczące rozdziałów dotyczących formatu pliku ELF w SysV ABI docs: powodem, dla którego te informacje są zawarte, jest fakt, że format ELF definiuje interfejs między systemem operacyjnym a aplikacją. Kiedy powiesz OS aby uruchomić program, oczekuje, że program zostanie sformatowany w określony sposób i (na przykład) oczekuje, że pierwsza sekcja binarna będzie nagłówkiem ELF zawierającym pewne informacje przy określonych przesunięciach pamięci. W ten sposób aplikacja przekazuje systemowi operacyjnemu ważne informacje o sobie. Jeśli zbudujesz program w formacie binarnym innym niż Elf (takim jak.out lub PE), system operacyjny, który oczekuje aplikacji sformatowanych w ELF, nie będzie w stanie zinterpretować pliku binarnego lub uruchomić podanie. Jest to jeden wielki powód, dla którego aplikacje systemu Windows nie mogą być uruchamiane bezpośrednio na komputerze z Linuksem (lub odwrotnie) bez ponownego skompilowania lub uruchomienia w jakiejś warstwie emulacyjnej, która może przetłumaczyć z jednego formatu binarnego na inny.

IIRC, Windows obecnie używa formatu Portable Executable (or, PE). W sekcji "Linki zewnętrzne" tej strony Wikipedii znajdują się linki zawierające więcej informacji na temat formatu PE.

Również odnośnie Twojej notki o C++ mangling nazw: ABI może zdefiniować "ustandaryzowany" sposób, w jaki kompilator C++ wykonuje mangling nazw dla celów zgodności. Oznacza to, że jeśli stworzę bibliotekę, a Ty stworzysz program, który jej używa, powinieneś być w stanie użyć innego kompilatora niż ja I nie musisz się martwić o to, że wynikowe binaria są niekompatybilne z powodu różnych schematów manipulowania nazwami. Jest to przydatne tylko wtedy, gdy definiujesz nowy format pliku binarnego lub piszesz kompilator lub linker.

 362
Author: bta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-05 14:42:26

Jeśli znasz assembly i jak to działa na poziomie systemu operacyjnego, jesteś zgodny z pewnym ABI. ABI reguluje takie rzeczy jak sposób przekazywania parametrów, gdzie umieszczane są zwracane wartości. Dla wielu platform jest tylko jeden ABI do wyboru, a w tych przypadkach ABI jest po prostu "jak wszystko działa".

Jednak ABI reguluje również takie rzeczy jak sposób, w jaki klasy/obiekty są rozmieszczone w C++. Jest to konieczne, jeśli chcesz mieć możliwość przekazywania odniesień do obiektów ponad granicami modułów lub jeśli chcesz mieszać kod skompilowany z różnymi kompilatorami.

Ponadto, jeśli masz 64-bitowy system operacyjny, który może wykonywać 32-bitowe binaria, będziesz miał różne ABIs dla 32-i 64-bitowego kodu.

Ogólnie, każdy kod linkujący do tego samego pliku wykonywalnego musi być zgodny z tym samym ABI. Jeśli chcesz komunikować się między kodami za pomocą różnych ABIs, musisz użyć jakiejś formy RPC lub protokołów serializacji.

Myślę, że za bardzo starasz się wcisnąć różne typy interfejsów do stałej zestaw cech. Na przykład interfejs niekoniecznie musi być podzielony na konsumentów i producentów. Interfejs jest po prostu konwencją, w której dwa byty wchodzą w interakcję.

ABIs może być (częściowo) ISA-agnostyczny. Niektóre aspekty (takie jak wywołanie konwencji) zależą od ISA, podczas gdy inne aspekty (takie jak układ klas C++) nie.

Dobrze zdefiniowany ABI jest bardzo ważny dla osób piszących Kompilatory. Bez dobrze zdefiniowanego ABI nie da się wygenerować kod interoperacyjny.

EDIT: kilka uwag do wyjaśnienia:

  • "Binary" w ABI nie wyklucza użycia łańcuchów lub tekstu. Jeśli chcesz połączyć bibliotekę DLL eksportującą klasę C++, gdzieś w niej muszą być zakodowane metody i podpisy typów. To jest miejsce, gdzie c++ NAZWA-mangling przychodzi.
  • powodem, dla którego nigdy nie podałeś ABI jest to, że zdecydowana większość programistów nigdy tego nie zrobi. ABIs są dostarczane przez te same osoby projektujące platformę (tj. system operacyjny), a bardzo niewielu programistów będzie miało kiedykolwiek przywilej zaprojektowania szeroko używanego ABI.
 97
Author: JesperE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-27 15:11:18

Application binary interface (ABI) jest podobny do API, ale funkcja nie jest dostępna dla wywołującego na poziomie kodu źródłowego. Tylko reprezentacja binarna jest dostępna / dostępna.

ABIs może być zdefiniowany na poziomie architektury procesora lub na poziomie systemu operacyjnego. ABIs są standardami, które mają być przestrzegane przez fazę generatora kodu kompilatora. Standard jest ustalany przez system operacyjny lub przez procesor.

Funkcjonalność: Zdefiniuj mechanizm / standard, aby funkcja wywołania niezależne od języka implementacji lub określonego kompilatora / linkera / toolchaina. Podaj mechanizm, który pozwala na JNI, lub interfejs Python-C, itp.

Istniejące encje: funkcje w postaci kodu maszynowego.

Consumer: inna funkcja( w tym jedna w innym języku, skompilowana przez inny kompilator lub połączona przez inny linker).

 16
Author: alvin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-15 23:31:42

W rzeczywistości nie potrzebujesz w ogóle ABI, Jeśli --

  • twój program nie ma funkcji i--
  • twój program jest pojedynczym programem wykonywalnym, który działa sam (np. system wbudowany), gdzie jest dosłownie jedyną uruchomioną rzeczą i nie musi rozmawiać z niczym innym.

Uproszczone podsumowanie:

API: "Oto wszystkie funkcje, które możesz wywołać."

ABI: "to jest Jak wywołać funkcję."

ABI to zbiór reguł, których przestrzegają kompilatory i linkery, aby skompilować Twój program tak, aby działał poprawnie. ABIs obejmuje wiele tematów:

  • prawdopodobnie największą i najważniejszą częścią ABI jest standard wywołania procedury czasami znany jako "konwencja wywołania". Wywołanie konwencji standaryzuje sposób tłumaczenia "funkcji" na kod asemblera.
  • ABIs również dyktować, jak nazwy ujawnionych funkcji w bibliotekach powinny być reprezentowane tak, aby inny kod mógł wywoływać te biblioteki i wiedzieć, jakie argumenty powinny być przekazywane. To się nazywa "wymachiwanie imieniem".
  • ABIs określa również, jakiego rodzaju typy danych mogą być używane, jak muszą być wyrównane i inne szczegóły niskiego poziomu.
[[2]} głębsze spojrzenie na konwencję wywołania, która uważam za rdzeń ABI: Maszyna sama w sobie nie ma pojęcia "funkcji". Kiedy piszesz a funkcja w języku wysokiego poziomu, takim jak c, kompilator generuje linię kodu asemblera, taką jak _MyFunction1:. Jest to etykieta , która ostatecznie zostanie rozwiązana na adres przez asembler. Ta etykieta oznacza " początek "twojej" funkcji " w kodzie złożenia. W kodzie wysokiego poziomu, kiedy "wywołujesz" tę funkcję, to co tak naprawdę robisz powoduje, że procesor przeskakuje na adres tej etykiety i kontynuuje jej wykonywanie.

W przygotowaniu do skoku kompilator musi robić wiele ważnych rzeczy. Konwencja wywołania jest jak lista kontrolna, którą stosuje kompilator, aby zrobić to wszystko:

  • Po pierwsze, kompilator wstawia trochę kodu asemblera, aby zapisać bieżący adres, tak aby po zakończeniu "funkcji" CPU mógł wrócić do właściwego miejsca i kontynuować wykonywanie.
  • Następnie kompilator generuje kod asemblera przekazujący argumenty.
    • niektóre konwencje wywołujące nakazują umieszczanie argumentów na stosie (w określonej kolejności oczywiście).
    • inne konwencje nakazują umieszczanie argumentów w poszczególnych rejestrach ( Oczywiście w zależności od ich typów danych ).
    • jeszcze inne konwencje nakazują użycie określonej kombinacji stosu i rejestrów.
  • oczywiście, jeśli wcześniej było coś ważnego w tych rejestrach, wartości te są teraz nadpisywane i tracone na zawsze, więc niektóre konwencje wywołujące mogą dyktować, że kompilator powinien zapisać niektóre z tych rejestrów przed umieszczeniem w nich argumentów.
  • teraz kompilator wstawia instrukcję skoku mówiącą procesorowi, aby udał się do tej etykiety, którą wykonał wcześniej (_MyFunction1:). W tym momencie możesz uznać PROCESOR za " w "swojej " funkcji".
  • na końcu funkcji kompilator umieszcza kod złożenia, który sprawi, że procesor napisze zwracaną wartość we właściwym miejscu. Konwencja wywołująca będzie dyktować, czy wartość zwracana powinna być umieszczona w konkretnego rejestru (w zależności od jego typu), lub na stosie.
  • Teraz czas na sprzątanie. Konwencja wywołująca będzie określać, gdzie kompilator umieszcza kod assembly cleanup.
    • niektóre konwencje mówią, że rozmówca musi oczyścić stos. Oznacza to, że po zakończeniu "funkcji", a procesor wskakuje z powrotem do miejsca, w którym była wcześniej, następny kod do wykonania powinien być jakimś bardzo specyficznym kodem oczyszczającym.
    • inne konwencje mówią, że niektóre szczególne części kod czyszczenia powinien znajdować się na końcu "funkcji" przed skokiem do tyłu.

Istnieje wiele różnych konwencji ABIs / wywołujących. Niektóre główne to:

  • dla procesora x86 lub x86-64 (środowisko 32-bitowe):
    • CDECL
    • STDCALL
    • FASTCALL
    • VECTORCALL
    • THISCALL
  • dla procesora x86-64 (64-bit środowisko):
    • SYSTEMV
    • MSNATIVE
    • VECTORCALL
  • dla procesora ARM (32-bit)
    • AAPCS
  • dla procesora ARM (64-bit)
    • AAPCS64

Tutaj {[37] } jest świetna strona, która faktycznie pokazuje różnice w zestawieniu generowanym podczas kompilacji dla różnych ABIs.

Kolejną rzeczą, o której warto wspomnieć, jest to, że ABI jest nie tylko istotne wewnątrz modułu wykonywalnego Twojego programu. On również używany przez linkera, aby upewnić się, że program poprawnie wywołuje funkcje biblioteki. Na twoim komputerze działa wiele bibliotek współdzielonych i tak długo, jak Twój kompilator wie, jakiego ABI używają, może poprawnie wywoływać z nich funkcje bez wysadzania stosu.

Zrozumienie przez kompilator jak wywoływać funkcje biblioteczne jest niezwykle Ważne. Na platformie hostowanej (czyli takiej, na której system operacyjny ładuje programy) Twój program nie może nawet migać bez wywołanie jądra.

 14
Author: Lakey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-30 20:40:46

Funkcjonalność: zestaw umów, które wpływają na kompilator, autorów zestawów, łącznik i system operacyjny. Kontrakty określają, w jaki sposób funkcje są rozmieszczone, gdzie przekazywane są parametry, jak przekazywane są parametry, jak działają zwroty funkcji. Są one zazwyczaj specyficzne dla krotki (architektura procesora, system operacyjny).

Istniejące encje: układ parametrów, semantyka funkcji, alokacja rejestru. Na przykład architektura ARM ma liczne ABIs( APCS, EABI, GNU-EABI, not mind a bunch of historical cases) - użycie mieszanego ABI spowoduje, że Twój kod po prostu nie będzie działał podczas wywoływania ponad granicami.

Konsument: kompilator, autorzy zestawów, system operacyjny, Architektura specyficzna dla procesora.

Komu potrzebne te szczegóły? Kompilator, autorzy asemblerów, linkery wykonujące generowanie kodu (lub wymagania wyrównania), system operacyjny (obsługa przerwań, interfejs syscall). Jeśli programowałeś assembly, byłeś zgodny z ABI!

C++ name mangling jest szczególnym przypadkiem-problem związany z linkerem i dynamicznym linkerem-jeśli name mangling nie jest ustandaryzowany, dynamiczne linkowanie nie będzie działać. Odtąd C++ ABI nazywa się właśnie tym, C++ ABI. Nie jest to problem z poziomem linkera, ale problem z generowaniem kodu. Gdy masz binarny C++, nie jest możliwe, aby był kompatybilny z innym C++ ABI (manipulowanie nazwami, obsługa wyjątków) bez rekompilacji ze źródła.

ELF jest formatem pliku dla zastosowanie Ładowarki i łącznika dynamicznego. ELF jest formatem kontenera dla kodu binarnego i danych i jako taki określa ABI kawałka kodu. Nie uważałbym elfa za ABI w ścisłym tego słowa znaczeniu, gdyż PE nie jest ABI.

Wszystkie ABIs są specyficzne dla zestawu instrukcji. ARM ABI nie będzie miał sensu na procesorze MSP430 lub x86_64.

Windows ma kilka ABIs - na przykład fastcall i stdcall to dwa popularne ABIs. Syscall ABI znowu jest inny.

 9
Author: Yann Ramin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-23 06:26:25

Pozwól, że chociaż odpowiem na część twojego pytania. Z przykĹ 'adem jak Linux ABI wpĹ' ywa na systemcalls i dlaczego jest to przydatne.

Systemcall jest sposobem, aby program z przestrzeni użytkownika poprosił o coś przestrzeń jądra. Jego działanie polega na umieszczeniu kodu numerycznego wywołania i argumentu w określonym rejestrze i wywołaniu przerwania. Następnie następuje przełączenie na kernelspace i jądro wyszukuje kod numeryczny, a argument, obsługuje żądanie, umieszcza wynik z powrotem w rejestr i uruchamia przełącznik z powrotem do przestrzeni użytkownika. Jest to potrzebne na przykład, gdy aplikacja chce przydzielić pamięć lub otworzyć plik (syscalls "brk" i "open").

Teraz syscalls mają krótkie nazwy "brk", itp. i odpowiadające im kody opcodes, są one zdefiniowane w pliku nagłówkowym specyficznym dla systemu. Tak długo, jak te opcje pozostają takie same, możesz uruchamiać te same skompilowane programy z różnymi zaktualizowanymi jądrami bez konieczności rekompilacji. Więc masz interfejs używany przez precompiled binarys, stąd ABI.

 6
Author: snies,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-31 09:56:07

Najlepszym sposobem odróżnienia ABI od API jest wiedzieć dlaczego I do czego jest ono używane:

Dla x86-64 jest generalnie jeden ABI (a dla x86 32-bit jest inny "set"): {]}

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 podąża za nim z niewielkimi zmianami. A Windows x64 ma swój ABI:

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

Znając ABI i zakładając, że inny kompilator również za nim podąża, wtedy binaria teoretycznie wiedzą, jak się wzajemnie wywoływać (w szczególności API bibliotek) i przekazywać parametry nad stosem lub przez rejestry itp. Albo jakie rejestry będą zmieniane po wywołaniu funkcji itp. Zasadniczo wiedza ta pomoże oprogramowaniu zintegrować się ze sobą. Znając kolejność rejestry / układ stosu bez większego problemu mogę złożyć różne programy napisane w assemblach.

Ale API są różne:

Jest to wysoki poziom nazw funkcji, z argumentem zdefiniowanym, tak, że jeśli różne elementy oprogramowania budowane przy użyciu tych API, mogą być w stanie wywołać do siebie. Należy jednak przestrzegać dodatkowego wymogu tego samego ABI.

Na przykład Windows kiedyś był API POSIX zgodny:

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

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

Linux jest również zgodny z POSIX. Ale pliki binarne nie mogą być po prostu przesunięte i uruchomione natychmiast. Ale ponieważ używali tych samych nazw w interfejsie API zgodnym z POSIX, możesz pobrać to samo oprogramowanie w języku C, przekompilować je w innym systemie operacyjnym i natychmiast uruchomić.

API mają ułatwić integracja oprogramowania - etap wstępnej kompilacji. Tak więc po kompilacji oprogramowanie może wyglądać zupełnie inaczej - jeśli ABI są inne.

ABI mają na celu zdefiniowanie dokładnej integracji oprogramowania na poziomie binarnym / assembly.

 4
Author: Peter Teoh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-22 05:02:37

W celu wywołania kodu w bibliotekach współdzielonych lub wywołania kodu między jednostkami kompilacji, plik obiektowy musi zawierać etykiety dla tych wywołań. C++ zniekształca nazwy etykiet metod, aby wymusić ukrywanie danych i pozwolić na przeciążenie metod. Dlatego nie można mieszać plików z różnych kompilatorów C++, chyba że wyraźnie obsługują one ten sam ABI.

 3
Author: Justin Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-01 03:48:23

Podsumowanie

Istnieją różne interpretacje i silne opinie dokładnej warstwy, które definiują ABI (application binary interface).

Moim zdaniem ABI jest subiektywną konwencją tego, co jest uważane za daną platformę dla określonego API. ABI jest "resztą" konwencji ,które "nie zmienią się" dla określonego API lub które będą adresowane przez środowisko uruchomieniowe: executory, narzędzia, linkery, Kompilatory, jvm i OS.

Definiowanie an Interface: ABI, API

Jeśli chcesz używać biblioteki takiej jak joda-time musisz zadeklarować zależność od joda-time-<major>.<minor>.<patch>.jar. Biblioteka korzysta z najlepszych praktyk i korzysta z wersji semantycznej . Definiuje to kompatybilność API na trzech poziomach:

  1. Patch - nie musisz w ogóle zmieniać kodu. Biblioteka po prostu naprawia kilka błędów.
  2. Minor - nie musisz zmieniać kodu od dodawania
  3. Major-interfejs (API) jest zmieniony, a Ty może trzeba zmienić kod.

Aby móc korzystać z nowego, głównego wydania tej samej biblioteki, nadal należy przestrzegać wielu innych konwencji:

    W przeciwieństwie do innych bibliotek Java, JVM może być używany w wielu różnych językach, np. w języku Java, Java, java, java, java, java, java, java, java, java, java, java, java, java, java, java.]}
  • wywołanie konwenansów
  • konwencje JVM
  • konwencje linkowania
  • konwencje Runtime Wszystkie te narzędzia są definiowane i zarządzane przez nas użyj.

Przykłady

Java case study

Na przykład, Java ustandaryzowała wszystkie te konwencje, Nie w narzędziu, ale w formalnej specyfikacji JVM. Specyfikacja umożliwiła innym dostawcom dostarczenie innego zestawu narzędzi, które mogą generować kompatybilne biblioteki.

Java dostarcza dwa inne interesujące studia przypadków dla ABI: wersje Scala i Dalvik maszyna wirtualna.

Dalvik virtual machine złamał ABI

Dalvik VM wymaga innego typu kodu bajtowego niż kod Javy. Biblioteki Dalvik są uzyskiwane przez konwersję kodu bajtowego Java (z tym samym API) dla Dalvik. W ten sposób można uzyskać dwie wersje tego samego API: zdefiniowaną przez oryginalną joda-time-1.7.2.jar. Możemy nazywać mnie joda-time-1.7.2.jar i joda-time-1.7.2-dalvik.jar. Używają innego ABI dla zorientowanych na stos standardowych maszyn wirtualnych Java: Oracle, IBM, open Java lub dowolna inna; a drugi ABI to ten wokół Dalvik.

Kolejne wydania Scali to incompatible

Scala nie posiada binarnej kompatybilności pomiędzy podrzędnymi wersjami Scali: 2.X . Z tego powodu ten sam API " io.reactivex "% % "rxscala" % "0.26.5" ma trzy wersje (w przyszłości więcej): dla Scali 2.10, 2.11 i 2.12. Co się zmieniło? Nie wiem na razie, ale binaria nie są kompatybilne. Prawdopodobnie najnowsze wersje dodają rzeczy, które sprawiają, że biblioteki są bezużyteczne na starych maszynach wirtualnych, prawdopodobnie rzeczy związane z linkowaniem/nazywaniem / parametrem konwencje.

Kolejne wydania Javy są niekompatybilne

Java ma również problemy z głównymi wersjami JVM: 4,5,6,7,8,9. Oferują one tylko kompatybilność wsteczną. Jvm9 wie, jak uruchomić kod skompilowany/ukierunkowany (opcja javac -target) dla wszystkich innych wersji, podczas gdy JVM 4 nie wie, jak uruchomić kod ukierunkowany dla JVM 5. Wszystko to, gdy masz jedną bibliotekę joda. Ta niezgodność działa na radarze dzięki różnym rozwiązaniom:

  1. Semantic wersjonowanie: gdy biblioteki są nastawione na wyższy JVM, Zwykle zmieniają główną wersję.
  2. użyj JVM 4 jako ABI, a będziesz bezpieczny.
  3. Java 9 dodaje specyfikację, w jaki sposób można umieścić kod bajtowy dla określonego docelowego JVM w tej samej bibliotece.

Dlaczego zacząłem od definicji API?

API i ABI to tylko konwencje określające zgodność. Niższe warstwy są ogólne w odniesieniu do mnóstwa semantyki wysokiego poziomu. Dlatego łatwo jest zrób jakieś konwencje. Pierwszy rodzaj konwencji dotyczy wyrównania pamięci, kodowania bajtów, wywoływania konwencji, dużych i małych endiańskich kodowań itp. Na ich szczycie znajdują się konwencje wykonywalne, jak inne opisane, konwencje łączące, pośredni kod bajtowy, Jak ten używany przez Javę lub LLVM ir używany przez GCC. Po trzecie dostajesz konwencje jak znaleźć biblioteki, jak je załadować (patrz Java classloaders). Coraz wyżej w pojęciach pojawiają się nowe konwencje, które traktujesz to jako dar. Dlatego nie dotarli do wersji semantycznej . Są niejawne lub załamane w wersji major. Możemy zmienić wersjonowanie semantyczne za pomocą <major>-<minor>-<patch>-<platform/ABI>. To już się dzieje: platforma jest już rpm, dll, jar (JVM bytecode), war (JVM + web server), apk, 2.11 (specyficzna wersja Scala) i tak dalej. Kiedy mówisz APK, mówisz już o określonej części ABI swojego API.

API można przeportować do różne ABI

Najwyższy poziom abstrakcji (źródła napisane w oparciu o najwyższy API mogą być rekompilowane/przeniesione do dowolnej innej abstrakcji niższego poziomu.

Powiedzmy, że mam jakieś źródła dla rxscala. Jeśli Narzędzia Scali zostaną zmienione, mogę je przekompilować. Jeśli zmieni się JVM, mogę mieć automatyczne konwersje ze starej maszyny na nową, bez zawracania sobie głowy koncepcjami wysokiego poziomu. Chociaż portowanie może być trudne, pomoże każdemu innemu klientowi. Jeśli nowy system Operacyjny jest tworzony przy użyciu zupełnie innego kodu asemblera, który może zostać stworzony przez tłumacza.

API przeportowane w różnych językach

Istnieją interfejsy API, które są portowane w wielu językach, np. reactive streams . Na ogół definiują mapowania do określonych języków/platform. Argumentowałbym, że API jest główną specyfikacją formalnie zdefiniowaną w ludzkim języku lub nawet konkretnym języku programowania. Wszystkie inne "mappingi" są w pewnym sensie ABI, inaczej bardziej API niż zwykle ABI. To samo dzieje się z interfejsami reszty.

 2
Author: raisercostin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-15 23:42:45

ABI musi być spójne między wywołującym i callee, aby mieć pewność, że połączenie powiedzie się. Użycie stosu, użycie rejestru, pop końca rutynowego stosu. Wszystko to są najważniejsze części ABI.

 1
Author: Ignacio Vazquez-Abrams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-31 09:42:07

W skrócie i w filozofii, tylko rzeczy Rodzaju mogą się dobrze dogadać, A ABI może być postrzegane jako rodzaj Rodzaju , którego rzeczy programowe współpracują ze sobą.

 1
Author: smwikipedia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-26 15:50:29

Próbowałem też zrozumieć, że odpowiedź ABI i JesperE ' a była bardzo pomocna.

Z bardzo prostej perspektywy możemy próbować zrozumieć ABI, rozważając kompatybilność binarną.

KDE wiki definiuje bibliotekę jako kompatybilną binarnie " jeśli program połączony dynamicznie z poprzednią wersją biblioteki nadal działa z nowszymi wersjami biblioteki bez potrzeby rekompilacji."Aby uzyskać więcej informacji na temat dynamicznego łączenia, zobacz statyczne łączenie vs dynamiczne łączenie

Teraz, spróbujmy przyjrzeć się tylko najbardziej podstawowym aspektom wymaganym, aby Biblioteka była kompatybilna binarnie (zakładając, że nie ma zmian w kodzie źródłowym biblioteki):

  1. ta sama / wstecznie kompatybilna Architektura zestawów instrukcji (instrukcje procesora, struktura plików rejestru, organizacja stosu, typy dostępu do pamięci, wraz z rozmiarami, układem i wyrównaniem podstawowych typów danych, do których procesor może uzyskać bezpośredni dostęp)
  2. Same konwencje wywołujące
  3. Konwencja mangling o tej samej nazwie (może to być potrzebne, jeśli program Fortran musi wywołać jakąś funkcję biblioteki C++).

Oczywiście, jest wiele innych szczegółów, ale to jest głównie to, co ABI również obejmuje.

Dokładniej odpowiadając na twoje pytanie, z powyższego możemy wywnioskować:

Funkcjonalność ABI: kompatybilność binarna

Existing entities: existing program / libraries / OS

Consumer: biblioteki, OS

Mam nadzieję, że to pomoże!

 1
Author: blue_whale,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-21 17:08:05

Application binary interface (ABI)

Funkcjonalność:

  • tłumaczenie z modelu programisty na dane domeny systemu Typ, Rozmiar, wyrównanie, konwencja wywołująca, która kontroluje sposób argumenty funkcji są przekazywane i zwracane wartości; numery połączeń systemowych i jak aplikacja powinna wykonywać połączenia systemowe do systemu operacyjnego; nazwa kompilatorów języka wysokiego poziomu schemat maglowania, propagacja wyjątków i wywoływanie zjazd pomiędzy kompilatorami na tej samej platformie, ale nie wymagają kompatybilność między platformami...

Istniejące podmioty:

  • logiczne bloki bezpośrednio uczestniczące w wykonaniu programu: ALU, rejestry ogólnego przeznaczenia, rejestry do mapowania pamięci/ I/O we/O itp...

Konsument:

  • procesory językowe linker, asembler...

Są one potrzebne każdemu, kto ma zapewnić, że Narzędzia budowlane działają jako w całości. Jeśli piszesz jeden moduł w języku assembly, drugi w Pythonie i zamiast własnego boot-loadera chcesz używać systemu operacyjnego, to twoje moduły "aplikacji" działają ponad "binarnymi" granicami i wymagają zgody takiego "interfejsu".

Używanie nazw w języku C++, ponieważ w aplikacji może być wymagane łączenie plików obiektowych z różnych języków wysokiego poziomu. Rozważ użycie standardowej biblioteki GCC do wykonywania wywołań systemowych do Windows zbudowanych w Visual C++.

ELF jest jednym z możliwych oczekiwań linkera z pliku obiektowego do interpretacji, chociaż JVM może mieć inny pomysł.

W przypadku aplikacji Windows RT Store spróbuj wyszukać ARM ABI, jeśli naprawdę chcesz, aby niektóre narzędzia do budowania działały razem.

 1
Author: Chawathe Vipul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-15 23:34:19

Termin ABI jest używany w odniesieniu do dwóch różnych, ale powiązanych ze sobą pojęć.

Mówiąc o kompilatorach odnosi się do reguł używanych do tłumaczenia z konstruktów na poziomie źródłowym na konstrukcje binarne. Jak duże są typy danych? jak działa stos? jak przekazać parametry do funkcji? które rejestry powinny być zapisywane przez dzwoniącego vs callee?

Mówiąc o bibliotekach odnosi się do interfejsu binarnego prezentowanego przez skompilowaną bibliotekę. Interfejs ten jest wynikiem wiele czynników, w tym kod źródłowy biblioteki, reguły używane przez kompilator oraz w niektórych przypadkach definicje pobrane z innych bibliotek.

Zmiany w bibliotece mogą złamać ABI bez łamania API. Rozważ na przykład bibliotekę z podobnym interfejsem.

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

A programista aplikacji pisze kod jak

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

Programista aplikacji nie dba o rozmiar lub układ FOO, ale aplikacja binarna kończy się z zakodowanym na twardo rozmiar foo. JeĹ "li programista biblioteki doda dodatkowe pole do foo i ktoĹ" uĹźywa nowej biblioteki binarnej ze starÄ ... binarnä ... aplikacjÄ..., to biblioteka moĹźe dokonaÄ ‡ dostÄ ™ pu do pamiÄ ™ ci.

OTOH if the library author had designed their API like.

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

A programista aplikacji pisze kod jak

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

Wtedy aplikacja binarna nie musi wiedzieć nic o strukturze FOO, która może być ukryta wewnątrz biblioteki. Cena, za którą płacisz to jednak jest to, że operacje sterty są zaangażowane.

 1
Author: plugwash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-25 02:35:05