|
1.
Problem
Czasami gcc zgłasza następujący błąd podczas kompilacji kodu:
Listing 1.1: Typowy błąd zgłaszany przez gcc |
.libs/assert.o: relocation R_X86_64_32 against `a local symbol' can not be used
when making a shared object; recompile with -fPIC .libs/assert.o: could not read
symbols: Bad value
|
W tym tekście omówimy wszystkie możliwe przyczyny pojawienia się takiego błędu.
1.
Co to jest PIC?
PIC to skrót od Position-Independent Code (pol. kod niezależny od
pozycji). Poniższy tekst jest wstępem do artykułu w
Wikipedii odnośnie kodu niezależnego od pozycji:
"W informatyce kod niezależny od pozycji (PIC) lub wykonywanie niezależne od
pozycji (PIE) to obiektowy kod, który można wykonać w różnych położeniach w
pamięci. PIC jest przeważnie używany w bibliotekach współdzielonych, by kod tej
samej biblioteki mógł zostać przypisany do lokacji w każdej aplikacji (używając
systemu wirtualnej pamięci), gdzie nie będzie się pokrywać z aplikacją ani
innymi bibliotekami współdzielonymi. PIC jest również używany na starszych
systemach pozbawionych MMU, co powoduje, że system operacyjny musi trzymać
aplikacje we wzajemnej separacji.
Kod niezależny od pozycji może zostać skopiowany do dowolnego miejsca w pamięci
bez żadnych modyfikacji i uruchomiony, w odróżnieniu od kodu nierelokacyjnego,
który wymaga specjalnego procesu przez linkowanie, by mógł zostać uruchomiony w
podanej lokalizacji. Generalnie kod musi być pisany lub kompilowany w specjalny
sposób w odróżnieniu od kodu niezależnego od pozycji. Instrukcje odnoszące się
do specyficznych adresów w pamięci, takie jak (gałęzie?) absolutne, muszą zostać
zastąpione przez odpowiednie liczniki w relatywnych instrukcjach. Dodatkowa
pośredniość powoduje, że kod PIC może być mniej skuteczny, chociaż współczesne
procesory są projektowane, tak by poprawiać tę niedogodność."
—Wikipedia Encyklopedia
Na pewnych architekturach (również na AMD64), biblioteki współdzielone
muszą posiadać włączoną obsługę "PIC".
1.
Co to są "relokacje"?
Jeszcze raz cytujemy Wikipedię:
"W informatyce relokacja odnosi się do procesu zamiany referencji symbolicznych
lub nazw bibliotek, które aktualnie używają adresów w pamięci przed
uruchomieniem programu. Jest to zwyczajnie robione przez linker podczas
kompilacji, chociaż można to zrobić podczas uruchamiania przez loader.
Kompilatory i assemblery przeważnie tworzą pliki wykonywalne, z najniższym lub
zerowym adresem startowym w pamięci. Przed wykonaniem kodu obiektowego adresy te
powinny zostać wyregulowane, by wskazywały poprawne adresy uruchomieniowe."
—Wikipedia Encyklopedia
Tyle teorii. Teraz praktyka:
1.
Przykład 1: zepsuty kompilator
GCC 3.4 posiada zepsutą implementację flagi -fvisibility-inlines-hidden.
Używanie jej nie jest rozsądne, gdyż wiekszość błedów (ang. bug) jest przeważnie
oznaczana jako RESOLVED INVALID. Błąd 108872 to przykład typowego błędu
wywołanego przez tą flagę.
1.
Przykład 2: zepsuta obsługa sprawdzania `-fPIC' w skrypcie configure
Wiele skryptów configure sprawdza czy kompilator wspiera flagę
-fPIC. Sprawdzenie polega na kompilacji minimalnego programu z włączoną
flagą -fPIC i sprawdzenie stderr. Jeśli kompilator zgłosi
jakiekolwiek ostrzeżenie przyjmuje się że flaga -fPIC nie jest wspierana
przez kompilator i jest opuszczana. Niestety, jeśli użytkownik zdefiniuje
nieistniejącą flagę (np. flagi tylko dla C++ w CFLAGS lub flagi
wprowadzone w nowych wersjach GCC i niewystępujące w starszych wersjach), GCC
również zgłosi ostrzeżenie, powodując błąd.
Aby zapobiec tego typu problemom, profil AMD64 używa bashrc, który filtruje
niepoprawne flagi w C[XX]FLAGS.
Przykładem jest błąd 122208.
1.
Przykład 3: brak wsparcia dla flagi `-fPIC' w kompilowanym programie
To jest najczęściej występujący przypadek. To jest poważny błąd w systemie
budowania i powinien zostać naprawiony w ebuildzie poprzez patch. Przykładowy
błąd dla tego przypadku przedstawiono poniżej:
Listing 1.1: Przykładowy błąd |
.libs/assert.o: relocation R_X86_64_32 against `a local symbol' can not be used
when making a shared object; recompile with -fPIC .libs/assert.o: could not read
symbols: Bad value
|
To oznacza, że plik assert.o nie został skompilowany z włączoną
flagą -fPIC, a powinien. Kiedy naprawi się taki rodzaj błędu, trzeba się
upewnić, że tylko obiekty, które są używane w bibliotekach współdzielonych są
skompilowane z flagą -fPIC.
W tym przypadku, globalne dodanie flagi -fPIC do C[XX]FLAGS
rozwiązuje problem, chociaż nie jest to wskazane, gdyż program wykonywalny
również posiada włączoną obsługę "PIC".
Uwaga:
Dodanie flagi -fPIC do linkera lub LDFLAGS nie rozwiąże problemu.
|
1.
Przykład 4: linkowanie dynamiczne, kontra archiwa statyczne
Czasami pakiet próbuje skompilować biblioteki współdzielone używając archiwów
zbudowanych statycznie, które nie posiadają włączonej obsługi "PIC". Są dwa
powody, dlaczego tak się dzieje:
Często jest to wynik mieszania flagi USE=static oraz USE=-static.
Jeśli biblioteka może zostać skompilowana statycznie, poprzez ustawienie flagi
USE=static, nie tworzy się wówczas plik z rozszerzeniem .so,
ale tylko plik z rozszerzeniem .a. Jednak, kiedy włączymy flagę
-l w GCC, by zlinkować bibliotekę (dynamicznie lub statycznie), wtedy GCC
wróci do archiwum statycznego, jeśli nie będzie mógł znaleźć biblioteki
współdzielonej. W tym wypadku, wskazanym rozwiązaniem jest skompilowanie
statycznej biblioteki z włączoną flagą -fPIC.
Ostrzeżenie:
Na architekturze AMD64 archiwa statyczne można budować tylko i wyłącznie z
włączoną flagą -fPIC. Na pozostałych architekturach jest to niepotrzebne
i powoduje znaczny spadek wydajności podczas uruchamiania.
|
Przykładem może być błąd 88360
lub błąd mysql 8796
Czasami zdarza się również tak, że biblioteka nie powinna być współdzielona w
ogóle, gdy np. nadmiernie używa zmiennych globalnych. W takim wypadku najlepiej
jest skompilować taką bibliotekę jako statyczną.
Przykładem jest błąd 131460.
Listing 1.1: Przykładowy błąd |
gcc -fPIC -DSHARED_OBJECT -c lex.yy.c
gcc -shared -o html2txt.so lex.yy.o -lfl
usr/lib/gcc/x86_64-pc-linux-gnu/4.1.1/../../../../x86_64-pc-linux-gnu/bin/ld:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.1/../../../../lib64/libfl.a(libyywrap.o):
relocation R_X86_64_32 against `a local symbol' can not be used when making a
shared object; recompile with -fPIC
/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.1/../../../../lib64/libfl.a: could not
read symbols: Bad value
|
|