Linux, GNU GCC, ld, skrypty wersji i format binarny ELF - jak to działa?

13

Próbuję dowiedzieć się więcej o wersjonowaniu bibliotek w systemie Linux i o tym, jak to wszystko uruchomić. Oto kontekst:

- Mam dwie wersje biblioteki dynamicznej, która udostępnia ten sam zestaw interfejsów, powiedzmy libsome1.soi libsome2.so.

- Aplikacja jest połączona z libsome1.so.

- Ta aplikacja używa libdl.sodo dynamicznego ładowania innego modułu, powiedzmy libmagic.so.

- Teraz libmagic.sojest powiązany z libsome2.so. Oczywiście, bez użycia skryptów linkera do ukrywania symboli libmagic.so, w czasie wykonywania wszystkie wywołania interfejsów libsome2.sosą przetwarzane libsome1.so. Można to potwierdzić, porównując wartość zwracaną przez libVersion()z wartością makra LIB_VERSION.

- Więc próbuję następnie skompilować i połączyć libmagic.soze skryptem linkera, który ukrywa wszystkie symbole oprócz 3, które są w nim zdefiniowane libmagic.soi są przez niego eksportowane. To działa ... albo przynajmniej libVersion()i LIB_VERSIONwartości dopasowania (i zgłasza wersji 2 nie 1).

- Jednak gdy niektóre struktury danych są serializowane na dysk, zauważyłem pewne uszkodzenie. Jeśli w katalogu aplikacji usunę libsome1.soi utworzę miękki link w jego miejscu, aby wskazać libsome2.so, wszystko działa zgodnie z oczekiwaniami i takie samo uszkodzenie nie występuje.

Nie mogę przestać myśleć, że może to być spowodowane konfliktem w rozdzielczości symboli łącznika w czasie wykonywania. Próbowałem wielu rzeczy, takich jak próba połączenia libsome2.so, aby wszystkie symbole były wyrównane symbol@@VER_2( do czego wciąż jestem zdezorientowany, ponieważ polecenie nm -CD libsome2.sonadal wyświetla symbole jako symboli nie symbol@@VER_2) ... Wydaje się, że nic nie działa !!! Wsparcie!!!!!!

themoondothshine
źródło
Twoje ostatnie podejście to takie, od którego bym zaczął. I zgadzam się, że zepsucie jest prawdopodobnie pomieszaniem symboli. Niestety nie mam dla ciebie odpowiedzi.
RobotHumans
to może się lepiej na SO, choć thh nie rozumiem tego wystarczająco, aby powiedzieć na pewno. oflaguj go, jeśli chcesz, abyśmy go przenieśli.
ksenoterrakid,
1
Wypróbuj flagi RTLD_LOCALi RTLD_DEEPBINDdlopen w swojej aplikacji. Nie mam teraz czasu na testowanie tego, ale powinno działać w oparciu o stronę podręcznika.
stribika

Odpowiedzi:

13

To nie odpowiada dokładnie na twoje pytanie, ale ...

Po pierwsze, ELF jest specyfikacją używaną przez Linux dla plików wykonywalnych (programów), bibliotek współdzielonych, a także plików obiektowych, które są plikami pośrednimi znalezionymi podczas kompilacji oprogramowania. Pliki obiektów kończą się na .o, biblioteki współdzielone kończą się na .so, po którym następuje zero lub więcej cyfr oddzielonych kropkami, a pliki wykonywalne nie mają normalnie żadnych rozszerzeń.

Zazwyczaj istnieją trzy formularze określające bibliotekę współdzieloną, pierwsza forma kończy się na .so. Na przykład biblioteka o nazwie readline jest przechowywana w pliku o nazwie libreadline.so i normalnie znajduje się w katalogu / lib, / usr / lib lub / usr / local / lib. Ten plik znajduje się podczas kompilacji oprogramowania z opcją -lreadline. -l każe kompilatorowi połączyć się z następującą biblioteką. Ponieważ biblioteki zmieniają się od czasu do czasu, mogą stać się przestarzałe, dlatego biblioteki zawierają coś o nazwie SONAME. SONAME dla readline może wyglądać jak libreadline.so.2 dla drugiej wersji głównej wersji libreadline. Może być także wiele mniejszych wersji readline, które są kompatybilne i nie wymagają ponownej kompilacji oprogramowania. Niewielka wersja readline może nazywać się libreadline.so.2.14. Zwykle libreadline. więc jest to tylko symboliczny link do najnowszej głównej wersji readline, libreadline.so.2 w tym przypadku. libreadline.so.2 jest także dowiązaniem symbolicznym do libreadline.so.2.14, który jest faktycznie używanym plikiem.

SONAME biblioteki jest osadzony w samym pliku biblioteki. Gdzieś w pliku libreadline.so.2.14 znajduje się ciąg libreadline.so.2. Kiedy program zostanie skompilowany i połączony z readline, wyszuka plik libreadline.so i przeczyta osadzoną w nim SONAME. Później, kiedy program zostanie faktycznie uruchomiony, załaduje libreadline.so.2, a nie tylko libreadline.so, ponieważ była to nazwa SONAME, którą odczytano podczas pierwszego połączenia. Pozwala to systemowi na zainstalowanie wielu niekompatybilnych wersji readline, a każdy program załaduje odpowiednią wersję główną, z którą był połączony. Ponadto, uaktualniając readline, powiedzmy, do 2.17, mogę po prostu zainstalować libreadline.so.2.17 wraz z istniejącą biblioteką, a po przeniesieniu dowiązania symbolicznego libreadline.so.2 z libreadline.so.2.13 do libreadline.so.2.17,

penguin359
źródło