AIX und Run-Time Linking

Fast alle heutigen Programme unter AIX sind dynamisch gelinkt, d.h. notwendige Bibliotheken werden zur Laufzeit geladen und gebunden (Run-Time Linking). Doch woher weiß ein Programm welche Bibliotheken benötigt werden und in welchem Verzeichnis diese zu finden sind? Was kann man tun, falls eine Bibliothek nicht automatisch gefunden wird? Welche Bedeutung haben die Variablen LIBPATH und LD_LIBRARY_PATH?

Ein kleines C-Programm

Um diese Fragen genauer zu beleuchten, verwenden wir das folgende kleine C-Programm:

$ cat hello.c
#include <stdio.h>

int main()
{
        printf("hello world\n");
        return 0;
}

$

Das Programm gibt die Zeile „hello world“ mit Hilfe der Funktion printf aus der Standard-C-Bibliothek (libc.a) aus.

Wir kompilieren das Programm mit Hilfe des GNU C-Compilers (jeder andere C-Compiler ist natürlich auch möglich):

$ gcc -o hello hello.c
$

Und starten das Programm:

$ ./hello
hello world
$

Das Programm gibt, wie erwartet, die Meldung „hello world“ aus. Doch woher weiß das Programm das die Standard-C Bibliothek (libc.a) gelinkt werden muss und wo diese zu finden ist?

Die Loader-Sektion eines ausführbaren Programms

Diese Frage lässt sich mit Hilfe des Kommandos dump beantworten. Das Kommando dump zeigt ausgewählte Teile von Object-Dateien, Archiven (Bibliotheken) und ausführbaren Dateien. Mit der Option „-H“ lässt sich die sogenannte Loader-Sektion anzeigen:

$ dump -H hello
hello:


                        ***Loader Section***
                      Loader Header Information
VERSION#         #SYMtableENT     #RELOCent        LENidSTR
0x00000001       0x0000000b       0x00000026       0x0000008d      


#IMPfilID        OFFidSTR         LENstrTBL        OFFstrTBL
0x00000002       0x000002f0       0x00000039       0x0000037d      



                        ***Import File Strings***
INDEX  PATH                          BASE                MEMBER             
0      /opt/freeware/lib/gcc/powerpc-ibm-aix7.2.0.0/8.1.0:/opt/freeware/lib/gcc/powerpc-ibm-aix7.2.0.0/8.1.0/../../..:/usr/lib:/lib                                        
1                                    libc.a              shr.o              
$

(Bei 64-bit Dateien muss die Option „-X64“ oder „-Xany“ zusätzlich verwendet werden.)

Unter dem Index 0 ist der Library Suchpfad hinterlegt, wie bei der PATH Variablen der Shell sind Verzeichnisse mit Doppelpunkten getrennt. Benötigte Bibliotheken werden in den aufgelisteten Verzeichnissen gesucht. Sobald eine Bibliothek gefunden ist, werden die weiteren Verzeichnisse nicht mehr durchsucht. Das Betriebssystem AIX verwendet standardmäßig den Pfad „/usr/lib:/lib“, die weiteren Pfade wurden vom GNU C-Compiler hinzugefügt. Im Anschluß an den Library Suchpfad werden die benötigten Bibliotheken aufgelistet, in unserem Fall die Standard-C Bibliothek libc.a unter dem Index 1.

Möchte man wissen in welchem Verzeichnis eine Bibliothek gefunden wird (es könnte ja, in mehr als einem Verzeichnis, eine Bibliothek mit Namen libc.a existieren), kann man das Kommando ldd verwenden:

$ ldd hello
hello needs:
         /usr/lib/libc.a(shr.o)
         /unix
         /usr/lib/libcrypt.a(shr.o)
$

Die libc.a wird also unter /usr/lib gefunden, und hängt selbst von weiteren Bibliotheken ab, daher die zwei weiteren Einträge.

Bedeutung von LIBPATH und LD_LIBRARY_PATH

Um zu zeigen was passiert, wenn über den Library Suchpfad nicht alle benötigten Bibliotheken gefunden werden, kompilieren wir unser C-Programm noch einmal, allerdings mit etwas anderen Optionen:

$ gcc -o hello -Wl,-blibpath:- hello.c
$

Die Option „-Wl,-blibpath:-„ sorgt dafür das jetzt als Library Suchpfad ein „“ in das erzeugte Programm eingetragen wird:

$ dump -H hello
hello:


                        ***Loader Section***
                      Loader Header Information
VERSION#         #SYMtableENT     #RELOCent        LENidSTR
0x00000001       0x0000000b       0x00000026       0x00000012      


#IMPfilID        OFFidSTR         LENstrTBL        OFFstrTBL
0x00000002       0x000002f0       0x00000039       0x00000302      


                        ***Import File Strings***
INDEX  PATH                          BASE                MEMBER             
0      -                                                                    
1                                    libc.a              shr.o              
$

Damit kann das Programm zur Laufzeit die Standard-C Bibliothek nicht mehr finden und der Aufruf des Programms führt zu der folgenden Fehlermeldung:

$ ./hello
exec(): 0509-036 Cannot load program ./hello because of the following errors:
        0509-150   Dependent module libc.a(shr.o) could not be loaded.
        0509-022 Cannot load module libc.a(shr.o).
        0509-026 System error: A file or directory in the path name does not exist.
$

Diese Meldung hat vermutlich schon jeder einmal gesehen, wenn benötigte Bibliotheken für ein aufgerufenes Programm fehlen. In solchen Fällen kann ein zusätzlicher Library-Suchpfad in Form einer Umgebungs-Variable gesetzt werden. Unter AIX gibt es hierzu die beiden Variablen LIBPATH und LD_LIBRARY_PATH.

Die libc.a ist, wie wir oben gesehen haben, unter /usr/lib zu finden. Wir setzen daher zunächst LIBPATH auf /usr/lib und starten unser Programm erneut:

$ LIBPATH=/usr/lib ./hello
hello world
$

Die libc.a wird offensichtlich gefunden und das Programm arbeitet wieder korrekt. Man kann natürlich auch die Variable exportieren, dann  muss sie nicht explizit vor dem Kommando angegeben werden.

Als nächstes setzen wir LD_LIBRARY_PATH auf /usr/lib und starten wieder unser Programm:

$ LD_LIBRARY_PATH=/usr/lib ./hello
hello world
$

Auch hier wird libc.a gefunden und das Programm arbeitet wieder korrekt.

Wir untersuchen noch, was passiert wenn beide Variablen gesetzt sind.

Wir setzen LD_LIBRARY_PATH auf /usr/lib und LIBPATH auf das nicht existierende Verzeichnis /dummy:

$ LD_LIBRARY_PATH=/usr/lib LIBPATH=/dummy ./hello
exec(): 0509-036 Cannot load program ./hello because of the following errors:
        0509-150   Dependent module libc.a(shr.o) could not be loaded.
        0509-022 Cannot load module libc.a(shr.o).
        0509-026 System error: A file or directory in the path name does not exist.
$

Die libc.a wird nicht mehr gefunden, obwohl LD_LIBRARY_PATH den korrekten Pfad enthält. Offensichtlich hat die Variable LIBPATH höhere Priorität und die Variable LD_LIBRARY_PATH wird ignoriert!

Wir überprüfen dies, indem wir nun LD_LIBRARY_PATH auf /dummy setzen, und LIBPATH auf /usr/lib:

$ LD_LIBRARY_PATH=/dummy LIBPATH=/usr/lib ./hello
hello world
$

Das Programm arbeitet wieder korrekt.

Fazit

Bibliotheken werden also in der folgenden Reihenfolge gesucht:

  1. Durchsuchen des Library-Suchpfads aus der Loader-Sektion des ausführbaren Programms.
  2. Falls LIBPATH gesetzt ist, durchsuchen der Pfade aus LIBPATH.
  3. Nur falls LIBPATH nicht gesetzt ist: durchsuchen der Pfade aus LD_LIBRARY_PATH (falls gesetzt).

Ist sowohl LIBPATH, wie auch LD_LIBRARY_PATH gesetzt, dann wird LD_LIBRARY_PATH ignoriert.

 

Zurück zu AIX