Dynamic Shared Object (DSO)

Der Apache-Server ist ein modulares Programm, bei dem der Administrator die Funktionalität des Servers durch die Auswahl von Modulen zusammenstellen kann. Die Module können dann beim Aufbau des Servers statisch zur binären Datei httpd kompiliert werden. Alternativ können Module als Dynamic Shared Objects (DSOs) kompiliert werden, die neben der binären Hauptdatei httpd vorhanden sind. DSO-Module können beim Aufbau des Servers oder später kompiliert und mit dem Apache Extension Tool (apxs) hinzugefügt werden.

In den folgenden Abschnitten wird beschrieben, wie DSO-Module benutzt werden und welche Theorie dahintersteht.

Implementierung mod_so LoadModule

Die DSO-Unterstützung zum Laden einzelner Apache-Module basiert auf dem Modul mod_so, welches statisch in den Apache-Kern kompiliert werden muss. Neben core ist es das einzige Modul, selbst kein DSO-Objekt sein kann. Alle übrigen Apache-Module können als DSOs kompiliert und die DSO-Fassung in der Konfiguration über die Option --enable-module=shared aktiviert werden (siehe Installation). Nachdem ein Modul als mod_foo.so als DSO kompiliert wurde, kann es mit dem Befehl LoadModule des Moduls mod_so in der Datei httpd.conf beim Serverstart oder Neustart geladen werden.

Mit dem neuen Programm apxs (APache eXtenSion) wird das Erzeugen von DSO-Dateien für Apache-Module (insbesondere für Module von Fremdherstellern) vereinfacht. Mit diesem Programm können DSOs außerhalb des Apache-Quellbaums eingerichtet werden. Die Idee ist einfach: Bei der Installation des Apache werden mit der Prozedur make install die Apache C-Header-Dateien installiert und die plattformabhängigen Compiler- und Linker-Flags für die Einrichtung der DSO-Dateien dem Programm apxs gesetzt. Der Benutzer kann dann mit apxs seine Modulquelldateien kompilieren, ohne sich um die plattformabhängigen Compiler- und Linker-Flags für die DSO-Unterstützung kümmern zu müssen.

Verwendung im Überblick

Es folgt ein kurzer Überblick über die DSO-Eigenschaften des Apache 2.0:

  1. So wird ein mitgeliefertes Apache-Modul (z.B. das Modul mod_foo.c) als eigene DSO mod_foo.so eingerichtet und installiert: $ ./configure --prefix=/path/to/install --enable-foo=shared
    $ make install
  2. So wird ein Apache-Modul (z.B. das Modul mod_foo.c) eines Fremdherstellers als eigene DSO mod_foo.so eingerichtet und installliert: $ ./configure --add-module=module_type:/path/to/3rdparty/mod_foo.c --enable-foo=shared
    $ make install
  3. Konfiguration des Apache für die spätere Installation von DSOs: $ ./configure --enable-so
    $ make install
  4. Einrichtung und Installation eines Apache-Moduls (z.B. mod_foo.c) als eigene DSO mod_foo.so außerhalb des Quellcodebaums des Apache mit apxs: $ cd /path/to/3rdparty
    $ apxs -c mod_foo.c
    $ apxs -i -a -n foo mod_foo.la

Jedes einmal kompilierte DSO-Modul muss mit der Direktive LoadModule in der Datei httpd.conf geladen werden, damit der Apache es aktiviert.

Hintergrund

Bei modernen Unix-Varianten gibt es normalerweise einen komplizierten Mechanismus zum Binden und Laden von Dynamic Shared Objects (DSOs), der die Möglichkeit bietet, ein in einem speziellen Format bereitgestelltes Stück Programmcode, während der Laufzeit in den Adressraum eines ausführbaren Programms zu laden.

Für das Laden gibt es normalerweise zwei Möglichkeiten: Automatisch durch ein Systemprogramm mit der Bezeichnung ld.so beim Starten eines Programms oder manuell aus dem ausführenden Programm heraus über eine Programmschnittstelle zum Unix-Lader über die Systemaufrufe dlopen()/dlsym().

Im ersten Fall werden die DSOs normalerweise als Shared Libraries oder DSO-Bibliotheken bezeichnet und tragen die Bezeichnung libfoo.so oder libfoo.so.1.2. Sie befinden sich in einem Systemverzeichnis (normalerweise im Verzeichnis /usr/lib) und die Verknüpfung zum ausführbaren Programm wird beim Einrichten mit der Option -lfoo für den Linker-Aufruf hergestellt. Dadurch wird die Verknüpfung zum ausführbaren Programm fest codiert, so dass der Unix-Lader beim Programmstart die Datei libfoo.so im Verzeichnis /usr/lib, in mit Linker-Optionen wie -R fest codierten Pfaden oder in über die Umgebungsvariable LD_LIBRARY_PATH angegebenen Pfaden finden kann. Anschließend löst er (noch nicht aufgelöste Symbole) des ausführbaren Programms auf, die sich in der DSO-Datei befinden.

Auf Symbole in ausführbaren Programmen wird in DSOs normalerweise nicht verwiesen (weil es sich um allgemein wiederverwendbaren Code handelt) und daher müssen keine weiteren Auflösungen durchgeführt werden. Das ausführbare Programm muss selbst nichts unternehmen, um die Symbole aus der DSO-Datei benutzen zu können, da die Auflösung vollständig vom Unix-Lader durchgeführt wird. (Der Code zum Aufruf von ld.so ist Bestandteil des Laufzeitstarts und wird in jedes ausführbare Programm eingebunden, das nicht statisch gebunden wurde). Der Vorteil des dynamischen Ladens allgemeinen Bibliothekscodes ist offensichtlich: der Bibliothekscode muss nur einmal in einer Systembibliothek wie libc.so gespeichert werden, was den Festplattenbedarf der Programme reduziert.

Im zweiten Fall spricht man von Shared Objects oder DSO-Dateien, die mit einer beliebigen Dateinamenserweiterung gekennzeichnet werden können (üblich ist die Bezeichnung foo.so). Diese Dateien befinden sich normalerweise in einem programmspezifischen Verzeichnis, ohne dass automatisch eine Verbindung zum ausführbaren Programm hergestellt wird. Vielmehr lädt das Programm die DSO-Datei während der Ausführung mit dlopen() in seinen Adressbereich. Zu diesem Zeitpunkt werden keine Symbole der DSO-Datei für das Programm aufgelöst. Stattdessen löst der Unix-Lader alle (noch nicht aufgelösten) Symbole aus der DSO-Datei, die zu den exportierten Symbolen des Programms und den bereits geladenen DSO-Bibliotheken gehören (insbesondere aus der allgegenwärtigen libc.so) automatisch auf. Auf diese Weise erhält das DSO-Objekt Kenntnis von den Symbolen des Programms, als wäre es zuvor statisch mit ihm gebunden worden.

Um die Vorteile der API des DSO-Objekts nutzen können, muss das Programm schließlich noch die speziellen Symbole aus der DSO-Datei mit der Funktion dlsym() für die spätere Verwendung auflösen. Anders ausgedrückt, muss das ausführbare Programm jedes benötigte Symbol manuell auflösen, um es benutzen zu können. Der Vorteil einer solchen Vorgehensweise liegt darin, dass optionale Programmteile solange nicht geladen werden müssen (und auch keinen Speicherplatz belegen), wie sie vom Programm nicht benötigt werden. Wenn Sie benötigt werden, können sie dynamisch geladen werden, um die Grundfunktionalität des Programms zu erweitern.

Dieser DSO-Mechanismus mag recht einfach erscheinen, ein Schritt ist jedoch schwierig, nämlich das Auflösen der Symbole aus dem ausführbaren Programm für das DSO-Objekt, wenn die DSO-Datei ein Programm erweitert (die zweite Variante). Dieses "reversive Auflösen" der DSO-Symbole aus einem ausführbaren Programm widerspricht dem Bibliotheksdesign (wonach die Bibliothek nichts von den Programmen weiß, von denen sie benutzt wird). Darüber hinaus ist es weder unter allen Betriebssystemen durchführbar noch standardisiert. In der Praxis werden die globalen Symbole des ausführbaren Programms häufig nicht reexportiert und stehen daher für ein DSO-Objekt nicht zur Verfügung. Das Hauptproblem besteht darin, den Linker zu zwingen, alle globalen Symbole zu exportieren, wenn der DSO-Mechanismus für die Erweiterung eines Programms während der Ausführungszeit benutzt werden soll.

In der Regel werden die DSO-Bibliotheken benutzt, weil sie dem entsprechen, wofür der DSO-Mechanismus entwickelt wurde und weshalb er für fast alle Arten von Bibliotheken des Betriebssystems benutzt wird. Die Verwendung von DSO-Dateien zur Erweiterung eines Programms wird dagegen nicht häufig benutzt.

Seit 1998 gibt es nur wenige Software-Pakete, die den DSO-Mechanismus für die Erweiterung der Programmfunktionalität während der Laufzeit benutzen: Perl 5 (über seinen XS-Mechanismus und das DynaLoader-Modul), Netscape Server, usw. Seit der Version 1.3 gehört auch der Apache dazu, weil er bereits ein Modulkonzept zur Erweiterung der Funktionalität und intern eine ähnliche Herangehensweise zum Einbinden externer Module in die Kernfunktionalität des Apache verwendet. Der Apache ist daher prädestiniert für den Einsatz des DSO-Mechanismus zum Laden der Module während der Laufzeit.

Pro und Kontra

Die oben beschriebenen DSO-Eigenschaften haben folgende Vorteile:

Der DSO-Mechanismus hat folgende Nachteile: