Pod Windows, kiedy kompiluję kod C / C ++ w projekcie DLL w MSVC, otrzymuję 2 pliki:
MyDll.dll
MyDll.lib
gdzie, o ile rozumiem, MyDll.lib
zawiera pewnego rodzaju tabelę wskaźników wskazującą lokalizacje funkcji w bibliotece dll. Podczas korzystania z tej biblioteki DLL, powiedzmy w pliku exe, MyDll.lib
jest ona osadzana w pliku exe podczas łączenia, więc w czasie wykonywania „wie”, gdzie znajdują się funkcje MyDll.dll
i może z nich korzystać.
Ale jeśli skompiluję ten sam kod w systemie Linux, otrzymam tylko jeden plik MySo.so
bez MySo.a
(odpowiednik lib
pliku w systemie Linux), więc skąd plik wykonywalny w systemie Linux wie, gdzie znajdują się funkcje, MySo.so
jeśli nic nie jest w nim osadzone podczas łączenia?
Linker MSVC może łączyć ze sobą pliki obiektów (.obj) i biblioteki obiektów (.lib) w celu utworzenia pliku .EXE lub .DLL.
Aby połączyć się z DLL, proces w MSVC polega na użyciu tak zwanej biblioteki importu (.LIB), która działa jak klej między nazwami funkcji C a tabelą eksportu DLL (w DLL można wyeksportować funkcję według nazwy lub przez porządkowy - ten ostatni był często używany do nieudokumentowanych interfejsów API).
Jednak w większości przypadków tabela eksportu DLL ma wszystkie nazwy funkcji, a zatem biblioteka importu (.LIB) zawiera w dużej mierze zbędne informacje („ funkcja importu ABC -> funkcja eksportowana ABC ” itp.).
Możliwe jest nawet wygenerowanie pliku .LIB z istniejącego pliku .DLL.
Linkery na innych platformach nie mają tej „funkcji” i mogą łączyć się bezpośrednio z bibliotekami dynamicznymi.
źródło
Różnica, którą widzisz, to bardziej szczegół implementacji - pod maską zarówno Linux, jak i Windows działają podobnie - kod wywołuje funkcję kodu pośredniczącego, który jest statycznie powiązany w pliku wykonywalnym, a ten kod pośredniczący ładuje w razie potrzeby bibliotekę DLL / shlib (w przypadku opóźnienia ładowanie , w przeciwnym razie biblioteka jest ładowana przy uruchomieniu programu) i (przy pierwszym wywołaniu) rozwiązuje symbol przez
GetProcAddress
/dlsym
.Jedyna różnica polega na tym, że w systemie Linux te kody pośredniczące (zwane kodami pośredniczącymi PLT) są generowane dynamicznie po połączeniu aplikacji z biblioteką dynamiczną (biblioteka zawiera wystarczającą ilość informacji do ich wygenerowania), podczas gdy w systemie Linux są one generowane, gdy sama biblioteka DLL jest utworzony w osobnym
.lib
pliku.Te dwa podejścia są tak podobne, że w rzeczywistości można naśladować biblioteki Windows importujące biblioteki w systemie Linux (patrz projekt Implib.so ).
źródło
W Linuksie przekazujesz
MySo.so
linkerowi, który jest w stanie wyodrębnić tylko to, co jest potrzebne do fazy łącza, wprowadzając odwołanieMySo.so
potrzebne w czasie wykonywania.źródło
.dll
lub.so
są udostępnionymi bibliotekami lib (połączonymi w czasie wykonywania), podczas gdy.a
i.lib
są biblioteką statyczną (połączoną w czasie kompilacji). Nie ma różnicy między Windows i Linux.Różnica polega na tym, w jaki sposób są obsługiwane. Uwaga: różnica dotyczy tylko organów celnych, w jaki sposób są one wykorzystywane. Nie byłoby trudno stworzyć Linuksa w systemie Windows i odwrotnie, z tym że praktycznie nikt tego nie robi.
Jeśli używamy biblioteki dll lub wywołujemy funkcję nawet z własnego pliku binarnego, istnieje prosty i przejrzysty sposób. Na przykład w C widzimy, że:
Jednak na poziomie asm może być wiele różnic. Na przykład na x86
call
wykonywany jest kod operacji, który42
jest podawany na stosie. Lub w niektórych rejestrach. Lub gdziekolwiek. Nikt nie wie, że przed napisaniem biblioteki dll , w jaki sposób będzie ona używana. Lub w jaki sposób projekty będą chciały z niego korzystać, możliwe napisane przy pomocy kompilatora (lub w języku!), Który nawet nie istnieje (lub jest nieznany twórcom dll).Na przykład domyślnie zarówno C, jak i Pascal umieszczają argumenty (i uzyskują wartości zwracane) ze stosu - ale robią to w innej kolejności . Możesz także wymieniać argumenty między funkcjami w rejestrach przez optymalizację zależną od kompilatora.
Jak widzisz poprawnie, niestandardowy system Windows polega na tym, że budując bibliotekę DLL, tworzymy również minimalny
.a
/.lib
za jej pomocą. Ta minimalna statyczna biblioteka jest tylko opakowaniem, poprzez które można uzyskać dostęp do symboli (funkcji) tej biblioteki DLL. To sprawia, że wymagane konwersje telefoniczne na poziomie asm.Jego zaletą jest kompatybilność. Jego wadą jest to, że jeśli masz tylko plik .dll, możesz mieć trudności z ustaleniem, jak mają być wywoływane jego funkcje. To sprawia, że korzystanie z bibliotek DLL jest zadaniem hakującym, bibliotek jeśli programista biblioteki DLL nie daje takiej możliwości
.a
. Służy więc głównie celom związanym z zamknięciem, na przykład łatwiej jest zdobyć dodatkową gotówkę na zestawy SDK.Jego kolejną wadą jest to, że nawet jeśli używasz biblioteki dynamicznej, musisz skompilować to małe opakowanie statycznie.
W Linuksie interfejs binarny bibliotek DLL jest standardem i jest zgodny z konwencją C. Tak więc nie
.a
jest wymagane i istnieje zgodność binarna między udostępnionymi bibliotekami, w zamian nie mamy zalet niestandardowego oprogramowania Microsoft.źródło