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
Viz také
Váš názor
https://aka.ms/ContentUserFeedback.
Připravujeme: V průběhu roku 2024 budeme postupně vyřazovat problémy z GitHub coby mechanismus zpětné vazby pro obsah a nahrazovat ho novým systémem zpětné vazby. Další informace naleznete v tématu:Odeslat a zobrazit názory pro