Hier wordt beschreven hoe de Linux® binaire compatibiliteit
werkt. Het meeste van wat nu volgt is sterk gebaseerd op een
e-mailbericht van Terry Lambert
<tlambert@primenet.com>
aan FreeBSD babbel mailinglijst (Message ID:
<199906020108.SAA07001@usr09.primenet.com>
).
FreeBSD heeft een abstractie met de naam “execution class loader”. Dit is een wig in de systeemaanroep execve(2).
Wat er gebeurt is dat FreeBSD een lijst van loaders heeft, in
plaats van een enkele loader die terugvalt op de
#!
loader voor het draaien van elke
shellinterpreter of shellscript.
Vroeger onderzocht de enige loader op het UNIX® platform het magische getal (in het algemeen de eerste 4 of 8 bytes van het bestand) om te zien of het een binary was die het systeem kende en als dat het geval was laadde het de binaire loader.
Als het niet het binaire type voor het systeem was, faalde de aanroep naar execve(2) en probeerde de shell het als shellopdrachten uit te voeren.
Deze aanname was een standaard voor “wat de huidige shell ook is.”
Later werd er een hack gemaakt voor sh(1) om de eerste
twee tekens te onderzoeken en als die bestonden uit
:\n
voerde het in plaats hiervan de
csh(1) shell uit (het idee is dat SCO de hack als eerste
maakte).
Wat FreeBSD nu doet is door een lijst van loaders gaan
met een generieke #!
loader die kennis heeft
van interpreters in de zin van de karakters die volgen op de
volgende witruimte tot de laatste, met uiteindelijk een
terugval op /bin/sh
.
Voor Linux® ABI-ondersteuning ziet FreeBSD het magische getal als een ELF-binary (het maakt op dit punt geen onderscheid tussen FreeBSD, Solaris™, Linux® of elk ander besturingssysteem dat een ELF-beeldtype heeft).
De ELF loader zoekt naar een gespecialiseerd merk, dat een commentaargedeelte in het ELF-beeld is en dat niet aanwezig is in SVR4/Solaris™ ELF-binairen.
Om Linux®-binairen werkend te krijgen, moeten ze
gemerkt worden als het type
Linux
met brandelf(1):
#
brandelf -t Linux bestand
Als dit gedaan is, ziet de ELF loader het
Linux
-merk in het bestand.
Als de ELF loader het Linux
-merk
tegenkomt, verplaatst de loader een pointer in de
proc
-structuur. Alle systeemaanroepen
worden met deze pointer geïndexeerd (in een traditioneel
UNIX® systeem is dit de
sysent[]
-structuurarray, die de
systeemaanroepen bevat). Ook wordt het proces gemerkt voor
speciale behandeling door de valstrikvector van de
signaal-trampolinecode samen met nog meer (kleine) aanpassingen
die door de Linux® kernelmodule worden afgehandeld.
De Linux® kernelmodule bevat naast andere dingen een lijst
van sysent[]
-ingangen waarvan de adressen
in de kernelmodule staan.
Als een systeemaanroep door de Linux®-binary wordt aangeroepen, verwijdert de valstrikcode de referentie aan de functiepointer van de systeemaanroep en geeft die de ingangspunten van de systeemaanroep van Linux® en niet van FreeBSD.
Verder reroot de Linux®-modus
dynamisch lookups. Dit is wat de optie union
(niet het unionfs
bestandssysteemtype!) voor het aankoppelen van bestandssystemen
effectief doet. Eerst wordt een poging gedaan om het bestand
in de map
/compat/linux/origineel-pad
op te zoeken en vervolgens alleen als dat
mislukt, wordt het bestand in
/origineel-pad
opgezocht. Dit zorgt ervoor dat binairen die andere binairen
nodig hebben kunnen draaien (zo kan bijvoorbeeld de
Linux®-gereedschapskist geheel onder Linux® ABI-ondersteuning
draaien). Dit betekent ook dat Linux®-binairen FreeBSD-binairen
kunnen laden en draaien als er geen overeenkomende
Linux®-binairen zijn en dat er een uname(1)-opdracht in
de mappenstructuur /compat/linux
gezet kan
worden om er zeker van te zijn dat Linux®-binairen niet kunnen
weten dat ze niet op Linux® draaien.
Effectief bevindt er zich een Linux®-kernel in de
FreeBSD-kernel. De verschillende onderliggende functies die alle
functies implementeren die de kernel aanbiedt, zijn dezelfde
tabelingangen voor de systeemaanroepen van FreeBSD als van
Linux®: bestandssysteembewerkingen, bewerkingen op het
virtuële geheugen, signaalaflevering, System V IPC,
enzovoort. Het enige verschil is dat FreeBSD-binairen de
lijm functies voor FreeBSD krijgen en dat de
Linux®-binairen de lijm-functies voor
Linux® krijgen (de meeste oudere besturingssystemen hadden
alleen hun eigen lijm-functies: adressen
van functies die in een statische globale
sysent[]
structuurarray werden opgeslagen,
in plaats van adressen van functies waarvan dynamisch een
geïnitialiseerde pointer wordt verwijderd in de
proc
-structuur van het proces dat de aanroep
doet).
Welke is de eigenlijke FreeBSD ABI? Dat maakt niet uit. Eigenlijk is het enige verschil dat (op dit moment; dit kan eenvoudig veranderen in een toekomstige uitgave, en dat gebeurt waarschijnlijk na deze uitgave) de lijm-functies van FreeBSD statisch gelinkt zijn in de kernel en dat de lijm-functies van Linux® zowel statisch gelinkt kunnen worden als dat ze door een kernelmodule worden benaderd.
Maar is dit nu echt emulatie? Nee. Het is een ABI-implementatie, geen emulatie. Er is geen emulator (of simulator, om de volgende vraag voor te zijn) bij betrokken.
Dus waarom wordt het dan soms “Linux®-emulatie” genoemd? Om het moeilijk te maken om FreeBSD te verkopen! Serieus, het is zo omdat de historische implementatie in een tijd werd gedaan toen er echt geen ander woord was om te beschrijven wat er aan de hand was, om te zeggen dat FreeBSD Linux®-binairen draaide was niet waar als de code niet in de kernel gecompileerd werd of als een module geladen werd en er moest een woord zijn voor hetgeen geladen werd. Vandaar “de Linux®-emulator”.
All FreeBSD documents are available for download at http://ftp.FreeBSD.org/pub/FreeBSD/doc/
Questions that are not answered by the
documentation may be
sent to <freebsd-questions@FreeBSD.org>.
Send questions about this document to <freebsd-doc@FreeBSD.org>.