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

Siehe auch

Inlineassembler