Použití a zachování registrů v sestavení inline assemblerem
Specifické pro Microsoft
Obecně byste neměli předpokládat, že při zahájení bloku bude mít registr danou __asm
hodnotu. Nezaručují se zachování hodnot registru napříč samostatnými __asm
bloky. Pokud ukončíte blok vloženého kódu a zahájíte další, nemůžete se spolehnout na registry v druhém bloku, aby si zachovaly své hodnoty z prvního bloku. Blok __asm
dědí všechny hodnoty registru, které jsou výsledkem normálního toku řízení.
Pokud používáte __fastcall
konvenci volání, kompilátor předá argumenty funkce v registrech místo v zásobníku. To může způsobit problémy s funkcemi s __asm
bloky, protože funkce nemá způsob, jak zjistit, který parametr je v jakém registru. Pokud funkce přijme parametr v EAX a okamžitě uloží něco jiného v EAX, původní parametr se ztratí. Kromě toho je nutné zachovat registr ECX v jakékoli funkci deklarované s __fastcall
.
Abyste se takovým konfliktům registrů vyhnuli, nepoužívejte __fastcall
konvenci pro funkce, které obsahují __asm
blok. Pokud konvenci zadáte __fastcall
globálně pomocí možnosti kompilátoru /Gr, deklarujte každou funkci obsahující __asm
blok s __cdecl
nebo __stdcall
. (Atribut __cdecl
říká kompilátoru, aby pro tuto funkci použil konvenci volání jazyka C.) Pokud kompilujete pomocí /Gr, vyhněte se deklarování funkce atributem __fastcall
.
Při psaní __asm
jazyka sestavení ve funkcích C/C++ nemusíte zachovat registry EAX, EBX, ECX, EDX, ESI nebo EDI. Například v POWER2. Příklad jazyka C při psaní funkcí s vloženým sestavenímpower2
funkce nezachovává hodnotu v registru EAX. Použití těchto registrů však ovlivní kvalitu kódu, protože alokátor registru je nemůže použít k ukládání hodnot napříč __asm
bloky. Kromě toho pomocí EBX, ESI nebo EDI vloženého kódu sestavení vynutíte kompilátor uložit a obnovit tyto registry ve funkci prologue a epilogue.
Pro rozsah __asm
bloku byste měli zachovat další používané registry (například DS, SS, SP, BP a příznaky). Registry ESP a EBP byste měli zachovat, pokud nemáte nějaký důvod je změnit (například pro přepínání zásobníků). Viz také optimalizace vložené sestavení.
Některé typy SSE vyžadují zarovnání zásobníku s osmi bajty a vynucení kompilátoru k generování kódu dynamického zarovnání zásobníku. Aby bylo možné po zarovnání získat přístup k místním proměnným i parametrům funkce, kompilátor udržuje dva ukazatele rámce. Pokud kompilátor vynechá ukazatel rámce (FPO), použije EBP a ESP. Pokud kompilátor neprovádí FPO, použije EBX a EBP. Pokud chcete zajistit správné spuštění kódu, neupravujte v asm kódu EBX, pokud funkce vyžaduje dynamické zarovnání zásobníku, protože by mohlo upravit ukazatel rámce. Buď přesuňte 8bajtů zarovnané typy mimo funkci, nebo nepoužívejte EBX.
Poznámka:
Pokud kód vloženého sestavení změní směrový příznak pomocí pokynů STD nebo CLD, musíte příznak obnovit na původní hodnotu.
END Microsoft Specific