Ich verstehe nicht, wie das funktionieren soll.
GCC-Inline-Assembler ist ein Schmerz, um richtig zu werden, aber sehr spezifisch, wenn es darum geht, Clobbering-Informationen zu markieren, damit der Compiler weiß, was Sie tun.
Die Inline-Assemblierung von Microsoft Visual C ++ ist wirklich einfach zu verwenden (es scheint immer nur zu funktionieren), aber ich habe keine Ideen, welche Garantien oder Annahmen es für Ihren Code gibt.
Versucht VC ++, "automatisch zu erkennen", welche Register verfälscht sind? Woher weiß es, wie die Register und der Stapelzeiger geändert werden? Macht es irgendwelche Annahmen? Wenn ja, wie kommst du um diese Annahmen herum?
Warum GCC es nicht so macht wie MSVC, gibt es mehrere Gründe:
GCC ist ein Retargetget-Compiler, aber die Assembly-Syntax besteht nur aus Rohtext. Damit die Clobber-Erkennung automatisch erfolgt, müsste GCC die Assembler-Sprache parsen, um zu verstehen, welche Register verfälscht werden (einschließlich implizit verfälschter Register durch Befehle, deren Opcodes kein Register nennen). Dies müsste über alle Architekturen hinweg funktionieren. Derzeit analysiert GCC die Assemblersprache nicht. Es wird nur in die Assembly-Ausgabe eingefügt, nachdem die %
Ersetzungen durchgeführt wurden. Die Idee ist, zu generieren und Parsing zu vermeiden.
In der GCC-Inline-Assemblersprache ist clobbering registers die Ausnahme und nicht die Regel . Der Grund ist, dass es eine anspruchsvollere Sprache ist als die in MSVC. Die Inline-Assembler-Sprache von GCC weist Register für Sie zu. Normalerweise verwenden Sie also nicht direkt %eax
, sondern einen Code wie %0
, für den GCC ein verfügbares Register ersetzt. (Dazu muss der Compiler die Assemblersprache nicht verstehen! Sie drücken die Einschränkungen aus, die sicherstellen, dass GCC ein passendes Register für %0
ersetzt, das zur Verwendung passt.) Sie brauchen nur clobber für Ihre Assembly Code überschreibt hartcodierte Register, nicht wenn er die Ausgabeoperanden überschreibt, die von GCC für Sie zugewiesen wurden.
Beachten Sie, dass Sie bei der GCC-Inline-Assembly nicht den Code schreiben müssen, der Ihre Assemblersprachoperanden aus den C-Ausdrücken lädt, die ihre Anfangswerte erzeugen, oder die Ihre Ergebnisoperanden in den C-Zielen speichert. Zum Beispiel drücken Sie einfach aus, dass es einen Eingabeoperanden vom Typ "r"
(register) geben soll, der vom Ausdruck foo->bar + 1
abgeleitet ist. GCC ordnet das Register zu und generiert den Code, um es aus foo->bar + 1
zu laden, und ersetzt das Vorkommen von %0
in Ihrer Assemblyvorlage durch den Namen dieses Registers.
Zitat von den Dokumenten :
Wenn Sie __asm zum Schreiben der Assemblersprache in C / C ++ - Funktionen verwenden, müssen Sie die Register EAX, EBX, ECX, EDX, ESI oder EDI nicht beibehalten. Zum Beispiel im Beispiel POWER2.C in Schreibfunktionen mit Inline Assembly , die power2-Funktion behält den Wert im EAX-Register nicht bei. Die Verwendung dieser Register wirkt sich jedoch auf die Codequalität aus, da der Registerzuordner sie nicht zum Speichern von Werten über __asm-Blöcke verwenden kann. Wenn Sie EBX, ESI oder EDI in Inline-Assemblercode verwenden, erzwingen Sie außerdem, dass der Compiler diese Register im Funktionsprolog und Epilog speichert und wiederherstellt.
Sie sollten andere Register, die Sie verwenden (wie DS-, SS-, SP-, BP- und Flag-Register), für den Bereich des __asm-Blocks beibehalten. Sie sollten die ESP- und EBP-Register beibehalten, es sei denn, Sie haben einen Grund, sie zu ändern (z. B. um Stacks zu wechseln). Siehe auch Inline-Baugruppe optimieren .
Tags und Links c gcc inline-assembly visual-c++