Ha kíváncsiak vagyunk a Linux
emuláció működésére,
olvassuk el ezt a szakaszt. Az itt leírtak
leginkább Terry Lambert
(<tlambert@primenet.com>
) FreeBSD chat levelezési lista
címére írt levele nyomán kerülnek
bemutatásra (Az üzenet azonosítója:
<199906020108.SAA07001@usr09.primenet.com>
).
A FreeBSD rendelkezik egy ún. "végrehajtási osztály betöltővel" (execution class loader). Ez lényegében a execve(2) rendszerhívás alatt meghúzódó absztrakciós réteg.
A FreeBSD-nek a #!
karaktersorozat
hatására parancsértelmezők vagy a
hozzájuk tartozó szkriptek
betöltésére utasító
biztonsági betöltő helyett van egy
listája az alkalmas betöltőkről.
A UNIX(R) rendszerek a hagyományok szerint egyetlen betöltővel rendelkeznek, ami először megvizsgálja a betölteni kívánt állomány bűvös számát (ami általában az első 4 vagy 8 byte) és ez alapján eldönti, hogy az adott formátum támogatott-e. Amennyiben ez így van, meghívja a betöltőt.
Ha a bináris típusa nem ismert a rendszer számára, akkor az execve(2) hívás hibával tér vissza, és a parancsértelmező próbálja meg a saját parancsaiként értelmezni.
Eddig ez volt az alapértelmezés, "akármilyen parancsértelmezőnk is volt".
Később az sh(1) kódjába
bekerült egy aprócska okosítás, amivel
megnézte az állomány első két
karakterét, és ha az :\n
volt,
akkor a futtatáshoz maga helyett a csh(1)
parancsértelmezőt hívta meg (ezt
állítólag először a SCO
csinálta).
A FreeBSD viszont végignézi a betöltők
teljes listáját, amiben a sor végén
szerepel egy általános #!
formátumú betöltő. Ez az
állomány futtatásához
használatos értelmezők kódját
keresi, és ha egyet sem sikerül azonosítania,
akkor a /bin/sh
programot indítja
el.
A Linux ABI támogatását a FreeBSD úgy oldja meg, hogy először észleli az ELF bináris bűvös számát (ekkor még nem tesz különbséget a FreeBSD, SolarisTM, Linux vagy más ELF típusú binárisokat használó operációs rendszerek közt).
Ezután az ELF formátum betöltője az ELF állomány megjegyzéseket tároló szakaszában bélyegek (brand) után kutat, ami SVR4 és SolarisTM ELF binárisok esetén nem létezik.
A Linux binárisokat
működésükhöz a brandelf(1)
segítségével Linux
típusúnak kell
megbélyegezni:
#
brandelf -t Linux állomány
Miután ezt megcsináltuk, az ELF
betöltő észre fogja venni az
állomány Linux
típusát.
Mikor az ELF betöltő észleli, hogy az
állomány Linux
típusú, kicseréli egy mutató
értékét a proc
struktúrában. Minden rendszerhívás
ezen a mutatón keresztül érhető el (a
hagyományos UNIX(R) rendszerekben ez a
rendszerhívásokat tartalmazó
sysent[]
struktúratömb).
Emellett a frissen elindított program szoftveres
megszakításait tartalmazó
tömbjéhez beállítja a speciális
jelzések kezelését, valamint a Linux modul
által végzett néhány további
(kisebb) javítást.
A Linux rendszerhívásokat tartalmazó
tömb többek közt tartalmazza a
sysent[]
bejegyzések egy
listáját, amelyek címei a rendszermag Linux
moduljára mutatnak.
Amikor a Linux bináris hív egy
rendszerhívást, a hozzá tartozó
szoftveres megszakítás kódja a
proc
struktúrából a neki
megfelelő rendszerhívás kódját
hivatkozza, így FreeBSD rendszerhívás
belépési pontja helyett a Linuxét kapja
meg.
Ráadásul Linux módban a
különböző állományok
hivatkozásai is
átirányítódnak.
Ez lényegében olyan, mint amit az
állományrendszerek
csatlakoztatásánál a union
beállítás csinál (ami
nem egyezik meg az
unionfs
állományrendszerrel!).
Ilyenkor az állományokat először a
/compat/linux/eredeti-hely
könyvtárában keresi, és
majd ha ott nem találja, csak akkor
kezdi el keresni az
/eredeti-hely
ponton. Ezzel oldhatjuk meg, hogy más binárisok
futtatását igénylő binárisok is
képesek legyenek rendesen működni
(például így az egész linuxos
eszköztár tud futni a Linux ABI-n keresztül).
Egyúttal arra is utal, hogy ha a Linux binárisok
számára nem áll rendelkezésre a
megfelelő bináris, akkor FreeBSD binárisokat is
el tudnak indítani. Ha a uname(1) programot pedig
bemásoljuk a /compat/linux
könyvtáron belülre, akkor a Linux
binárisok képtelenek lesznek megmondani, hogy nem
Linux alatt futnak.
Így lényegében egy Linux magot
találunk a FreeBSD rendszermagjában. A benne
megtalálható különböző
szolgáltatásokat megvalósító
függvények: az állományműveletek,
a virtuális memória kezelése, a
jelzések küldése és System V
típusú folyamatok közti
kommunikáció stb. megegyeznek a FreeBSD és a
Linux hívásai esetén egyaránt.
Egyetlen eltérés, hogy a FreeBSD binárisok a
FreeBSD segédfüggvényein
(glue function), a Linux binárisok pedig a Linux
segédfüggvényein keresztül férnek
hozzájuk (a legelső operációs
rendszerek tulajdonképpen csak a saját
segédfüggvényeiket tartalmazták: a
hívást kezdeményező program
proc
struktúrájában a
függvények dinamikusan beállított
címe helyett egy globális
sysent[]
struktúratömbben
tárolták a meghívható
függvényeket).
Melyik közülük a FreeBSD natív ABI-ja? Ez teljesen lényegtelen. Alapvetően az egyetlen különbség csupán annyi (pillanatnyilag, de ez a jövőben még változhat, valószínűleg hamarosan), hogy a FreeBSD segédfüggvényei statikusan megtalálhatóak a rendszermagban, míg a Linux segédfüggvényei egyaránt elérhetőek modulból vagy statikus linkeléssel.
Na igen, de akkor ez most emuláció? Nem. Ez egy ABI, nem emuláció. Itt szó sincs emulátorról (ahogy szimulátorról sincs).
De akkor mégis miért hívják ezt sokszor "Linux emulációnak"? Hát hogy nehezebb legyen eladni a FreeBSD-t! Komolyra fordítva a szót: ennek a kezdeti változata akkoriban született meg, amikor erre még nem volt rendes szó. Nem mondhattuk, hogy a FreeBSD befordítás vagy egy modul betöltése nélkül képes lett volna Linux binárisokat futtatni, ezért valamilyen módon meg kellett neveznünk az ilyenkor betöltött kódot - ebből lett "a Linux emulátor".
Ha kérdése van a FreeBSD-vel kapcsolatban, a
következő címre írhat (angolul):
<questions@FreeBSD.org>.
Ha ezzel a dokumentummal kapcsolatban van kérdése, kérjük erre a címre írjon:
<gabor@FreeBSD.org>.