plucky (3) dlclose.3.gz

Provided by: manpages-pl-dev_4.25.1-1_all bug

NAZWA

       dlclose, dlopen, dlmopen - otwiera i zamyka obiekt dzielony

BIBLIOTEKA

       Biblioteka konsolidacji dynamicznej (libdl, -ldl)

SKŁADNIA

       #include <dlfcn.h>

       void *dlopen(const char *filename, int flags);
       int dlclose(void *handle);

       #define _GNU_SOURCE
       #include <dlfcn.h>

       void *dlmopen(Lmid_t lmid, const char *filename, int flags);

OPIS

   dlopen()
       Funkcja  dlopen()  ładuje  dynamiczny  obiekt  dzielony  (bibliotekę dzieloną) pliku, o nazwie zawartej w
       zakończonym znakiem nul łańcuchu filename i zwraca nieprzezroczysty „uchwyt” dla tego obiektu dzielonego.
       Uchwytu  tego  używa  się  z  innymi  funkcjami z API dlopen, takimi jak dlsym(3), dladdr(3), dlinfo(3) i
       dlclose().

       Jeśli filename wynosi NULL, to zwracany jest uchwyt do głównego programu. Jeśli filename zawiera  ukośnik
       („/”),  to  jest  interpretowana jako (względna lub absolutna) ścieżka. W innych sytuacjach, konsolidator
       dynamiczny szuka obiektu w następujący sposób (więcej szczegółów w podręczniku ld.so(8)):

       •  (tylko ELF) Jeśli wywołujący obiekt (tj. biblioteka współdzielona, lub  plik  wykonywalny,  z  którego
          wywoływane  jest  dlopen())  zawiera znacznik DT_RPATH, natomiast nie zawiera znacznika DT_RUNPATH, to
          przeszukiwane są katalogi wypisane w znaczniku DT_RPATH.

       •  Jeśli, w momencie uruchomienia tego programu,  zdefiniowano  zmienną  środowiskową  LD_LIBRARY_PATH  i
          zawierała  ona listę katalogów rozdzielonych dwukropkiem, to przeszukiwane są te katalogi (ze względów
          bezpieczeństwa, zmienna ta jest ignorowana w przypadku programów z ustawionym  bitem  set-user-ID  lub
          set-group-ID).

       •  (tylko ELF) Jeśli wywołujący obiekt zawiera znacznik DT_RUNPATH, to przeszukiwane są katalogi wypisane
          w tym znaczniku.

       •  Sprawdzany jest plik bufora /etc/ld.so.cache (zarządzany przez ldconfig(8)) pod kątem zawierania wpisu
          dla filename.

       •  Przeszukiwane są katalogi /lib i /usr/lib (w tej kolejności).

       Jeśli  obiekt  określony  w  filename  ma  zależności  od  innych  obiektów  dzielonych,  są  one również
       automatycznie ładowane przez konsolidator dynamiczny, za  pomocą  tych  samych  reguł  (proces  ten  może
       postępować rekurencyjnie, jeśli te obiekty mają z kolei swoje zależności itd.).

       We flags należy podać jedną z dwóch poniższych wartości:

       RTLD_LAZY
              Przeprowadza  leniwe  dowiązanie. Rozwiązuje symbole jedynie wtedy, gdy wykonywany jest kod, który
              się do nich odnosi. Jeśli do danego symbolu nic się nie odniesie, to nie zostanie nigdy rozwiązany
              (leniwe  dowiązanie  jest wykonywane tylko przy odniesieniach do funkcji; odniesienia do zmiennych
              są zawsze bezzwłocznie przypisywane przy ładowaniu obiektu dzielonego). Od glibc  2.1.1,  znacznik
              ten jest przesłaniany przez efekt zmiennej środowiskowej LD_BIND_NOW.

       RTLD_NOW
              Jeśli poda się tę wartość lub zmienna środowiskowa LD_BIND_NOW jest ustawiona na niepusty łańcuch,
              wszystkie niezdefiniowane symbole obiektu dzielonego  są  rozwiązywane  przed  powrotem  dlopen().
              Jeśli nie da się tego wykonać, zwracany jest błąd.

       Ponadto, we flags można zsumować (OR) zero lub więcej z poniższych wartości:

       RTLD_GLOBAL
              Symbole  zdefiniowane  za  pomocą  tego  obiektu  dzielonego zostaną udostępnione do rozwiązywania
              symboli kolejno ładowanych obiektów dzielonych.

       RTLD_LOCAL
              Jest to odwrotność RTLD_GLOBAL, a także wartość domyślna,  jeśli  nie  podano  żadnego  znacznika.
              Symbole zdefiniowane w tym obiekcie dzielonym nie są udostępniane do rozwiązywania symboli kolejno
              ładowanych obiektów dzielonych.

       RTLD_NODELETE (od glibc 2.2)
              Nie odłącza obiektu dzielonego podczas dlclose(). Statyczne i  globalne  zmienne  obiektu  nie  są
              zatem inicjowane ponownie, jeśli obiekt zostanie później przeładowany za pomocą dlopen().

       RTLD_NOLOAD (od glibc 2.2)
              Nie ładuje obiektu dzielonego. Można to wykorzystać do sprawdzenia, czy obiekt jest już rezydentny
              (dlopen() zwróci NULL jeśli nie jest, albo uchwyt obiektu  jeśli  jest).  Znacznik  może  posłużyć
              również  do  dodania  znaczników  do  już  załadowanego obiektu dzielonego. Przykładowo, wcześniej
              załadowany  obiekt  dzielony   ze   znacznikiem   RTLD_LOCAL   może   być   otwarty   ponownie   z
              RTLD_NOLOAD | RTLD_GLOBAL.

       RTLD_DEEPBIND (od glibc 2.3.4)
              Umieszcza dziedzinę przeszukiwania dla symboli, w tym obiekcie dzielonym przed dziedziną globalną.
              Oznacza to, że samodzielny obiekt będzie  preferował  używanie  swoich  symboli,  zamiast  symboli
              globalnych o tej samej nazwie w obiektach, które zostały już załadowane.

       Jeśli  filename  wynosi NULL, to zwracany jest uchwyt do głównego programu. Przy przekazaniu tego uchwytu
       do dlsym(3), powoduje on wyszukiwanie symbolu w głównym  programie,  następnie  we  wszystkich  obiektach
       dzielonych  załadowanych  przy rozruchu programu, a potem we wszystkich obiektach dzielonych załadowanych
       za pomocą dlopen() ze znacznikiem RTLD_GLOBAL.

       Odniesienia symboli w obiekcie dzielonym są rozwiązywane za pomocą (w tej kolejności):  symboli  w  mapie
       linkowań  obiektów załadowanych do głównego programu i jego zależności; symboli w obiektach dzielonych (i
       ich zależności), które były uprzednio otworzone za pomocą dlopen() i znacznika RTLD_GLOBAL;  definicji  w
       samym obiekcie dzielonym (i zależności, które zostały załadowane dla tego obiektu).

       Wszelkie  symbole  globalne  w  pliku  wykonywalnym,  które  zostały  umieszczone  w jego tablicy symboli
       dynamicznych przez ld(1), mogą być użyte również do rozwiązywania  odniesień  w  dynamicznie  załadowanym
       obiekcie  dzielonym.  Symbole  mogą  być  umieszczone  w  tablicy symboli dynamicznych albo ponieważ plik
       wykonywalny  skonsolidowano  z  „-rdynamic”  (lub  synonimicznie:  z  „--export-dynamic”),  co   powoduje
       umieszczenie  wszystkich  symboli  globalnych  pliku wykonywalnego w tablicy symboli dynamicznych, albo z
       powodu  odnotowania  przez  ld(1)  zależności  od  symbolu  w  innym  obiekcie,  podczas   konsolidowania
       statycznego.

       Jeśli  ten  sam obiekt dzielony zostanie powtórnie otworzony za pomocą dlopen(), to zwracany jest ten sam
       uchwyt obiektu. Dynamiczny konsolidator utrzymuje liczniki odniesień  dla  uchwytów  obiektów,  tak  więc
       dynamicznie  załadowany  obiekt  dzielony  nie  jest  dealokowany,  dopóki  dlclose() nie zostanie na nim
       wywołany tak wiele razy, jak udanie wywołano na nim dlopen(). Konstruktory  (zob.  niżej)  są  wywoływane
       tylko wtedy, gdy obiekt jest faktycznie ładowany do pamięci (tj. gdy licznik odniesień wzrośnie do 1).

       Kolejne  wywołanie dlopen(), ładujące ten sam obiekt za pomocą RTLD_NOW, może wymusić rozwiązanie symbolu
       dla obiektu dzielonego wcześniej załadowanego za pomocą RTLD_LAZY. Podobnie, obiekt uprzednio  załadowany
       za pomocą RTLD_LOCAL może awansować na RTLD_GLOBAL w kolejnym wywołaniu dlopen().

       Jeśli dlopen() z jakiegoś powodu zawiedzie, zwróci NULL.

   dlmopen()
       Funkcja  ta  wykonuje  te  same  zadania co dlopen() — argumenty filename i flags oraz wartości zwraca są
       takie same, z wyjątkiem różnic opisanych niżej.

       Funkcja dlmopen() różni się od dlopen() głównie tym, że akceptuje dodatkowy argument, lmid, który określa
       listę  map  linkowań  (link-map)  (do  której  można odnosić się również jako namespace), w której obiekt
       dzielony powinien być załadowany (dla porównania, dlopen() dodaje dynamicznie ładowany obiekt dzielony do
       tej  samej  przestrzeni  nazw,  jak  obiekt  dzielony,  z  którego  wywołano  dlopen()).  Typ Lmid_t jest
       nieprzezroczystym uchwytem odnoszącym się do tej przestrzeni nazw.

       Argument lmid jest albo identyfikatorem istniejącej przestrzeni nazw  (który  można  pozyskać  za  pomocą
       żądania RTLD_DI_LMID dlinfo(3)) lub jedną z następujących wartości specjalnych:

       LM_ID_BASE
              Ładuje obiekt dzielony w pierwotnej przestrzeni nazw (tj. w przestrzeni nazw aplikacji).

       LM_ID_NEWLM
              Tworzy  nową  przestrzeń  nazw  i  ładuje  w  niej  obiekt  dzielony.  Obiekt  musi być prawidłowo
              skonsolidowany do odniesień wszystkich innych obiektów dzielonych  jakich  wymaga,  ponieważ  nowa
              przestrzeń nazw jest początkowo pusta.

       Jeśli filename wynosi NULL, to jedyną dopuszczalną wartością lmid jest LM_ID_BASE.

   dlclose()
       Funkcja  dlclose()  zmniejsza  licznik odniesień na dynamicznie załadowanych obiektach, do których odnosi
       się handle.

       Jeśli licznik odniesień obiektu spadnie do zera, a żadne symbole w tym obiekcie  nie  są  wymagane  przez
       inne  obiekty, obiekt ten jest odłączany po pierwszym wywołaniu dowolnych destruktorów zdefiniowanych dla
       obiektu (symbole w obiekcie mogą być wymagane przez inny obiekt, ponieważ  otworzono  go  ze  znacznikiem
       RTLD_GLOBAL, a jeden z jego symboli umożliwił relokację w innym obiekcie).

       Wszystkie  obiekty  dzielone  załadowane  automatycznie,  gdy dlopen() przywołano na obiekcie, do którego
       odnosi się handle, są rekurencyjnie zamykane w ten sam sposób.

       Pomyślny powrót z dlclose() nie gwarantuje, że symbole powiązane  z  handle  są  usunięte  z  przestrzeni
       adresowej  wywołującego.  Oprócz  odniesień  wynikających  z bezpośrednich wywołań dlopen(), mogły zostać
       niebezpośrednio załadowane obiekty dzielone (i policzone odniesienia), ze względu na zależności w  innych
       obiektach  dzielonych.  Tylko  gdy  wszystkie  odniesienia  zostały  uwolnione,  obiekt dzielony może być
       usunięty z przestrzeni adresowej.

WARTOŚĆ ZWRACANA

       W przypadku powodzenia, dlopen() i dlmopen() zwracają uchwyt do ładowanego obiektu, niebędący NULL-em.  W
       razie  wystąpienia  błędu  (nie można znaleźć pliku, nie był odczytywalny, miał zły format lub spowodował
       błędy przy załadowaniu) funkcje te zwracają NULL.

       W przypadku powodzenia, dlclose() zwraca 0; w razie wystąpienia błędu, zwraca wartość niezerową.

       Błędy z opisywanych funkcji można diagnozować za pomocą dlerror(3).

ATRYBUTY

       Informacje o pojęciach używanych w tym rozdziale można znaleźć w podręczniku attributes(7).

       ┌───────────────────────────────────────────────────────────────┬────────────────────────┬───────────────┐
       │InterfejsAtrybutWartość       │
       ├───────────────────────────────────────────────────────────────┼────────────────────────┼───────────────┤
       │dlopen(), dlmopen(), dlclose()                                 │ Bezpieczeństwo wątkowe │ MT-bezpieczne │
       └───────────────────────────────────────────────────────────────┴────────────────────────┴───────────────┘

STANDARDY

       dlopen()
       dlclose()
              POSIX.1-2008.

       dlmopen()
       RTLD_NOLOAD
       RTLD_NODELETE
              GNU.

       RTLD_DEEPBIND
              Solaris.

HISTORIA

       dlopen()
       dlclose()
              glibc 2.0.  POSIX.1-2001.

       dlmopen()
              glibc 2.3.4.

UWAGI

   dlmopen() i przestrzenie nazw
       Lista  map  linków  (link-map)  definiuje  izolowaną  przestrzeń  nazw  do  rozwiązywania  symboli  przez
       konsolidator dynamiczny. Wewnątrz przestrzeni nazw, zależny obiekt dzielony jest niebezpośrednio ładowany
       zgodnie ze zwykłymi regułami, a odniesienia do symboli  są  podobnie  rozwiązywane  zgodnie  ze  zwykłymi
       regułami,  lecz  rozwiązywanie to jest ograniczone do definicji zapewnionych przez obiekty, które zostały
       (bezpośrednio lub niebezpośrednio) załadowane do tej przestrzeni nazw.

       Funkcja dlmopen() pozwala na izolację załadowań obiektów — możliwość załadowania  obiektu  dzielonego  do
       nowej przestrzeni nazw, bez ujawniania reszcie aplikacji symboli udostępnionych przez nowy obiekt. Proszę
       zauważyć, że użycie znacznika RTLD_LOCAL nie jest wystarczające do  tego  celu,  ponieważ  zapobiega  ono
       udostępnieniu  symboli  obiektu  dzielonego  dla  wszystkich  innych  obiektów  dzielonych.  W niektórych
       przypadkach, zachodzi potrzeba udostępnienia symboli zapewnionych  przez  dynamicznie  załadowany  obiekt
       dzielony  dla  (podzbioru) innych obiektów dzielonych, bez ujawniania tych symboli całej aplikacji. Można
       to uzyskać za pomocą oddzielnej przestrzeni nazw i znacznika RTLD_GLOBAL.

       Funkcja dlmopen() może służyć również  do  zapewnienia  lepszej  izolacji,  niż  znacznik  RTLD_LOCAL.  W
       szczególności, obiekty dzielone załadowane za pomocą RTLD_LOCAL mogą być awansowane do RTLD_GLOBAL, jeśli
       są zależnościami innego obiektu dzielonego załadowanego  ze  znacznikiem  RTLD_GLOBAL.  Z  tego  względu,
       RTLD_LOCAL  jest niewystarczające do izolowania załadowanego obiektu dzielonego, z wyjątkiem (nieczęstej)
       sytuacji, gdy ma się całkowitą kontrolę nad wszystkich zależnościami obiektu dzielonego.

       Możliwe zastosowania dlmopen() to wtyczki, gdzie autor struktury ładowania wtyczek nie może ufać  autorom
       wtyczek  i  nie  chce, aby jakiekolwiek niezdefiniowane symbole ze struktury wtyczek były rozwiązywane do
       symboli wtyczek. Kolejne zastosowanie, to ładowanie tego samego obiektu więcej niż raz. Bez korzystania z
       dlmopen(),  wymagałoby  to utworzenia odrębnej kopii pliku obiektu dzielonego. Za pomocą dlmopen(), można
       to uzyskać ładując ten sam plik obiektu dzielonego do różnych przestrzeni nazw.

       Implementacja glibc obsługuje co najwyżej 16 przestrzeni nazw.

   Funkcje inicjalizacji i kończenia
       Obiekty dzielone mogą eksportować funkcje za  pomocą  atrybutów  funkcji  __attribute__((constructor))  i
       __attribute__((destructor)).  Funkcje  konstrukcyjne  są  wykonywane  przed  powrotem dlopen(), a funkcje
       destrukcyjne  są  wykonywane  przez  powrotem  dlclose().  Obiekty  dzielone   mogą   eksportować   wiele
       konstruktorów  i  destruktorów,  a  każdej  funkcji  można  przypisać  priorytety, aby określić kolejność
       wykonywania. Więcej informacji na stronach info gcc (w rozdziale „Function attributes”).

       Starszą metodą  uzyskiwania  (częściowo)  tego  samego  wyniku  jest  użycie  dwóch  symboli  specjalnych
       rozpoznawanych  przez  konsolidator: _init i _fini. Jeśli dynamicznie ładowany obiekt dzielony eksportuje
       algorytm nazwany _init(), to kod ten jest wykonywany po załadowaniu obiektu  dzielonego,  przed  powrotem
       dlopen().  Jeśli  obiekt  dzielony eksportuje algorytm nazwany _fini(), to jest on wywoływany zaraz przed
       odłączeniem obiektu. W tym przypadku,  konieczne  jest  unikania  linkowania  wobec  rozruchowych  plików
       systemowych,  które  zawierają  domyślne  wersje  tych  plików;  można to uczynić za pomocą opcji wiersza
       poleceń gcc(1) -nostartfiles.

       Używanie _init i _fini  jest  obecnie  przestarzałe,  na  korzyść  opisanych  wcześniej  konstruktorów  i
       destruktorów,  które  oprócz  innych  zalet,  pozwalają  na  zdefiniowanie  wielu funkcji inicjalizacji i
       kończenia.

       Od glibc 2.2.3, atexit(3) może posłużyć do zarejestrowania  uchwytu  wyjścia,  który  jest  automatycznie
       wywoływany przez odłączaniu obiektu dzielonego.

   Historia
       Funkcje te są częścią API dlopen, wywodzącego się z SunOS.

USTERKI

       Według  stanu  na  glibc 2.24, podanie znacznika RTLD_GLOBAL przy wywoływaniu dlmopen() generuje błąd. Co
       więcej, podanie RTLD_GLOBAL przy  wywoływaniu  dlopen()  powoduje  załamanie  programu  (SIGSEGV),  jeśli
       wywołanie  nastąpiło  z  dowolnego obiektu załadowanego w przestrzeni nazw innej niż pierwotna przestrzeń
       nazw.

PRZYKŁADY

       Poniższy program ładuje bibliotekę matematyczną (glibc), szuka adresu funkcji cos(3) i  wypisuje  cosinus
       liczby 2.0. Pokazano przykład tworzenia i działania programu:

           $ cc dlopen_demo.c -ldl
           $ ./a.out
           -0.416147

   Kod źródłowy programu

       #include <dlfcn.h>
       #include <stdio.h>
       #include <stdlib.h>

       #include <gnu/lib-names.h>  /* Definiuje LIBM_SO (będzie to
                                      łańcuch podobny do "libm.so.6") */
       int
       main(void)
       {
           void *handle;
           double (*cosine)(double);
           char *error;

           handle = dlopen(LIBM_SO, RTLD_LAZY);
           if (!handle) {
               fprintf(stderr, "%s\n", dlerror());
               exit(EXIT_FAILURE);
           }

           dlerror();    /* Czyści ewentualne istniejące błędy */

           cosine = (double (*)(double)) dlsym(handle, "cos");

           /* Zgodnie ze standardem ISO C, rzutowanie pomiędzy wskaźnikami
              funkcji a 'void *', jak poniżej, daje niezdefiniowany wynik.
              POSIX.1-2001 i POSIX.1-2008 akceptują ten stan rzeczy i proponują
              następujące obejście problemu:

                  *(void **) (&cosine) = dlsym(handle, "cos");

              To (niezgrabne) rzutowanie jest zgodne ze standem ISO C i uniknie
              ostrzeżeń kompilatora.

              2013 Technical Corrigendum 1 do POSIX.1-2008 poprawia stan rzeczy,
              wymagając od zgodnych implementacji obsługi rzutowań 'void *'
              do wskaźnika funkcji. Tym niemniej, niektóre kompilatory (np. gcc
              z opcją '-pedantic') mogą narzekać na rzutowanie użyte
              w tym programie. */

           error = dlerror();
           if (error != NULL) {
               fprintf(stderr, "%s\n", error);
               exit(EXIT_FAILURE);
           }

           printf("%f\n", (*cosine)(2.0));
           dlclose(handle);
           exit(EXIT_SUCCESS);
       }

ZOBACZ TAKŻE

       ld(1),  ldd(1),  pldd(1),  dl_iterate_phdr(3), dladdr(3), dlerror(3), dlinfo(3), dlsym(3), rtld-audit(7),
       ld.so(8), ldconfig(8)

       strony info gcc, strony info ld

TŁUMACZENIE

       Autorami polskiego tłumaczenia niniejszej strony podręcznika  są:  Przemek  Borys  <pborys@dione.ids.pl>,
       Andrzej Krzysztofowicz <ankry@green.mf.pg.gda.pl> i Michał Kułach <michal.kulach@gmail.com>

       Niniejsze  tłumaczenie  jest  wolną  dokumentacją.  Bliższe informacje o warunkach licencji można uzyskać
       zapoznając się z GNU General Public License w wersji  3  ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩  lub
       nowszej. Nie przyjmuje się ŻADNEJ ODPOWIEDZIALNOŚCI.

       Błędy  w  tłumaczeniu  strony  podręcznika  prosimy  zgłaszać  na  adres  listy dyskusyjnej ⟨manpages-pl-
       list@lists.sourceforge.net⟩.