Paraméterátadás assembly nyelvű programokban
Paraméterátadás assembly nyelvű programokban ASM((type Halász Végh), előadás);
Többszintű tárgyalás Magasszintű nyelven mindenki jól használja; csak felidézünk (és magyarázunk!) fogalmakat Magasszintű assembly: gyakorlatból ismert; az elmélete nem teljesen megalapozott Igazi assembly: 1:1 gépi utasítás megfelelések; mit rejt el előlünk a HLA? Utasításvégrehajtási vonatkozások http://www.inf.unideb.hu/~jvegh/asm/AoAHLA/HTML/index.html
Ismétlődő kódok Kódsorok többszöri bemásolása Egyszerű, de sok helyet foglal Csak abszolút azonos műveletek hajthatók végre Egy példány többszöri végrehajtása Kevesebb hely kell Kód újrafelhasználás, biztonság
Veremtároló kialakulása 0. utasítás 1. utasítás EIP ESP FFFE adat FFFF adat
Veremtároló kialakulása 0. utasítás 1. utasítás EIP ESP FFFE adat FFFF adat
Szubrutinhívás Vezérlésátadás (hívás, CALL) Visszatérés és folytatás (RETURN) Hogyan jegyezzük meg a visszatérési címet? Hogyan őrizzük meg a számítógép állapotát?
A CALL/RET utasítás hatása előző utasítás EIP CALL SUB1 Következő utasítás . . . ESP . . . SUB1:első utasítás RET FFFE adat FFFF adat
A CALL/RET utasítás hatása előző utasítás CALL SUB1 EIP Következő utasítás . . . ESP . . . SUB1:első utasítás RET FFFE adat FFFF adat
A CALL/RET utasítás hatása előző utasítás CALL SUB1 EIP következő utasítás . . . ESP Vissza cím (EIP) . . . SUB1:első utasítás EIP RET FFFE adat FFFF adat
A CALL/RET utasítás hatása előző utasítás CALL SUB1 Következő utasítás . . . ESP Vissza cím (EIP) . . . SUB1:első utasítás RET EIP FFFE adat FFFF adat
A CALL/RET utasítás hatása előző utasítás CALL SUB1 Következő utasítás EIP . . . Vissza cím (EIP) ESP . . . SUB1:első utasítás RET FFFE adat FFFF adat EIP
A minimális ASM szubrutin A főprogramban: call sub1; A szubrutinban: Sub1: ret;
A minimális HLA szubrutin Gyakorlat 1. feladata A HLA főprogramban call Fgv11(T1[EBX*4],T2[ECX*2]); A HLA szubrutin procedure Fgv11(VAL i:int32; VAL j:int16); begin Fgv11; ret; end Fgv11;
HLA eljárások call stdout.newln; stdout.newln(); Eljárásdeklaráció: procedure ProcName; [@opciók] << helyi deklarációk >> begin ProcName; << az eljárás utasításai >> end ProcName; Hívás: call stdout.newln; stdout.newln();
HLA opciók @NOFRAME nem kell be- és kilépő kód @NODISPLAY egymásba ágyazás; gyorsít @NOALIGNSTACK veremcímek igazítása procedure minimal; @nodisplay; @noframe; @noalignstk; begin minimal; ret(); end minimal;
A hiányzó RET hatása program missingRET; #include( "stdlib.hhf" ); procedure firstProc; @noframe; @nodisplay; begin firstProc; stdout.put( "firstProc eljárásban" nl ); end firstProc; procedure secondProc; @noframe; @nodisplay; begin secondProc; stdout.put( "secondProc eljárásban" nl ); ret(); end secondProc; begin missingRET; call firstProc; end missingRET;
Veremtároló használata szubrutinban előző utasítás CALL SUB1 következő utasítás . . . ESP Vissza cím (EIP) . . . SUB1:első utasítás EIP PUSH EAX RET FFFE adat FFFF adat
Veremtároló használata szubrutinban előző utasítás CALL SUB1 következő utasítás ESP EAX mentés . . . Vissza cím (EIP) . . . SUB1:első utasítás PUSH EAX EIP RET FFFE adat FFFF adat
Veremtároló használata szubrutinban előző utasítás CALL SUB1 következő utasítás EAX mentés . . . ESP Vissza cím (EIP) . . . SUB1:első utasítás PUSH EAX RET EIP FFFE adat FFFF adat
Veremtároló használata szubrutinban előző utasítás CALL SUB1 következő utasítás EAX mentés . . . ESP Vissza cím (EIP) . . . SUB1:első utasítás 32 1:2 PUSH EAX RET EIP FFFE adat FFFF adat
Extra pop hatása ESP EIP Vissza cím (extraPop) program extraPop; #include( "stdlib.hhf" ); procedure messedUpToo; @noframe; @nodisplay; begin messedUpToo; stdout.put( "Entered messedUpToo" nl ); pop( eax ); ret(); end messedUpToo; procedure callsMU2; @noframe; @nodisplay; begin callsMU2; stdout.put( "calling messedUpToo" nl ); messedUpToo(); stdout.put( "Returned from messedUpToo" nl ); end callsMU2; begin extraPop; stdout.put( "Calling callsMU2" nl ); callsMU2(); stdout.put( "Returned from callsMU2" nl ); end extraPop; ESP Vissza cím (extraPop) EIP
Extra pop hatása ESP EIP Vissza (callsMU2) Vissza cím(extraPop) program extraPop; #include( "stdlib.hhf" ); procedure messedUpToo; @noframe; @nodisplay; begin messedUpToo; stdout.put( "Entered messedUpToo" nl ); pop( eax ); ret(); end messedUpToo; procedure callsMU2; @noframe; @nodisplay; begin callsMU2; stdout.put( "calling messedUpToo" nl ); messedUpToo(); stdout.put( "Returned from messedUpToo" nl ); end callsMU2; begin extraPop; stdout.put( "Calling callsMU2" nl ); callsMU2(); stdout.put( "Returned from callsMU2" nl ); end extraPop; ESP Vissza (callsMU2) Vissza cím(extraPop) EIP
Extra pop hatása ESP EIP Vissza (callsMU2) Vissza cím (extraPop) program extraPop; #include( "stdlib.hhf" ); procedure messedUpToo; @noframe; @nodisplay; begin messedUpToo; stdout.put( "Entered messedUpToo" nl ); pop( eax ); ret(); end messedUpToo; procedure callsMU2; @noframe; @nodisplay; begin callsMU2; stdout.put( "calling messedUpToo" nl ); messedUpToo(); stdout.put( "Returned from messedUpToo" nl ); end callsMU2; begin extraPop; stdout.put( "Calling callsMU2" nl ); callsMU2(); stdout.put( "Returned from callsMU2" nl ); end extraPop; ESP Vissza (callsMU2) EIP Vissza cím (extraPop)
Extra pop hatása EIP ESP Vissza (callsMU2) Vissza cím (extraPop) program extraPop; #include( "stdlib.hhf" ); procedure messedUpToo; @noframe; @nodisplay; begin messedUpToo; stdout.put( "Entered messedUpToo" nl ); pop( eax ); ret(); end messedUpToo; procedure callsMU2; @noframe; @nodisplay; begin callsMU2; stdout.put( "calling messedUpToo" nl ); messedUpToo(); stdout.put( "Returned from messedUpToo" nl ); end callsMU2; begin extraPop; stdout.put( "Calling callsMU2" nl ); callsMU2(); stdout.put( "Returned from callsMU2" nl ); end extraPop; Vissza (callsMU2) EIP ESP Vissza cím (extraPop)
A processzor állapotának megőrzése program nonWorkingProgram; #include( "stdlib.hhf" ); procedure PrintSpaces; begin nonWorkingProgram; mov( 20, ecx ); repeat PrintSpaces(); stdout.put( '*', nl ); dec( ecx ); until( ecx = 0 ); end nonWorkingProgram; procedure PrintSpaces; begin PrintSpaces; mov( 40, ecx ); repeat stdout.put( ' ' ); dec( ecx ); until( ecx = 0 ); end PrintSpaces;
A processzor állapotának megőrzése program nonWorkingProgram; #include( "stdlib.hhf" ); procedure PrintSpaces; begin nonWorkingProgram; mov( 20, ecx ); repeat PrintSpaces(); stdout.put( '*', nl ); dec( ecx ); until( ecx = 0 ); end nonWorkingProgram; procedure PrintSpaces; begin PrintSpaces; push( eax ); push( ecx ); mov( 40, ecx ); repeat stdout.put( ' ' ); dec( ecx ); until( ecx = 0 ); pop( ecx ); pop( eax ); end PrintSpaces;
Egy szubrutin feladatai Folytatás a hívás utáni utasítással Ha nem minden alkalommal ugyanazt kell csinálni: paraméterek (irány) Be- és kimenő (hogyan) Érték és cím szerint átadott (hol) regiszter, kódterület, veremtároló (mennyi) (egyéb körülmények) eredmény visszaadás
In 1984 Richard Stallman's Free Software Foundation (FSF) began the GNU project
Paraméterátadás regiszterben // strfill- Karaktert ír egy sztringbe. // EDI- sztring mutató // AL- a sztringbe töltendő karakter. procedure strfill; @nodisplay; begin strfill; push( edi ); // Módosítjuk! while( (type char [edi] <> #0 ) do mov( al, [edi] ); inc( edi ); endwhile; pop( edi ); end strfill; Hívása: mov( s, edi ); // Sztring mutató beállítás mov( ' ', al ); // Karakter betöltés strfill(); // Hívás
Paraméterátadás regiszterben magasszintű szintaxis: procedure HasRegParms( count: uns32 in ecx; charVal:char in al ); Hívása: HasRegParms( ecx, bl ); Vigyázat: count és ecx ugyanazt jelentik! bl: extra utasítást generál
Paraméterátadás regiszterben magasszintű szintaxis: procedure HasRefRegParm( var myPtr:uns32 in edi ); Hívása: HasRefRegParm( x ); "mov( &x, edi);" vagy egy "lea( edi, x);" utasítást generál
Paraméterátadás a kódfolyamban program printDemo; #include( "stdlib.hhf" ); .... begin printDemo; call print; byte "Hello World!", 13, 10, 0 ; end printDemo;
Paraméterátadás a kódfolyamban procedure print; @noframe; @nodisplay; const // Az eljárás visszatérési cím offszetje RtnAdrs:text := "(type dword [ebp+4])"; begin print; push( ebp ); mov( esp, ebp ); push( eax ); push( ebx ); // Regiszterek megőrzése mov( RtnAdrs, ebx ); // sztring címe forever mov( [ebx], al ); breakif( !al ); stdout.putc( al ); endfor; inc( ebx ); mov( ebx, RtnAdrs ); pop( ebx ); pop( eax ); pop( ebp ); ret(); end print;
Paraméterátadás a kódfolyamban procedure print; @noframe; @nodisplay; const // Az eljárás visszatérési cím offszetje RtnAdrs:text := "(type dword [ebp+4])"; begin print; push( ebp ); mov( esp, ebp ); push( eax ); push( ebx ); // Regiszterek megőrzése mov( RtnAdrs, ebx ); // sztring címe forever mov( [ebx], al ); breakif( !al ); stdout.putc( al ); endfor; inc( ebx ); mov( ebx, RtnAdrs ); pop( ebx ); pop( eax ); pop( ebp ); ret(); end print; ESP EIP -8 ebx -4 eax EBP Régi EBP +4 Vissza cím +8 +12 +16
Paraméterátadás a kódfolyamban procedure print; @noframe; @nodisplay; const // Az eljárás visszatérési cím offszetje RtnAdrs:text := "(type dword [ebp+4])"; begin print; push( ebp ); mov( esp, ebp ); push( eax ); push( ebx ); // Regiszterek megőrzése mov( RtnAdrs, ebx ); // sztring címe forever mov( [ebx], al ); breakif( !al ); stdout.putc( al ); endfor; inc( ebx ); mov( ebx, RtnAdrs ); pop( ebx ); pop( eax ); pop( ebp ); ret(); end print; ESP -8 ebx -4 eax EIP EBP Régi EBP +4 Vissza cím + L +8 +12 +16
Paraméterátadás a veremtárolón át push( i ); push( j ); push( k ); call CallProc; static RtnAdrs: dword; p1Parm: dword; p2Parm: dword; p3Parm: dword; procedure CallProc( p1:dword; p2:dword; p3:dword ); @nodisplay; @noframe; begin CallProc; pop( p3Parm ); pop( p2Parm ); pop( p1Parm ); . . . ret(); end CallProc;
Paraméterátadás a veremtárolón át push( i ); push( j ); push( k ); call CallProc; static RtnAdrs: dword; p1Parm: dword; p2Parm: dword; p3Parm: dword; procedure CallProc( p1:dword; p2:dword; p3:dword ); @nodisplay; @noframe; begin CallProc; pop( RtnAdrs ); pop( p3Parm ); pop( p2Parm ); pop( p1Parm ); push( RtnAdrs ); . . . ret(); end CallProc;
Aktivációs rekordok Aktivációs – híváskor keletkezik Rekord – ilyen adatszerkezet (belül van az alapcíme) Összeállítása elosztott: a hívás előtt kezdődik, az eljárás fejezi be
Aktivációs rekord előkészítés procedure ARDemo ( i:uns32; j:int32; k:dword ); nodisplay; var a:int32; r:real32; c:char; b:boolean; w:word; begin ARDemo; . . . end ARDemo; Call ARDemo( i, j, k); EIP ESP
Aktivációs rekord előkészítés procedure ARDemo ( i:uns32; j:int32; k:dword ); nodisplay; var a:int32; r:real32; c:char; b:boolean; w:word; begin ARDemo; . . . end ARDemo; Call ARDemo( i, j, k); ESP k j i EIP
Aktivációs rekord előkészítés procedure ARDemo ( i:uns32; j:int32; k:dword ); nodisplay; var a:int32; r:real32; c:char; b:boolean; w:word; begin ARDemo; . . . end ARDemo; Call ARDemo( i, j, k); ESP Vissza cím k j i EIP
Aktivációs rekord folytatás procedure ARDemo ( i:uns32; j:int32; k:dword ); nodisplay; var a:int32; r:real32; c:char; b:boolean; w:word; begin ARDemo; . . . end ARDemo; Call ARDemo( i, j, k); ESP, EBP Régi EBP EIP Vissza cím k j i
Aktivációs rekord folytatás procedure ARDemo ( i:uns32; j:int32; k:dword ); nodisplay; var a:int32; r:real32; c:char; b:boolean; w:word; begin ARDemo; . . . end ARDemo; Call ARDemo( i, j, k); ESP w b c r a EBP Régi EBP EIP Vissza cím k j i
Aktivációs rekord folytatás procedure ARDemo ( i:uns32; j:int32; k:dword ); nodisplay; var a:int32; r:real32; c:char; b:boolean; w:word; begin ARDemo; mov(i,EAX); add(j, EAX); mov(EAX, a); . . . end ARDemo; ESP w -10 b -9 c -8 r -4 a EBP Régi EBP +4 Vissza cím +8 k +12 j +16 i
Aktivációs rekord folytatás procedure ARDemo ( i:uns32; j:int32; k:dword ); nodisplay; var a:int32; r:real32; c:char; b:boolean; w:word; begin ARDemo; mov(i,EAX);//mov([ebp+16], eax); add(j,EAX);//add([ebp+12],eax); mov(EAX,a);//mov(eax,[ebp-4]); . . . end ARDemo; ESP w -10 b -9 c -8 r -4 a EBP Régi EBP +4 Vissza cím +8 k +12 j +16 i
Aktivációs rekord folytatás procedure ARDemo ( i:uns32; j:int32; k:dword ); nodisplay; var a:int32; r:real32; c:char; b:boolean; w:word; begin ARDemo; . . . end ARDemo; Call ARDemo( i, j, k); ESP w -10 b -9 c -8 r -4 a EBP Régi EBP EIP +4 Vissza cím +8 k +12 j +16 i
Szubrutin standard be/kilépő kód procedure ARDemo ( i:uns32; j:int32; k:dword ); nodisplay; var a:int32; r:real32; c:char; b:boolean; w:word; begin ARDemo; push( ebp ); mov( esp, ebp ); sub( NumVars, esp ); . . . mov( ebp, esp ); pop( ebp ); ret(ParmBytes ); end ARDemo; ESP w -10 b -9 c -8 r -4 a EBP Régi EBP +4 Vissza cím +8 k +12 j +16 i
Szubrutin standard be/kilépő kód procedure ARDemo ( i:uns32; j:int32; k:dword ); nodisplay; var a:int32; r:real32; c:char; b:boolean; w:word; begin ARDemo; push( ebp ); mov( esp, ebp ); sub( NumVars, esp ); . . . mov( ebp, esp ); pop( ebp ); ret(ParmBytes ); end ARDemo; push( ebp ); mov( esp, ebp ); sub( _vars_, esp ); mov( ebp, esp ); pop( ebp ); ret( _parms_ );
A 32-bites memóriaszervezés
Többciklusú adatelérés
Szubrutin standard be/kilépő kód (@noalignstack; hatása) procedure ARDemo ( i:uns32; j:int32; k:dword ); nodisplay; var a:int32; r:real32; c:char; b:boolean; w:word; begin ARDemo; push( ebp ); mov( esp, ebp ); sub( NumVars, esp ); and( $FFFF_FFFC, esp ); . . . mov( ebp, esp ); pop( ebp ); ret(ParmBytes ); end ARDemo; push( ebp ); mov( esp, ebp ); sub( _vars_, esp ); and( $FFFF_FFFC, esp ); . . . mov( ebp, esp ); pop( ebp ); ret( _parms_ );
Érték vagy cím szerint adjunk át? Le kell másolni és átadni Csak bemenő paraméter lehet Kevés átadott bájt esetén előnyös Cím Minden alkalommal fel kell oldani Ezt a HLA nem rejti el Nagy adatszerkezetekre előnyös Változtatni csak így tudunk
Függvényeredmények és a @returns opció Eredményt általában regiszter(ek)ben adunk vissza Nagyobbat pointerként A @returns nem a függvényeredmény visszadásának helyét jelöli! A fordítás ideje alatti eredményt és nem a futási idő alatti eredményt jelöli
A @returns opció használata procedure IsAlphabeticChar( c:char ); @RETURNS( "EAX" ); begin IsAlphabeticChar; cs.member( c, {'a'..'z', `A'..'Z'} ); end IsAlphabeticChar; if( IsAlphabeticChar( ch ) ) then . . . endif; if( EAX ) then