Podczas kompilowania bibliotek współdzielonych w gcc opcja -fPIC kompiluje kod jako niezależny od pozycji. Czy jest jakiś powód (wydajność lub inny), dla którego nie miałbyś kompilować wszystkich pozycji kodu niezależnie?
Podczas kompilowania bibliotek współdzielonych w gcc opcja -fPIC kompiluje kod jako niezależny od pozycji. Czy jest jakiś powód (wydajność lub inny), dla którego nie miałbyś kompilować wszystkich pozycji kodu niezależnie?
Odpowiedzi:
Dodaje pośrednictwo. Z kodem niezależnym od pozycji musisz załadować adres swojej funkcji, a następnie przeskoczyć do niego. Zwykle adres funkcji jest już obecny w strumieniu instrukcji.
Ten artykuł wyjaśnia, jak działa PIC i porównuje go z alternatywą - relokacją czasu ładowania . Myślę, że ma to znaczenie dla twojego pytania.
Tak, istnieją powody dotyczące wydajności. Niektóre dostępy są efektywnie objęte inną warstwą pośrednictwa, aby uzyskać bezwzględną pozycję w pamięci.
Istnieje również GOT (Global offset table), który przechowuje przesunięcia zmiennych globalnych. Dla mnie wygląda to po prostu jak tabela poprawek IAT, która jest klasyfikowana jako zależna od pozycji przez Wikipedię i kilka innych źródeł.
Oprócz zaakceptowanej odpowiedzi. Jedną z rzeczy, która bardzo szkodzi wydajności kodu PIC, jest brak „względnego adresowania IP” na x86. W przypadku „adresowania względnego IP” można poprosić o dane w postaci X bajtów z bieżącego wskaźnika instrukcji. To znacznie uprościłoby kod PIC.
Skoki i wezwania są zwykle związane z EIP, więc tak naprawdę nie stanowią problemu. Jednak dostęp do danych będzie wymagał dodatkowej sztuczki. Czasami rejestr zostanie tymczasowo zarezerwowany jako „wskaźnik bazowy” danych, których wymaga kod. Na przykład powszechną techniką jest nadużywanie sposobu działania wywołań na platformie x86:
call label_1
.dd 0xdeadbeef
.dd 0xfeedf00d
.dd 0x11223344
label_1:
pop ebp ; now ebp holds the address of the first dataword
; this works because the call pushes the **next**
; instructions address
; real code follows
mov eax, [ebp + 4] ; for example i'm accessing the '0xfeedf00d' in a PIC way
Ta i inne techniki dodają warstwę pośredniego dostępu do danych. Na przykład GOT (Global offset table) używany przez kompilatory gcc.
x86-64 dodał tryb „względny RIP”, który znacznie upraszcza sprawę.
Ponieważ implementacja kodu całkowicie niezależnego od pozycji dodaje ograniczenie do generatora kodu, co może uniemożliwić użycie szybszych operacji lub dodać dodatkowe kroki, aby zachować to ograniczenie.
Może to być akceptowalny kompromis, aby uzyskać wieloprocesorowość bez systemu pamięci wirtualnej, w której ufasz procesom, że nie będą atakować wzajemnie pamięci i może być konieczne załadowanie określonej aplikacji pod dowolnym adresem podstawowym.
W wielu nowoczesnych systemach kompromisy w zakresie wydajności są różne, a program ładujący przemieszczający się jest często tańszy (kosztuje każde pierwsze załadowanie kodu) niż najlepsze, co optymalizator może zrobić, jeśli ma wolne panowanie. Ponadto dostępność wirtualnych przestrzeni adresowych ukrywa przede wszystkim większość motywacji do niezależności pozycji.
Ponadto sprzęt pamięci wirtualnej w większości nowoczesnych procesorów (używany przez większość współczesnych systemów operacyjnych) oznacza, że wiele kodu (wszystkie aplikacje przestrzeni użytkownika, z wyjątkiem dziwacznego użycia mmap itp.) Nie musi być niezależne od pozycji. Każdy program otrzymuje własną przestrzeń adresową, która według niego zaczyna się od zera.
Obecnie system operacyjny i kompilator domyślnie tworzą cały kod jako kod niezależny od pozycji. Spróbuj skompilować bez flagi -fPIC, kod skompiluje się dobrze, ale otrzymasz tylko ostrzeżenie. Windows podobnie jak Windows używa techniki zwanej mapowaniem pamięci, aby to osiągnąć.
Pytanie pochodzi z 2009 roku. Minęło dziesięć lat, a teraz cały kod jest właściwie niezależny od pozycji. Jest to teraz wymuszane przez systemy operacyjne i kompilatory. Nie ma możliwości rezygnacji. Cały kod jest kompilowany na siłę z PIE, a flaga -no-pic / -no-pie jest ignorowana, jako część tej wymówki ASLR. Powodem tego jest spowolnienie dawniej szybkich aplikacji i sprzedaż nowszego sprzętu pod pozorem zwiększonego bezpieczeństwa. Jest to całkowicie irracjonalne, ponieważ teraz duże rozmiary pamięci pozwalają nam w ogóle pozbyć się piekła dynamicznego linkowania, kompilując wszystkie aplikacje statycznie.
To samo działo się wcześniej, kiedy ludzie w milczeniu akceptowali realny tryb i odbieranie innym wolności. I pamiętam, że MMU ulega znacznemu spowolnieniu z powodu przełączania kontekstu i opóźnienia tłumaczenia adresu. Nie znajdziesz MMU w systemach krytycznych dla wydajności, takich jak te używane przez naukowców do próbkowania eksperymentów fizycznych.
Nie narzekasz, bo nawet nie wiesz, że wszystkie te koła szkoleniowe utrudniają Twój kod. Co mogę powiedzieć? Ciesz się 2 razy wolniejszym oprogramowaniem dzięki PIC! Co więcej, wraz z pojawieniem się LLVM, wkrótce zostanie wymuszony JIT (kod zarządzany), bez dostępu do wbudowanego asemblera x86, co dodatkowo spowolni każdy kod C / C ++. „Ci, którzy poświęcają wolność dla bezpieczeństwa, na nic nie zasługują”.