2011-08-05 37 views
13

Kompilowanie kodu do pliku obiektowego musi być wykonywane niezależnie od pozycji, jeśli plik obiektowy ma być załadowany jako biblioteka współdzielona (.so), ponieważ podstawowy adres wirtualny, do którego jest ładowany plik obiektu współdzielonego w różnych procesach, może być różne.Czy 32-bitowy kod x86 musi być specjalnie skompilowany z PIC dla współdzielonych plików biblioteki?

Teraz nie wystąpiły błędy podczas próby załadowania pliku .so skompilowanego i połączonego bez opcji -fpic GCC na 32-bitowych komputerach x86, podczas gdy nie powiedzie się na 64-bitowych komputerach x86.

Losowe stron internetowych znalazłem, że nie muszę -fpic na 32bit ponieważ kod skompilowany bez -fpic prac przez przypadek według 32bit X86 ABI również, gdy są wykorzystywane w sposób niezależny od pozycji. Ale nadal znajdowałem oprogramowanie, które dostarczane jest z oddzielnymi wersjami bibliotek w 32-bitowych wersjach: jedna dla PIC i jedna dla innych niż PIC. Na przykład kompilator intel jest dostarczany z libirc.a i libirc_pic.a, ten ostatni jest kompilowany w trybie niezależnym od pozycji (jeśli chcemy połączyć ten plik .a w plik .so).

Zastanawiam się, jaka jest dokładna różnica między używaniem -fpic i nie używanie go dla kodu 32-bitowego i dlaczego niektóre pakiety, takie jak kompilator intel, nadal są dostarczane z oddzielnymi wersjami bibliotek?

+0

Czy wypróbowałeś nie-fikcyjną kompilację kodu przy użyciu TLS? Lub załadować kilka bibliotek non-pic z nakładającymi się zakresami pamięci? Oddzielne statyczne biblioteki są statycznie łączone z programami (libirc.a, nie pic jest nieco szybszy) i statycznie do bibliotek .so (wersja _pic.a). – osgx

+0

Zobacz http://stackoverflow.com/questions/3146744/difference-in-position-independent-code-x86-vs-x86-64 – AProgrammer

Odpowiedz

0

bazy adresów wirtualnych, że plik wspólny cel został załadowany do różnych procesów może inaczej

Ponieważ obiekty udostępnione zazwyczaj ładuje się preferowanym adres mogą pojawić działa poprawnie . Ale fPIC jest dobrym pomysłem dla wszystkich wspólnych kodów.

Uważam, że powodem, dla którego często nie ma dwóch wersji biblioteki, jest to, że wiele dystrybucji używa domyślnie dla wszystkich kodów fPIC.

+3

Obiekty współużytkowane są zwykle połączone z obciążeniem pod adresem 0 i zdecydowanie nie ładują się tam. –

+0

Co @Employed Russian powiedział. Możesz również "prelinkować" biblioteki, aby miały preferowany adres bazowy, ale jest to oddzielny (i opcjonalny) krok od normalnego łączenia. – ninjalj

+1

@Employed Russian: Czy to jest coś tylko z Linuksem?Inne systemy operacyjne nie są tak głupie, że domyślnie są w 100% konfliktami adresów bazowych. –

10

Nie jest tak, że kod non-PIC działa "przez przypadek" na x86 (32-bitowy). Jest to, że dynamiczny linker dla x86 obsługuje niezbędne "textrels" potrzebne do jego działania. Dzieje się to przy bardzo dużym koszcie zużycia pamięci i czasu uruchamiania, ponieważ zasadniczo cały segment kodu musi być załatany podczas ładowania (i tym samym staje się pamięcią nie do współużytkowania).

Twórcy dynamicznego linkera twierdzą, że biblioteki współużytkowane inne niż PIC nie mogą być obsługiwane na architekturze x86_64 z powodu podstawowych problemów architektury (natychmiastowe przesunięcia adresu nie mogą być większe niż 32-bitowe), ale problem ten można łatwo rozwiązać po prostu zawsze ładując biblioteki w pierwszych 4gb wirtualnej przestrzeni adresowej. Oczywiście kod PIC jest bardzo niedrogi na x86_64 (PIC nie jest tak wydajnym zabójcą, jak na 32-bitowym x86), więc prawdopodobnie mają rację, aby go nie obsługiwać i uniemożliwić głupcom tworzenie bibliotek non-PIC ...

+0

Dzięki, to ma sens. Jeśli skompiluję bibliotekę PIC na x86, to już nie używam textrelów, podejrzewam? Dlaczego to nadal jest zabójca wydajności? –

+6

Kod PIC wymaga dodatkowego rejestru do przechowywania adresu bazowego. Na x86 masz już za mało rejestrów, więc zarezerwowanie jeszcze jednego sprawia, że ​​rejestry rozlewania kompilatora do pamięci jeszcze częściej. –

+2

PIC jest zabójcą wydajności na x86, ponieważ ładowanie rejestru GOT jest kosztowne. Wymaga wywołania funkcji i odczytywania/zapisywania adresu zwrotnego ze stosu. x86_64 ma adresowanie względne typu eip, dzięki czemu nie jest potrzebny rejestr GOT. –