Gentoo Logo

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

Zaktualizowano 23 lipca 2006

Donate to support our development efforts.

Copyright 2001-2012 Gentoo Foundation, Inc. Questions, Comments? Contact us.