ld.so, ld-linux.so* - dynamiczny konsolidator/ładowacz
Konsolidator dynamiczny może być uruchomiony albo
pośrednio przez uruchomienie jakiegokolwiek skonsolidowanego
dynamicznie programu lub obiektu dzielonego (w tym przypadku żadna
opcja linii poleceń nie będzie przekazana do konsolidatora
dynamicznego i w przypadku ELF-a uruchomiony zostanie konsolidator
dynamiczny przechowywany w sekcji .interp programu), albo
bezpośrednio przez uruchomienie:
/lib/ld-linux.so.* [OPCJE] [PROGRAM [ARGUMENTY]]
Programy ld.so i ld-linux.so* wyszukują i
uruchamiają obiekty dzielone (biblioteki dzielone) wymagane przez
program, przygotowują program do uruchomienia, a w końcu go
uruchamiają.
Binarki linuksowe wymagają konsolidacji dynamicznej (czyli
konsolidacji podczas uruchamiania), chyba że podczas kompilacji
programowi ld(1) przekazano opcję -static.
Program ld.so obsługuje binarki w używanym
dawno temu formacie a.out; ld-linux.so* obsługuje format ELF
(/lib/ld-linux.so.1 dla libc5, /lib/ld-linux.so.2 dla glibc2),
który jest używany przez wszystkich już od
ładnych paru lat. Poza tym oba programy zachowują się
tak samo i używają tych samych plików pomocniczych i
programów: ldd(1), ldconfig(8) oraz
/etc/ld.so.conf.
Podczas rozwiązywania zależności
obiektów dzielonych, konsolidator dynamiczny najpierw
przegląda każdy łańcuch znaków
zależności w poszukiwaniu znaku ukośnika (może
wystąpić, jeśli podczas linkowania obiektu dzielonego
podano nazwę ścieżki zawierającą
ukośniki). Jeśli taki znak zostanie znaleziony, to
łańcuch znaków zależności jest
interpretowany jako nazwa (względnej lub bezwzględnej)
ścieżki i obiekt dzielony jest ładowany,
używając tej nazwy ścieżki.
Jeśli zależność od obiektu dzielonego
nie zawiera znaku ukośnika, to potrzebne biblioteki dzielone
są szukane w następującej kolejności:
- o
- (Tylko ELF). Używa katalogów podanych w sekcji
atrybutów dynamicznych DT_RPATH binarki, jeśli jest obecna i
nie istnieje atrybut DT_RUNPATH. Użycie DT_RPATH jest
przestarzałe.
- o
- Przy użyciu zmiennej środowiskowej LD_LIBRARY_PATH,
chyba że plik wykonywalny jest uruchomiony w trybie bezpiecznego
wykonania; (zob. niżej), gdy jest ignorowana.
- o
- (Tylko ELF) Używając katalogów podanych w sekcji
atrybutów dynamicznych DT_RUNPATH binarki, jeśli taka sekcja
istnieje.
- o
- Z pliku bufora /etc/ld.so.cache, zawierającego
skompilowaną listę obiektów dzielonych
poprzednio znalezionych w ścieżce obiektów
dzielonych. Jeśli jednakże program binarny został
skonsolidowany z opcją linkera -z nodeflib, to pomijane
są obiekty dzielone z domyślnych ścieżek
obiektów dzielonych. Preferowane są obiekty dzielone
zainstalowane w katalogach zgodnych z właściwościami
sprzętu (patrz niżej).
- o
- W domyślnej ścieżce /lib a potem w
/usr/lib (na niektórych architekturach 64-bitowych
domyślną ścieżką 64-bitowych
obiektów dzielonych jest /lib64, a potem /usr/lib64).
Ten krok jest pomijany, jeśli program binarny został
skonsolidowany z opcją -z nodeflib
konsolidatora.
ld.so rozumie pewne łańcuchy znaków w
specyfikacji rpath (DT_RPATH lub DT_RUNPATH); łańcuch ty
są zamieniane następująco:
- $ORIGIN (lub równoważnie ${ORIGIN})
- Rozwija się do katalogu zawierającego program lub obiekt
dzielony. Tak więc aplikacja znajdująca się w
jakimśkatalogu/app może zostać skompilowana z
gcc -Wl,-rpath,'$ORIGIN/../lib'
tak żeby przypisane jej obiekty dzielone mogły
być umieszczone w jakimśkatalogu/lib,
niezależnie od tego, gdzie jakiśkatalog jest
umieszczony w hierarchii katalogów. Umożliwia to tworzenie
aplikacji, które nie muszą być instalowane w
specjalnych katalogów, ale mogą po prostu być
rozpakowane w dowolnym katalogu i
wciąż będą mogły
znaleźć swoje obiekty dzielone.
- $LIB (lub równoważnie ${LIB})
- Rozwija się do lib lub lib64 w
zależności od architektury (np. na x86-64 rozwija się
lib64, a na x86-32 rozwija się do lib).
- $PLATFORM (lub równoważnie ${PLATFORM})
- Rozwija się do łańcucha znaków
odpowiadającemu typowi procesora systemu (np. "x86_64").
Na niektórych architekturach jądro Linuksa nie przekazuje
konsolidatorowi dynamicznemu oznaczenia platformy. Wartość
tego łańcucha znaków jest pobierana z wartości
AT_PLATFORM pomocniczego wektora (patrz getauxval(3)).
- --list
- Wyświetla wszystkie zależności wraz ze sposobem ich
rozwiązania.
- --verify
- Sprawdza, że program jest konsolidowany dynamicznie i że ten
konsolidator dynamiczny może go obsłużyć.
- --inhibit-cache
- Nie używa /etc/ld.so.cache.
- --library-path
ścieżka
- Używa ścieżki zamiast ustawienia zmiennej
środowiska LD_LIBRARY_PATH (patrz niżej).
- --inhibit-rpath
lista
- Ignoruje informacje RPATH i RUNPATH w nazwach obiektów w
liście. Opcja jest ignorowana podczas działania w
trybie bezpiecznego wykonania (zob. niżej)
- --audit
lista
- Używa obiektów wymienionych w liście jako
audytorów.
ŚRODOWISKO
Różne zmienne środowiska
wpływają na działanie dynamicznego konsolidatora
Ze względów bezpieczeństwa, działania
niektórych zmiennych środowiskowych jest anulowane lub
modyfikowane, jeśli dynamiczny konsolidator określi, że
plik binarny powinien być uruchomiony w trybie bezpiecznego
wykonania. To określenie dokonywane jest na podstawie sprawdzenia,
czy wpis AT_SECURE w dodatkowym wektorze (zob. getauxval(3))
ma niezerową wartość. Wpis ten może mieć
niezerową wartość z różnych
powodów, m.in.:
- Rzeczywisty i efektywny identyfikator użytkownika procesu
różnią się lub rzeczywisty i efektywny
identyfikator grupy różnią się. Zwykle
ma to miejsce jako rezultat wykonywania programu z set-user-ID lub
set-group-ID.
- Proces użytkownika z identyfikatorem niebędącym ID
roota wykonuje plik binarny z nadanymi przywilejami permitted lub
effective.
- Niezerowa wartość mogła być ustawiona
przez linuksowy moduł bezpieczeństwa - Linux Security
Module.
Wśród ważniejszych zmiennych
środowiskowych są następujące:
- LD_ASSUME_KERNEL
(glibc od wersji 2.2.3)
- Każdy obiekt dzielony może informować konsolidator
dynamiczny o wymaganej minimalnej wersji ABI jądra (To wymaganie
jest zakodowane w sekcji "note" ELF-a; sekcja ta jest widoczna w
readelf -n jako sekcja oznaczona NT_GNU_ABI_TAG).
Podczas działania konsolidator dynamiczny określa
wersję ABI uruchomionego jądra i odrzuca obiekty dzielone,
które wymagają minimalnej wersji ABI większej
niż wersja ABI uruchomionego jądra.
LD_ASSUME_KERNEL może zostać użyta
do spowodowania, że konsolidator dynamiczny założy,
że jest uruchomiony na systemie z inną
wersją ABI jądra. Na przykład
następująca linia poleceń powoduje, że
konsolidator dynamiczny podczas ładowania obiektów
dzielonych wymaganych przez mójprog zakłada,
że działa w systemie Linux 2.2.5
$ LD_ASSUME_KERNEL=2.2.5 ./mójprog
W systemach, które dostarczają wielu wersji
obiektu dzielonego (w różnych katalogach w
ścieżce wyszukiwania) o różnych minimalnych
wymaganiach wersji ABI jądra, LD_ASSUME_KERNEL może
zostać użyte do wybrania tej wersji obiektu, która
zostanie użyta (w zależności od porządku
przeszukiwania katalogów). Historycznie najczęstszym
użyciem LD_ASSUME_KERNEL było ręczne
wybieranie starszej implementacji POSIX-owych wątków
LinuxThreads w systemach, które miały zainstalowane
zarówno LinuxThreads, jak i NPTL (który był
domyślną wersją na takich systemach); patrz
pthreads(7).
- LD_BIND_NOW
- (libc5; glibc od wersji 2.1.1) Gdy zmienna ta jest obecna, sprawia,
że dynamiczny konsolidator rozwiąże wszystkie symbole
podczas startu programu, a nie wtedy gdy będzie do nich pierwsze
odniesienie. Jest to użyteczne podczas używania
debuggera.
- LD_LIBRARY_PATH
- Lista katalogów, w których szukać bibliotek ELF
podczas wykonywania. Składniki listy
mogą być oddzielone dwukropkiem lub
średnikiem. Podobne do zmiennej środowiskowej PATH.
Ta zmienna jest ignorowana w trybie bezpiecznego wykonania.
- LD_PRELOAD
- Lista dodatkowych, podanych przez użytkownika obiektów
dzielonych ELF, którą należy załadować
przed wszystkimi innymi. Elementy listy mogą być oddzielone
od siebie spacjami lub dwukropkami. Umożliwia to
wybiórczą zamianę funkcji w innych obiektach
dzielonych. Może być używane do wybiórczego
nadpisywania funkcji z innych obiektów dzielonych. Obiekty
są wyszukiwane zgodnie z regułami podanymi w rozdziale OPIS.
W trybie bezpiecznego wykonania, załadowane wstępnie
ścieżki zawierające ukośniki są
ignorowane, a obiekty dzielone ze standardowej ścieżki
katalogów ładowane będą tylko wtedy, gdy
mają także ustawiony bit set-user-ID.
- LD_TRACE_LOADED_OBJECTS
- (tylko ELF) Gdy zmienna ta jest ustawiona (na dowolną
wartość) powoduje, że program wypisze swoje
dynamiczne zależności, tak jakby był uruchomiany
przez ldd(1), a nie normalnie.
Jest także wiele bardziej lub mniej mętnych
zmiennych, wiele przestarzałych lub przeznaczonych do użytku
wewnętrznego.
- LD_AOUT_LIBRARY_PATH
- (libc5) Wersja LD_LIBRARY_PATH tylko dla binariów a.out.
Starsze wersje ld-linux.so.1 wspierały także
LD_ELF_LIBRARY_PATH.
- LD_AOUT_PRELOAD
- (libc5) Wersja LD_PRELOAD tylko dla binariów a.out. Starsze
wersje ld-linux.so.1 wspierały także
LD_ELF_PRELOAD.
- LD_AUDIT
- (glibc od wersji 2.4). Rozdzielona dwukropkami lista określonych
przez użytkownika dzielonych obiektów ELF do
załadowania przez wszystkimi innymi obiektami w oddzielnej
przestrzeni nazw konsolidatora (to jest w przestrzeni nazw, która
nie wpływa na przyporządkowania symboli, które odbywa
się w procesie). Obiektów tych można
użyć do audytu operacji konsolidatora dynamicznego.
LD_AUDIT jest ignorowane w trybie bezpiecznego wykonania.
Konsolidator dynamiczny powiadomi obiekty dzielone audytu w
tak zwanych punktach sprawdzeń audytu \m na przykład
ładowanie nowego dzielonego obiektu, rozwiązanie symbolu
lub wywołanie symbolu z innego obiektu dzielonego \m przez
wywołanie odpowiedniej funkcji obiektu dzielonego.
Szczegóły można znaleźć w
rtld-audit(7). Interfejs audytu jest w dużej mierze zgodny
z tym udostępnianym przez Solarisa, opisanym w jego
Przewodniku po konsolidatorze i bibliotekach w rozdziale
Interfejs audytu konsolidatora.
- LD_BIND_NOT
- (glibc od wersji 2.1.95) Jeśli ta zmienna środowiskowa jest
ustawiona na niepusty łańcuch, to nie zachodzi aktualizacja
GOT (global offset table) ani PLT (procedure linkage table) po
rozwinięciu symbolu.
- LD_DEBUG
- (glibc od wersji 2.1) Wypisuje rozwlekłe informacje debugowania
konsolidatora dynamicznego. Jeśli ustawione na all wypisuje
wszystkie dostępne informacje debugowania, jeśli ustawione
na help wyświetla listę kategorii, które
można podać jako wartość tej zmiennej
środowiskowej. Od glibc wersji 2.3.4 LD_DEBUG jest
ignorowana w trybie bezpiecznego wykonania, chyba że istnieje plik
/etc/suid-debug (jest zawartość jest
nieistotna).
- LD_DEBUG_OUTPUT
- (glibc od wersji 2.1) Plik, do którego będzie zapisane
wyjście LD_DEBUG. Domyślnie jest to standardowe
wyjście błędów. LD_DEBUG_OUTPUT jest
ignorowane w trybie bezpiecznego wykonania.
- LD_DYNAMIC_WEAK
- (glibc od wersji 2.1.91) Jeśli ta zmienna środowiskowa jest
zdefiniowana (z dowolną wartością), to pozwala
na nadpisywanie słabych (ang. weak) symboli (przywracając
poprzednie zachowanie glibc). Od wersji 2.3.4 biblioteki glibc
LD_DYNAMIC_WEAK jest ignorowana w trybie bezpiecznego
wykonania.
- LD_HWCAP_MASK
- (glibc od wersji 2.1) Maska właściwości
sprzętowych.
- LD_KEEPDIR
- (tylko a.out)(libc5) Nie ignoruju katalogu w nazwach ładowanych
bibliotek a.out. Używanie tej opcji nie jest zalecane.
- LD_NOWARN
- (tylko a.out)(libc5) Powstrzymuje ostrzeżenia o bibliotekach a.out
o niekompatybilnych numerach minorowych wersji.
- LD_ORIGIN_PATH
- (glibc od wersji 2.1) Ścieżka, w której znaleziono
program binarny (dla programów bez bitu set-user-ID). Od wersji 2.4
biblioteki glibc LD_ORIGIN_PATH jest ignorowana w trybie
bezpiecznego wykonania.
- LD_POINTER_GUARD
- (glibc od wersji 2.4 do 2.22) Ustawione na 0 powoduje
wyłączenie ochrony wskaźników. Jakakolwiek
inna wartość włącza ochronę
wskaźników, co jest także zachowaniem
domyślnym. Ochrona wskaźników jest mechanizmem
bezpieczeństwa, w którym niektóre wskaźniki do
kodu przechowywanego w zapisywalnej pamięci programu (adresy
powrotu zwrócone przez setjmp(3) lub wskaźniki do
funkcji używane przez różne funkcje wewnętrzne
biblioteki glibc) są w sposób pseudolosowy zmieniane, aby
utrudnić hakerowi przejęcie tych wskaźników i
przeprowadzenie ataków typu przepełnienie bufora lub stosu.
Od glibc 2.23 LD_POINTER_GUARD nie można już
użyć do wyłączenia ochrony
wskaźników, która jest teraz zawsze aktywna.
- LD_PROFILE
- (glibc od wersji 2.1) Nazwa (pojedynczego) obiektu dzielonego
przeznaczonego do profilowania, podane albo jako nazwa
ścieżki, albo nazwa pliku so. Wyjście profilowania
jest dopisywane do pliku o nazwie
"$LD_PROFILE_OUTPUT/$LD_PROFILE.profile".
- LD_PROFILE_OUTPUT
- (glibc od wersji 2.1) Katalog, w którym powinno być zapisane
wyjście LD_PROFILE. Jeśli ta zmienna nie jest
zdefiniowana lub jeśli wartość tej zmiennej jest
pusta, to domyślnym katalogiem jest /var/tmp.
LD_PROFILE_OUTPUT jest ignorowane w trybie bezpiecznego wykonania;
wówczas zawsze używany jest /var/profile.
- LD_SHOW_AUXV
- (glibc od wersji 2.1) Jeśli ta zmienna środowiskowa jest
zdefiniowana (z dowolną wartością),
wyświetla tablicę pomocniczą przekazaną przez
jądro. Od wersji 2.3.5 biblioteki glibc LD_SHOW_AUXV jest
ignorowana w trybie bezpiecznego wykonania.
- LD_TRACE_PRELINKING
- (glibc od wersji 2.4) Jeśli ta zmienna środowiskowa jest
zdefiniowana (z dowolną wartością)
śledzi prekonsolidację obiektu, którego nazwa jest
przypisana do tej zmiennej środowiskowej (ldd(1)
służy do pozyskania listy obiektów, które
mogą być śledzone). Jeśli nazwa
obiektu nie zostanie rozpoznana, to śledzona jest cała
aktywność prekonsolidacji.
- LD_USE_LOAD_BIAS
- Domyślnie (czyli jeśli ta zmienna nie jest zdefiniowana)
programy wykonywalne i prekonsolidowane obiekty dzielone
będą uwzględniały adresy bazowe
obiektów dzielonych, od których zależą, a
(nieprekonsolidowane) programy wykonywalne niezależne od pozycji
(position-independent executable, PIE) i inne obiekty dzielone nie
będą ich uwzględniały. Jeśli
LD_USE_LOAD_BIAS jest zdefiniowana z jakąś
wartością, to zarówno programy wykonywalne, jak i
PIE, będą uwzględniały adresy bazowe.
Jeśli LD_USE_LOAD_BIAS jest zdefiniowana z
wartością 1, to ani programy wykonywalne, ani PIE nie
będą uwzględniały adresów bazowych.
Zmienna ta jest ignorowana w trybie bezpiecznego wykonania.
- LD_VERBOSE
- (glibc od wersji 2.1). Jeśli ustawione na niepusty
łańcuch znaków i jeśli została
ustawiona zmienna środowiskowa LD_TRACE_LOADED_OBJECTS, to
wypisuje informacje o wersjonowaniu symboli programu.
- LD_WARN
- (tylko ELF)(glibc od wersji 2.1.3) Jeśli ustawione na niepusty
łańcuch znaków, to włącza ostrzeganie o
nierozwijalnych symbolach.
- LD_PREFER_MAP_32BIT_EXEC
- (tylko x86-64)(glibc w wersji od 2.23) Zgodnie z przewodnikiem
optymalizacji oprogramowania Intel Silvermont, dla aplikacji 64-bitowych
wydajność przewidywania rozgałęzień
może być zmniejszona, gdy cel gałęzi jest
oddalony o ponad 4GB. Jeśli ta zmienna środowiskowa jest
ustawiona (na dowolną wartość), to
ld.so spróbuje najpierw przypisać flagi
wykonywalności za pomocą flagi MAP_32BIT
mmap(2), a jeśli się to nie powiedzie — bez
tej flagi. Przy okazji: MAP_32BIT przypisze niższe 2GB (nie 4GB)
przestrzeni adresowej. Ponieważ MAP_32BIT redukuje zakres
adresowy dostępny dla losowego rozmieszczania obszarów
pamięci (ang. ASLR - adress space layout randomization), w trybie
bezpiecznego wykonania LD_PREFER_MAP_32BIT_EXEC jest zawsze
wyłączona.
- LDD_ARGV0
- (libc5) argv[0] do użycia przez ldd(1), jeśli
żadne argumenty nie są obecne.
- /lib/ld.so
- Dynamiczny konsolidator/ładowacz a.out
- /lib/ld-linux.so.{1,2}
- Dynamiczny konsolidator/ładowacz ELF
- /etc/ld.so.cache
- Plik zawierający skompilowaną listę katalogów,
w których należy szukać obiektów dzielonych
oraz uporządkowaną listę kandydujących
obiektów dzielonych.
- /etc/ld.so.preload
- Plik zawierający oddzieloną spacjami listę
obiektów dzielonych ELF, które mają być
załadowane przed programem.
- lib*.so*
- obiekty dzielone
Możliwości ld.so dostępne są
tylko dla programów binarnych, skompilowanych przy użyciu libc
w wersji 4.4.3 lub wyższej. Funkcjonalności ELF-a są
dostępne od Linuksa 1.1.52 i libc5.
Niektóre obiekty dzielone są kompilowane z
użyciem specyficznych dla danego sprzętu instrukcji,
które nie muszą istnieć na każdym CPU. Takie
obiektypowinny być instalowane w katalogach, których
nazwy określają wymagane właściwości
sprzętu, na przykład /usr/lib/sse2/. Konsolidator
dynamiczny porównuje nazwy takich katalogów ze sprzętem
maszyny i wybiera najbardziej odpowiednią wersję danego
obiektu dzielonego. Katalogi właściwości sprzętu
mogą tworzyć kaskady, dopuszczając kombinacje cech CPU.
Lista nazw wspieranych właściwości sprzętowych
zależy od CPU. Obecnie rozpoznawane są
następujące nazwy:
- Alpha
- ev4, ev5, ev56, ev6, ev67
- MIPS
- loongson2e, loongson2f, octeon, octeon2
- PowerPC
- 4xxmac, altivec, arch_2_05, arch_2_06, booke, cellbe, dfp, efpdouble,
efpsingle, fpu, ic_snoop, mmu, notb, pa6t, power4, power5, power5+,
power6x, ppc32, ppc601, ppc64, smt, spe, ucache, vsx
- SPARC
- flush, muldiv, stbar, swap, ultra3, v9, v9v, v9v2
- s390
- dfp, eimm, esan3, etf3enh, g5, highgprs, hpage, ldisp, msa, stfle, z900,
z990, z9-109, z10, zarch
- x86 (tylko
32-bitowe)
- acpi, apic, clflush, cmov, cx8, dts, fxsr, ht, i386, i486, i586, i686,
mca, mmx, mtrr, pat, pbe, pge, pn, pse36, sep, ss, sse, sse2, tm
Angielska wersja tej strony pochodzi z wydania 4.05 projektu Linux
man-pages. Opis projektu, informacje dotyczące
zgłaszania błędów, oraz najnowszą
wersję oryginału można znaleźć pod
adresem https://www.kernel.org/doc/man-pages/.
Autorami polskiego tłumaczenia niniejszej strony
podręcznika man są: Przemek Borys (PTM)
<pborys@dione.ids.pl>, Grzegorz Goławski (PTM)
<grzegol@pld.org.pl>, Robert Luberda <robert@debian.org> i
Michał Kułach <michal.kulach@gmail.com>.
Polskie tłumaczenie jest częścią
projektu manpages-pl; uwagi, pomoc, zgłaszanie
błędów na stronie
http://sourceforge.net/projects/manpages-pl/. Jest zgodne z wersją
4.05 oryginału.