Verwenden und Beibehalten von Registern in der Inlineassembly
Microsoft-spezifisch
Im Allgemeinen sollten Sie nicht davon ausgehen, dass ein Register einen bestimmten Wert aufweist, wenn ein __asm
Block beginnt. Registerwerte werden nicht garantiert über separate __asm
Blöcke hinweg beibehalten. Wenn Sie einen Block von Inlinecode beenden und eine weitere beginnen, können Sie sich nicht auf die Register im zweiten Block verlassen, um deren Werte aus dem ersten Block beizubehalten. Ein __asm
Block erbt alle Registerwerte aus dem normalen Kontrollfluss.
Wenn Sie die __fastcall
aufrufende Konvention verwenden, übergibt der Compiler Funktionsargumente in Registern anstelle des Stapels. Dies kann Probleme in Funktionen mit __asm
Blöcken verursachen, da eine Funktion keine Möglichkeit hat, zu ermitteln, in welchem Parameter sich das Register befindet. Wenn die Funktion einen Parameter in EAX empfängt und sofort etwas anderes in EAX speichert, geht der ursprüngliche Parameter verloren. Darüber hinaus müssen Sie das ECX-Register in jeder funktion beibehalten, die mit __fastcall
.
Um solche Registerkonflikte zu vermeiden, verwenden Sie die Konvention nicht für Funktionen, die __fastcall
einen __asm
Block enthalten. Wenn Sie die __fastcall
Konvention global mit der /Gr-Compileroption angeben, deklarieren Sie jede Funktion, die einen __asm
Block mit __cdecl
oder __stdcall
. (Das __cdecl
Attribut weist den Compiler an, die C-Aufrufkonvention für diese Funktion zu verwenden.) Wenn Sie nicht mit /Gr kompilieren, vermeiden Sie, die Funktion mit dem __fastcall
Attribut zu deklarieren.
__asm
Wenn Sie die Assemblysprache in C/C++-Funktionen schreiben, müssen Sie die EAX-, EBX-, ECX-, EDX-, ESI- oder EDI-Register nicht beibehalten. Beispiel: in power2. C-Beispiel in Schreibfunktionen mit Inlineassembly behält die power2
Funktion den Wert im EAX-Register nicht bei. Die Verwendung dieser Register wirkt sich jedoch auf die Codequalität aus, da der Register-Allocator sie nicht zum Speichern von Werten über __asm
Blöcke hinweg verwenden kann. Darüber hinaus erzwingen Sie mithilfe von EBX, ESI oder EDI im Inlineassemblycode, dass der Compiler diese Register in der Funktionsprologe und epilog speichert und wiederherstellen kann.
Sie sollten andere Register beibehalten, die Sie verwenden (z. B. DS-, SS-, SP-, BP- und Flags-Register) für den Bereich des __asm
Blocks. Sie sollten die ESP- und EBP-Register beibehalten, es sei denn, Sie haben einen Grund, sie zu ändern (z. B. zum Wechseln von Stapeln). Siehe auch Optimieren der Inlineassembly.
Einige SSE-Typen erfordern eine Acht-Byte-Stapelausrichtung, wodurch der Compiler gezwungen wird, dynamischen Stapelausrichtungscode auszustrahlen. Um sowohl auf die lokalen Variablen als auch auf die Funktionsparameter nach der Ausrichtung zugreifen zu können, enthält der Compiler zwei Framezeiger Standard. Wenn der Compiler Framepointer-Auslassungen (FPO) durchführt, verwendet er EBP und ESP. Wenn der Compiler kein FPO ausführt, verwendet er EBX und EBP. Um sicherzustellen, dass Code ordnungsgemäß ausgeführt wird, ändern Sie EBX nicht im Asm-Code, wenn die Funktion eine dynamische Stapelausrichtung erfordert, da sie den Framezeiger ändern könnte. Verschieben Sie entweder die acht byte ausgerichteten Typen aus der Funktion, oder vermeiden Sie die Verwendung von EBX.
Hinweis
Wenn Ihr Inlineassemblycode die Richtungskennzeichnung mithilfe der ANWEISUNGEN STD oder CLD ändert, müssen Sie das Flag auf seinen ursprünglichen Wert wiederherstellen.
Ende Microsoft-spezifisch