Czy pliki obiektowe (C) utworzone za pomocą różnych kompilatorów są kompatybilne binarnie?

11

Rozumiem, że kompilatory C ++ nie są ze sobą kompatybilne. Jednak nie byłem w stanie znaleźć niczego na ten temat, w szczególności dla C. Wiem, że standard C pozostawia wiele miejsca dla kompilatorów do implementacji rzeczy, które uznają za stosowne: na przykład rozmiar i wyrównanie większości (wszystkich?) Typów danych jest definiowane pod kątem implementacji, z pewnymi minimalnymi gwarancjami. Dlatego dwa kompilatory (lub dwie wersje tego samego kompilatora) mogą nie zgadzać się co do wielu szczegółów.

Czy mam rację, sądząc, że nie ma gwarancji, że dwa pliki obiektowe skompilowane z różnymi kompilatorami faktycznie się połączą? Na przykład rozmiar wskaźników może wynosić 32 bity w jednym pliku obiektowym i 64 bity w drugim. Ale jeśli tak, to dlaczego biblioteki C są czasami dystrybuowane we wstępnie skompilowanej formie? Czy jest oczekiwanie, że użyję tego samego kompilatora, którego używali (np. Gcc), lub jakiegoś faktycznego standardu, który zapewni zgodność binarną? I w jaki sposób inne języki z interfejsem języka obcego zapewniają prawidłowe wyrównanie podczas łączenia z plikami obiektów C?

Doval
źródło
O ile pamiętam, pliki obiektów C powinny być ze sobą kompatybilne, o ile są one kompilowane dla tej samej platformy. Plik obiektowy to po prostu archiwum zawierające ładowany kod binarny z tabelą symboli, za pomocą której można uzyskać dostęp do każdego symbolu w module.
Giorgio
2
biblioteki lib mogą być kompatybilne, nie sądzę, że obj są gwarantowane
maniakiem ratchet
@Giorgo Przez „tę samą platformę” masz na myśli architekturę procesora czy architekturę procesora + system operacyjny?
Doval
@ratchetfreak Miałem wrażenie, że lib jest w większości tylko połączeniem wielu plików obiektowych. Czy to źle?
Doval
Nie spodziewałbym się, że obiekty będą kompatybilne w różnych kompilatorach.
old_timer

Odpowiedzi:

10

Ogólna odpowiedź brzmi: nie, kompilatory w języku C nie są ze sobą kompatybilne. Standard języka C nie definiuje żadnej binarnej interoperacyjności, a większość autorów kompilatorów nawet nie próbuje.

Muszę to zakwalifikować. Obiekty emitowane przez kompilator C muszą być połączone z bibliotekami wykonawczymi, aby utworzyć bibliotekę wykonywalną lub bibliotekę wykonawczą. Chociaż funkcje widoczne w bibliotece wykonawczej C powinny być kompatybilne, pojawią się również funkcje niewidoczne, które są unikalne dla implementacji i zapobiegają interoperacyjności.

Ten brak zgodności dotyczy także różnych wersji tego samego kompilatora. Zasadniczo programów i bibliotek skompilowanych ze starszymi i nowszymi wersjami kompilatora nie można łączyć ze sobą, a tych skompilowanych z MSVC nie można połączyć z tymi skompilowanymi przez GCC.

Istnieje konkretny i bardzo przydatny wyjątek. Każda platforma zapewnia dynamiczne łączenie ABI (Application Binary Interface) i każdy program w dowolnym języku, który może być zgodny z tym ABI, jest kompatybilny. Dlatego generalnie możliwe jest zbudowanie biblioteki DLL (w systemie Windows) za pomocą MSVC (lub czegoś innego) i wywołanie jej z programu skompilowanego przez inną wersję MSVC lub przez GCC i odwrotnie.

Istnieją dwa inne ABI w systemie Windows: zespoły COM i .NET i obejmują one szeroki zakres języków. Więc interoperacyjność jest zdecydowanie możliwa, ale nie są kompatybilne.


Stopień niezgodności można łatwo sprawdzić, porównując mapy linkerów. Do użytku w GNU ld -M, do używania MSVC link /map. Przeanalizuj dwa wygenerowane pliki. Oba będą zawierać nazwy, które rozpoznajesz, takie jak printf i main, chociaż (w zależności od opcji) nazwy mogą być zniekształcone na różne sposoby. Będą też mieć zupełnie inne nazwy, z których wielu nie rozpoznasz. Aby pliki obiektowe tworzone przez różne kompilatory były kompatybilne, muszą uzgodnić wszystkie te nazwy i nigdy tego nie robią. Nawet różne wersje tego samego kompilatora nie zawsze mogą to zrobić.

david.pfx
źródło
Ta odpowiedź wydaje się być sprzeczna z odpowiedzią Barta ; wygląda na to, że kompatybilne są tylko biblioteki współdzielone. Czy mógłbyś wyjaśnić, dlaczego niewidoczne, specyficzne dla implementacji funkcje biblioteki wykonawczej C zapobiegają interoperacyjności? Mówisz także, że „obiekty emitowane przez kompilator C muszą być połączone z bibliotekami wykonawczymi, aby stworzyć bibliotekę wykonywalną lub bibliotekę wykonawczą” - co z bibliotekami statycznymi?
Doval
Jak powiedział Bart, kompatybilne są tylko biblioteki z ABI. Udostępniane biblioteki (w systemie Unix) są jednym rodzajem ABI, są też inne. Napisz HelloWorld.c, skompiluj go za pomocą MSVC i gcc, porównaj mapy, a zobaczysz, jak się różnią. „Biblioteki wykonawcze” oznaczają podstawowe funkcje pomocnicze, do których automatycznie odwoływane są wszystkie kompilacje C / C ++, które mogą być połączone statycznie lub dynamicznie. Przeczytaj mapę lub kod źródłowy CRT, aby je zobaczyć.
david.pfx
Nie wiem, co oznacza porównywanie map, więc będę nieco bardziej szczegółowy: czy w praktyce można założyć, że wszystkie kompilatory dla danej architektury procesora ORAZ kombinacji systemów operacyjnych są kompatybilne? Np. Mam main.c, który kompiluję za pomocą gcc i mylibrary.c, które kompiluję z clang, oba na Linuksie x64. Zakładając rozsądny główny system operacyjny (Linux, Mac, Windows), czy można bezpiecznie założyć, że działałby niezależnie od tego, jakie są te dwa kompilatory?
Doval
1
Bardzo mało prawdopodobne, sprawdź mapę linków clang. Zobacz edycję.
david.pfx
17

To, czego szukasz, nazywa się ABI (Application Binary Interface).

Język C nie definiuje ABI, więc w tym sensie nie ma żadnej gwarancji, że pliki C skompilowane z różnymi kompilatorami będą ze sobą współpracować.

Z drugiej strony, na większości platform system operacyjny definiuje ABI do łączenia się z nim, a wszystkie kompilatory ukierunkowane na tę rodzinę systemów operacyjnych i rodziny procesorów również używają tego samego ABI do łączenia się ze składnikami innymi niż OS. W praktyce obiekty C utworzone przez różne kompilatory mogą ze sobą współpracować.

Bart van Ingen Schenau
źródło
To ma sens. Rozumiem, że biblioteki współdzielone również podążają za ABI systemu operacyjnego?
Doval
3
@Doval Zwłaszcza biblioteki współdzielone, muszą być możliwe do wywołania przez świat zewnętrzny.
toasted_flakes