Volací konvence
Způsob, jakým jsou předávany argumenty a návratové hodnoty funkcí, není u procesorů x86 pevně určen a jedná se o konvence definované v době překladu. Můžeme si tedy definovat ,,vlastní konvence''. Situaci komplikuje překladač (Visual Studio), který automaticky vytváří prolog a epilog funkce a mj. přidává ladící informace. Tento problém lze ale obejít pomocí specifického modifikátoru.
__declspec(naked) int foo() { // zamezí vložení prologu a epilogu _asm { mov eax, 10 ret; // je potreba uvest instrukci ret } }
Příklady
// funkce jednoho argumentu, ktera vraci hodnotu o jedna vetsi // pouzita konvence CDECL __declspec(naked) int incf1(int arg) { _asm { push ebp; // prolog funkce mov ebp, esp; mov eax, [ebp + 8]; inc eax; mov esp, ebp; // epilog funkce pop ebp; ret; } } // funkce jednoho argumentu, ktera vraci hodnotu o jedna vetsi // pouzita konvence FASTCALL (argument je predan pomoci registru ecx) __declspec(naked) int incf2(int arg) { _asm { push ebp; // prolog funkce mov ebp, esp; mov eax, ecx inc eax mov esp, ebp; // epilog funkce pop ebp; ret; } } // funkce jednoho argumentu, ktera vraci hodnotu o jedna vetsi // pouzita konvence FASTCALL (argument je predan pomoci registru ecx) // optimalizavana verze -- vsimnete si, ze v tomto pripade neni potreba prolog ani epilog // a staci jen instrukce ret __declspec(naked) int incf3(int arg) { _asm { mov eax, ecx inc eax ret; } }
// priklady volani funkci s ruznymi konvencemi int foo() { _asm { // volani funkce s konvenci CDECL push dword ptr 10 call incf1 add esp, 4 // volani funkce s konvenci FASTCALL mov ecx, 10 call incf2 // jde pouzit i incf3 } }
Poznámka
Použitou volací konvenci lze pro jednotlivé funkce určit pomocí specifických modifikátorů, např. __fastcall, __cdecl, atd. V průběhu tohoto cvičení je ale nepoužívejte.
Úkoly
- S použitím výše popsaného postupu napište funkci
int min1(int a, int b)
, která vrací nejmenší hodnotu ze dvou. K předání argumentů použijte zásobník. Tuto funkci zavolejte. - S použitím výše popsaného postupu napište funkci
int min2(int a, int b)
, která vrací nejmenší hodnotu ze dvou. K předání argumentů použijte registr ecx a zásobník. Tuto funkci zavolejte. - S použitím výše popsaného postupu napište funkci
int min3(int a, int b)
, která vrací nejmenší hodnotu ze dvou. K předání argumentů použijte registry ecx a edx. Tuto funkci zavolejte. - S použitím výše popsaného postupu napište funkce počítající rekurzivně faktoriál zadaného argumentu jednou s použitím konvence CDECL a jednou s použitím fastcall. Tyto funkce zavolejte a výsledek vypište na standardní výstup.
- S použitím výše popsaného postupu napište funkce počítající rekurzivně fibonacciho číslo zadaného argumentu jednou s použitím konvence CDECL a jednou s použitím fastcall.
Pro získání bodového hodnocení je potřeba splnit úkoly 1, 2, 3 a 4.