2012-05-08 4 views
8

Ich verstehe nicht, wie das funktionieren soll.Warum benötigt GCC Inline-Assembler Clobbering Informationen, aber MSVC nicht

GCC Inline-Assembler ist ein Schmerz, um richtig zu werden, aber sehr spezifisch über das Markieren von Clobbering-Informationen, so dass der Compiler weiß, was Sie tun.

Die Inline-Assemblierung von Microsoft Visual C++ ist wirklich einfach zu verwenden (es scheint immer zu funktionieren), aber ich habe keine Ideen, welche Garantien oder Annahmen es über Ihren Code macht.

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 umgehen Sie diese Annahmen?

Antwort

19

Was, warum GCC es nicht tun, um die Art und Weise MSVC der Fall ist, gibt es mehrere Gründe:

  1. GCC ist ein retargettable Compiler, aber die Montage Syntax ist nur 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 fügt es nur in die Assembly-Ausgabe ein, nachdem die % Ersetzungen durchgeführt wurden. Die Idee ist, zu generieren und Parsing zu vermeiden.

  2. In der GCC-Inline-Assemblersprache ist clobbering registers eher die Ausnahme als 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. (Und um das zu tun, 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 der Verwendung entspricht.) Sie benötigen nur clobber, wenn Ihr Assemblercode hart überschreibt -codierte Register, nicht, wenn es die von GCC für Sie zugewiesenen Ausgabeoperanden überschreibt.

Beachten Sie, dass mit GCC Inline-Assembler, Sie müssen nicht den Code schreiben, die Ihre Assemblersprache Operanden aus den C-Ausdrücke lädt, die ihre Anfangswerte erzeugen, oder die speichert Ihre Ergebnisoperanden in die C Destinationen.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 weist das Register zu und generiert den Code, um es von foo->bar + 1 zu laden, und ersetzt dann Vorkommen von %0 in Ihrer Assemblyvorlage mit dem Name des Registers.

+2

+1, eine sehr anspruchsvolle Antwort auf OPs Follow-up-Frage :) –

+0

# 2 war ein sehr nützlicher Kommentar, hatte ich keine Ahnung davon! Vielen Dank! :) – Mehrdad

+0

in 1. oben heißt es: * "Die Idee ist, zu generieren und zu vermeiden Parsing" * noch scheint es mir, dass für den Compiler erhalten die Informationen über verprügelte Elemente beinhaltet Parsing sowieso, nicht wahr? Aus dem - möglicherweise unkorrekten - Eindruck, dass "Inline-Assemblierung nicht das Ziel hat, die Unabhängigkeit der Architektur zu erhöhen und plattformspezifisch einfach zu assemblieren", wäre es schön, dass es ein Wörterbuch für die vom Compiler unterstützten Informationen gibt statt Programmierern Dinge zu vergessen. Gab es seit der Frage 2012 eine gewisse Entwicklung? – humanityANDpeace

4

Zitat von the docs:

Wenn __asm ​​mit Assembler-Sprache in C/C++ Funktionen zu schreiben, müssen Sie nicht die EAX, EBX, ECX, EDX, ESI oder EDI-Register zu bewahren. Beispiel: Im POWER2.C-Beispiel in Writing Functions with Inline Assembly behält die Funktion power2 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 Optimizing Inline Assembly.

+0

+1 Gefühl so dumm, nicht in die Dokumente schauen ... – Mehrdad

+1

Art der Pops die Frage though: Warum macht GCC das nicht? – Mehrdad

+2

Zusammenfassend für unsere anderen Leser: "Ja, MSVC erkennt automatisch, welche Register geplottert sind, während GCC erfordert, dass Sie sie explizit markieren." – Crashworks

Verwandte Themen