11.7. Weiterführende Themen

Wenn Sie sich fragen, wie die Linux-Binärkompatibilität unter FreeBSD realisiert wurde, sollten Sie diesen Abschnitt lesen. Der Großteil der folgenden Informationen stammt aus einer E-Mail, die von Terry Lambert () an die FreeBSD-Chat-Mailingliste () geschrieben wurde (Message ID: <199906020108.SAA07001@usr09.primenet.com>).

11.7.1. Wie funktioniert es?

FreeBSD verfügt über eine “execution class loader” genannte Abstraktion. Dabei handelt es sich um einen Eingriff in den execve(2) Systemaufruf.

FreeBSD verfügt über eine Liste von Ladern, anstelle eines einzigen, auf #! zurückgreifenden Laders, um Shell-Interpreter oder Shell-Skripte auszuführen.

Historisch gesehen untersuchte der einzige, auf UNIX-Plattformen vorhandene Lader die "magische Zahl" (in der Regel die ersten 4 oder 8 Bytes der Datei), um festzustellen, ob der Binärtyp dem System bekannt war. War dies der Fall, wurde der Binärlader aufgerufen.

Wenn es sich nicht um den zum System gehörigen Binärtyp handelte, gab execve(2) einen Fehler zurück, und die Shell versuchte stattdessen, die Datei als Shell-Befehl auszuführen.

Dabei wurde als Standardeinstellung “was auch immer die aktuelle Shell ist” festgelegt.

Später wurde ein Hack in sh(1) eingefügt, der die zwei ersten Zeichen untersuchte. Wenn diese :\n entsprachen, wurde stattdessen die csh(1)-Shell aufgerufen (wir glauben, dass dies zuerst von SCO umgesetzt wurde).

FreeBSD versucht heute eine Liste von Ladern, unter denen sich ein allgemeiner Lader für Interpreter befindet. Der auszuführende Interpreter wird im ersten, durch Leerzeichen getrennten Feld, der #!-Zeile angegeben. Lässt sich der Interpreter nicht ermitteln, wird auf /bin/sh zurückgegriffen.

Für die Linux ABI-Unterstützung erkennt FreeBSD die magische Zahl als ELF-Binärdatei (Zu diesem Zeitpunkt wird nicht zwischen FreeBSD, Solaris™, Linux oder anderen Systemen unterschieden, die über ELF-Binärdateien verfügen.).

Der ELF-Lader sucht nach einer speziellen Kennzeichnung, die aus einem Kommentarabschnitt in der ELF-Datei besteht, und die in SVR4/Solaris ELF Binärdateien nicht vorhanden ist.

Damit Linux-Binärdateien (unter FreeBSD) funktionieren, müssen sie als Linux gekennzeichnet werden, und zwar durch brandelf(1):

# brandelf -t Linux file

Nachdem dies geschehen ist, erkennt der ELF-Lader die Linux-Kennzeichnung der Datei.

Wenn der ELF-Lader die Linux-Kennzeichnung sieht, wird ein Zeiger in der proc-Struktur ersetzt. Alle Systemaufrufe werden durch diesen Zeiger indiziert (in einem traditionellen UNIX® System wäre das ein sysent[]-Strukturfeld, das die Systemaufrufe enthält). Der Prozess wird weiterhin speziell gekennzeichnet, so dass der Trap-vector im Signal-trampoline-code eine spezielle Behandlung erfährt und das Linux-Kernelmodul verschiedene kleinere Korrekturen vornehmen kann.

Der Linux-Systemaufrufvektor enthält neben anderen Dingen eine Liste der sysent[]-Einträge, deren Adressen sich im Kernelmodul befinden.

Wenn ein Linux-Programm einen Systemaufruf ausführt, dereferenziert die Trap-Behandlungsroutine den Zeiger auf die Eintrittspunkte für die Systemaufrufe und erhält damit die Linux-Eintrittspunkte und nicht die FreeBSD-Eintrittspunkte.

Zusätzlich verändert der Linuxmodus die Systempfade dynamisch; genauso, wie dies die Option union beim Einbinden von Dateisystemen macht (Achtung: nicht das Dateisystem unionfs!). Zuerst wird die Datei im Verzeichnis /compat/linux/Originalpfad gesucht, danach, wenn sie dort nicht gefunden wurde, wird sie im FreeBSD-Verzeichnis /Originalpfad gesucht. Dadurch wird sichergestellt, dass Binärdateien, die zur Ausführung andere Binärdateien benötigen, ausgeführt werden können (so dass alle Linux-Werkzeuge unter der ABI laufen). Dies bedeutet auch, dass Linux-Binärdateien FreeBSD-Binärdateien laden und ausführen können, wenn keine passenden Linux-Binärdateien vorhanden sind. Ein in /compat/linux plaziertes uname(1) kann damit Linux-Programmen vorgaukeln, dass sie auf einem Linux-System laufen.

Im Endeffekt gibt es einen Linux-Kernel innerhalb des FreeBSD-Kernels. Die Sprungtabellen für Linux- beziehungsweise FreeBSD-Systemaufrufe verweisen allerdings auf dieselben Funktionen, die Kerneldienste wie Dateisystemoperationen, Operationen für den virtuellen Speicher, Signalübermittlung und System V IPC bereitstellen, Der einzige Unterschied ist, dass Binärdateien unter FreeBSD FreeBSD-glue-Funktionen verwenden. Linux-Binärdateien hingegen verwenden die Linux-glue-Funktionen. Die meisten älteren Betriebssysteme hatten ihre eigenen glue-Funktionen: Funktionsadressen in einem globalen, statischen sysent[] Strukturfeld an Stelle von Funktionsadressen, die durch einen dynamisch initialisierten Zeiger aus der proc Struktur, die den Aufruf gemacht hatte, dereferenziert wurden.

Welche ist die echte FreeBSD-ABI? Das spielt keine Rolle. Grundsätzlich ist der einzige Unterschied (zurzeit ist das so; dies könnte sich in zukünftigen Versionen leicht ändern und wird sich wahrscheinlich auch ändern), dass die FreeBSD-glue-Funktionen statisch in den Kernel gelinkt sind, und dass die Linux-glue-Funktionen statisch gelinkt oder über ein Modul eingebunden werden können.

Ja, aber ist das wirkliche eine Emulation? Nein. Es ist eine Implementierung eines ABIs, keine Emulation. Es ist kein Emulator (oder Simulator, um der nächsten Frage zuvorzukommen) beteiligt.

Warum wird es manchmal “Linux-Emulation” genannt? Um es schwerer zu machen, FreeBSD zu verkaufen. Wirklich, das kommt daher, weil dies zu einer Zeit implemtiert wurde, in der es kein anderes Wort (als Emulation) gab, das beschrieb, was vor sich ging. Wenn der Kernel nicht entsprechend konfiguriert wurde oder das Modul geladen wurde, war es falsch zu behaupten, FreeBSD würde Linux-Binärprogramme ausführen. Man benötigte ein Wort, das beschrieb, was da geladen wurde – daher “Der Linux-Emulator”.

Wenn Sie Fragen zu FreeBSD haben, schicken Sie eine E-Mail an <de-bsd-questions@de.FreeBSD.org>.
Wenn Sie Fragen zu dieser Dokumentation haben, schicken Sie eine E-Mail an <de-bsd-translators@de.FreeBSD.org>.