Szerelőbetét
A programozásban az inline assembler a fordító azon képességére utal, hogy az assemblerben írt alacsony szintű kódot magas szintű nyelven , például C vagy Ada nyelven írt programba ágyazza be . Az összeszerelő betétek használata a következő célokat szolgálhatja:
- Optimalizálás : Ebből a célból az összeállítási kódot manuálisan írják, hogy megvalósítsák az algoritmus teljesítmény szempontjából legkritikusabb részeit. Ez lehetővé teszi a programozó számára, hogy a lehető legteljesebb mértékben használja ki találékonyságát, és nem korlátozza a fordítói konstrukciók.
- Processzorspecifikus utasítások elérése : Egyes processzorok támogatják a speciális utasításokat, például az összehasonlítást a cserével és a teszteléssel és beállítással , olyan utasításokat, amelyek szemaforok vagy más szinkronizálási és zárolási primitívek megvalósítására használhatók. Gyakorlatilag minden modern processzor rendelkezik ilyen vagy hasonló utasításokkal, mivel ezek szükségesek a multitasking megvalósításához . Különleges utasítások találhatók a következő processzorok utasításrendszereiben: SPARC VIS , Intel MMX és SSE , Motorola AltiVec .
- Rendszerhívások : A magas szintű programozási nyelvek ritkán biztosítanak közvetlen módot a rendszerhívásokhoz, erre a célra összeállítási kódot használnak [1] .
Példa optimalizálásra és speciális processzorutasítások használatára
Ez a példa az assembler beszúrására a D programozási nyelvben , amely megvalósítja az x tangensének kiszámítását, x86 FPU utasításokat használ . Ez a kód gyorsabban fut, mint a fordító által generált kód. Ezenkívül az itt található utasítást használjuk fldpi, amely a legközelebbi számközelítést tölti be az x86 architektúrához.
// Kiszámítjuk x tangensét
valós tan ( valós x )
{
asm
{
fld x [ EBP ] ; // betöltés x
fxam ; // páratlan értékek
tesztelése fstsw AX ;
sahf ;
jc trigerr ; // x a NAN, a végtelen vagy üres
// A 387-ek képesek denormálokat kezelni
SC18 : fptan ;
fstp ST ( 0 ) ; // X kiírása, ami mindig 1
fstsw AX ;
sahf ;
jnp Lret ; // C2 = 1 (x a tartományon kívül van)
// Az argumentumcsökkentés végrehajtása az x tartományba
kerüléséhez fldpi ;
fxch ;
SC17 : fprem1 ;
fstsw AX ;
sahf ;
jp SC17 ;
fstp ST ( 1 ) ; // pi eltávolítása a veremből
jmp SC18 ;
}
trigerr :
real . _ nan ; Lret : ; }
Rendszerhívási példa
Az operációs rendszer közvetlen elérése általában nem lehetséges védett memóriával. Az operációs rendszer privilegizáltabb szinten fut (kernel mód), mint a felhasználó (felhasználói mód). Az operációs rendszer felé irányuló kérésekhez szoftveres megszakításokat használnak. A magas szintű nyelvek ritkán támogatják ezt a funkciót, ezért a rendszerhívási interfészek inline assembler segítségével íródnak [1] .
A következő C példa az AT&T GNU Assembler szintaxisával írt rendszerhívási interfészt tartalmaz . Először nézzük meg az assembler beszúrási formátumát egy egyszerű példa segítségével:
asm ( "movl %ecx, %eax" ); /* áthelyezi az ecx tartalmát az eax-be */
Az asmés __asm__az azonosítók egyenértékűek. Egy másik egyszerű beillesztési példa:
__asm__ ( "movb %bh, (%eax)" ); /* áthelyezi a bájtot bh-ból az eax által jelölt memóriába */
Egy példa a rendszerhívási interfész megvalósítására:
extern int errno ;
int funkciónév ( int arg1 , int * arg2 , int arg3 )
{
int res ;
__asm__ volatile (
"int $0x80" /* kérje az operációs rendszert */
: "=a" ( res ), /* eredményt ad vissza az eax-ben ("a") */
"+b" ( arg1 ), /* adja át az arg1-et ebx-ben ("b") */
"+c" ( arg2 ), /* adja át az arg2-t ecx-ben ("c") */
"+d" ( arg3 ) /* adja át az arg3-at az edx-ben ("d") */
: "a" ( 128 ) /* átadja a rendszer hívószámát az eax-ban ("a") */
: "memória" , "cc" ); /* bejelenti a fordítónak, hogy a memória- és feltételkódok módosultak */
/* Az operációs rendszer hiba esetén negatív értéket ad vissza;
* A wrappers hiba esetén -1-et ad vissza, és beállítja az errno globális változót */
if ( -125 <= res && res < 0 ) {
errno = -res ; _
res = -1 ;
} return res ;
}
Kritika
A 21. század eleje óta az assembler betétek használatát többféle ok miatt egyre inkább elítélik [2] [3] :
- A modern optimalizáló fordítók jobb összeállítási kódot tudnak generálni, mint amit egy átlagos programozó meg tud írni. Önmagukban az assembler beillesztések zavarhatják a kód más részeinek optimalizálását. Néhány trükk, amely lehetővé tette a kód végrehajtásának optimalizálását az 1980-90-es évek processzorain a későbbi processzorokon, a végrehajtás jelentős lelassulásához vezethet a számítások eltérő szervezése miatt. Mint minden optimalizálásnál , az összeszerelő lapkákat is tesztelni kell , hogy teszteljük a hatékonyságukra vonatkozó hipotézist. A számítástechnikai rendszerek teljesítményének növekedése miatt sok optimalizálás irreleváns lehet, és előtérbe kerül a kód olvashatósága, a karbantartás egyszerűsége, a hibamegelőzés.
- Az összeállítási kód írása időigényesebb. Az összeszerelő betétben könnyű hibázni, amit nehéz észrevenni. Például az assembly nyelv nem támogatja a típusellenőrzést . A már generált összeállítási kódot nehezebb karbantartani .
- Az összeállítási kód nem hordozható. Az összeszerelő betétek a platformspecifikus mechanizmusokhoz való hozzáféréshez indokoltak. Ha többplatformos programokban assembler beszúrásokat használunk , akkor a különböző platformokhoz szükséges assembler beillesztéseket megkettőzni, és lehetőség szerint egy alternatív implementációt is megtartani magas szintű nyelven – ez a gyakorlat azonban problémákat okoz a program karbantartása során a párhuzamosan kell változtatásokat végrehajtani a különböző nyelveken írt kódrészleteken, nyelveken és különböző platformokon.
Jegyzetek
- ↑ 1 2 "Linux programozás" 5. fejezet A rendszerhívások működése . Opennet. Hozzáférés időpontja: 2013. szeptember 29. Az eredetiből archiválva : 2013. október 2. (határozatlan)
- ↑ Az assembler betétek használatának elemzése a nyitott projektek kódjában . opennet . Letöltve: 2022. május 3. Az eredetiből archiválva : 2022. május 3. (határozatlan)
- ↑ Okok, amiért NE használd az inline asm-t . Letöltve: 2022. május 3. Az eredetiből archiválva : 2022. április 28.. (határozatlan)
Linkek