2009-02-14 8 views
8

Die GCC-Toolchain verwendet AT & T-Assembler-Syntax standardmäßig, aber Unterstützung für Intel-Syntax ist über die .intel_syntax Direktive verfügbar.So verwenden Sie Adresskonstanten in GCC x86 Inline-Assembly

Zusätzlich beide AT & T und Intel-Syntax sind in einer prefix und einer noprefix Version, die sich darin unterscheiden, ob sie benötigen Namen mit einem % Sigill Präfix registrieren.

Je nachdem, welche Direktiven vorhanden sind, ändert sich das Format für Adresskonstanten.

Betrachten wir die folgende C-Code

*(int *)0xdeadbeef = 0x1234; 

objdump -d Verwendung finden wir, dass es die folgenden Assemblerbefehl kompiliert

movl $0x1234,0xdeadbeef 

Da es keine Register beteiligt sind, ist dies die richtige Syntax für beide .att_syntax prefix und .att_syntax noprefix, dh. in C-Code eingebettet, sehen sie so aus

__asm__(".att_syntax prefix"); 
__asm__("movl $0x1234,0xdeadbeef"); 

__asm__(".att_syntax noprefix"); 
__asm__("movl $0x1234,0xdeadbeef"); 

Sie können die Adresskonstante optional mit Klammern umgeben, dh.

__asm__("movl $0x1234,(0xdeadbeef)"); 

wird auch funktionieren.

Wenn ein sigil auf eine Ebene Adreßkonstante hinzufügen, wird der Code Copile scheitern

__asm__("movl $0x1234,$0xdeadbeef"); // won't compile 

Wenn man diesen Ausdruck mit geklam- mert umgibt, wobei der Compiler falschen Code ohne Warnung aussenden, dh

__asm__("movl $0x1234,($0xdeadbeef)"); // doesn't warn, but doesn't work! 

Dies wird fälschlicherweise die Anweisung emittieren

movl $0x1234,0x0 

In Intel m ode muss einer Adreßkonstante ein Segmentregister sowie die Operandengröße und das Flag PTR vorangestellt werden, wenn Mehrdeutigkeiten möglich sind. Auf meinem Computer (ein Intel Dual-Core-Laptop mit Windows XP und aktuellen Versionen von MinGW und Cygwin GCC) wird standardmäßig das Register ds verwendet.

Eckige Klammern um die Konstante sind optional. Die Adresskonstante wird auch korrekt erkannt, wenn das Segmentregister weggelassen wird, aber die Klammern vorhanden sind. Das Auslassen des Registers gibt jedoch eine Warnung an mein System aus.

Im prefix Modus muss dem Segmentregister das Präfix % vorangestellt werden, aber nur die Verwendung von Klammern funktioniert weiterhin. Dies sind die verschiedenen Möglichkeiten, um die richtige Anweisung zu generieren:

__asm__(".intel_syntax noprefix"); 
__asm__("mov DWORD PTR ds:0xdeadbeef,0x1234"); 
__asm__("mov DWORD PTR ds:[0xdeadbeef],0x1234"); 
__asm__("mov DWORD PTR [0xdeadbeef],0x1234"); // works, but warns! 

__asm__(".intel_syntax prefix"); 
__asm__("mov DWORD PTR %ds:0xdeadbeef,0x1234"); 
__asm__("mov DWORD PTR %ds:[0xdeadbeef],0x1234"); 
__asm__("mov DWORD PTR [0xdeadbeef],0x1234"); // works, but warns! 

Weglassen beider Segmentregister und Klammern werden

__asm__("mov DWORD PTR 0xdeadbeef,0x1234"); // won't compile 

nicht kompilieren ich diese Frage markieren würde als Community Wiki, also wenn Sie Haben Sie etwas Nützliches hinzuzufügen, fühlen Sie sich frei, dies zu tun.nur

+0

Es ist natürlich nicht * nur * AS in der Werkzeugkette hier; Welche Version (en) von gcc sind beteiligt? Haben Sie die Ausgabe von gcc-S überprüft, um zu bestätigen, dass das, was Sie erwarten, in GNU eingespeist wird? –

+0

ok, ich war es, der versaut hat - zumindest teilweise; Ersetzen von '($ 0xdeadbeaf)' mit '0xdeadbeaf' scheint zu funktionieren; Ich werde die Frage nach dem Testen dieser ... bearbeiten – Christoph

+0

@Charles: ja, 'gcc -S' ergibt die erwarteten Ergebnisse – Christoph

Antwort

4

Die noprefix/prefix Richtlinien steuern, ob Register erfordern einen % Präfix (*) (zumindest scheint es so, und das ist der einzige Unterschied in der Dokumentation erwähnt). Wertliterale benötigen immer ein $ Präfix in AT & T-Syntax und niemals in Intel-Syntax. So sind die folgenden Werke:

__asm__(".intel_syntax prefix"); 
__asm__("MOV [DWORD PTR 0xDEADBEEF], 0x1234"); 

Wenn Sie wirklich geneigt sind Intel-Syntax Inline-Assembly in C-Code mit GCC kompiliert zu verwenden und mit GAS montiert, vergessen Sie nicht, auch nachdem es die folgenden hinzuzufügen, so dass der Monteur kann grok dem Rest der (AT & T-Syntax) Montage von GCC generiert:

__asm__(".att_syntax prefix"); 

die Argumentation I für das Präfix/noprefix Unterscheidung zu sehen ist, daß für AT & T-Syntax, die % Präfix nicht wirklich benötigt wird, um für Register auf Intel-Architektur, weil Register benannt sind. Aber für die Einheitlichkeit kann es da sein, weil einige andere Architekturen (d. H. SPARC) registriert sind, in welchem ​​Fall das Spezifizieren einer niedrigen Zahl alleine nicht eindeutig ist, ob eine Speicheradresse oder ein Register gemeint war.

1

Hier meine Ergebnisse sind:

*(int *)0xdeadbeaf = 0x1234; // reference implementation 

// AT&T: addresses without sigil; parentheses are optional 

__asm__(".att_syntax prefix"); 
__asm__("movl $0x1234,0xdeadbeaf");  // works 
__asm__("movl $0x1234,(0xdeadbeaf)"); // works 
__asm__("movl $0x1234,($0xdeadbeaf)"); // doesn't work, doesn't warn! 
//__asm__("movl $0x1234,$0xdeadbeaf"); // doesn't compile 
//__asm__("movl 0x1234,0xdeadbeaf"); // doesn't compile 
//__asm__("movl 0x1234,(0xdeadbeaf)"); // doesn't compile 

__asm__(".att_syntax noprefix"); 
// same as above: no registers used! 

// Intel: addresses with square brackets or segment register prefix 
// brackets without prefix will warn 

__asm__(".intel_syntax noprefix"); 
__asm__("mov DWORD PTR ds:0xdeadbeaf,0x1234");  // works 
__asm__("mov DWORD PTR ds:[0xdeadbeaf],0x1234"); // works 
__asm__("mov DWORD PTR [0xdeadbeaf],0x1234");  // works, but warns! 
//__asm__("mov DWORD PTR 0xdeadbeaf,0x1234");  // doesn't compile 

// `prefix` will add % to register names 

__asm__(".intel_syntax prefix"); 
__asm__("mov DWORD PTR %ds:0xdeadbeaf,0x1234");  // works 
__asm__("mov DWORD PTR %ds:[0xdeadbeaf],0x1234"); // works 
__asm__("mov DWORD PTR [0xdeadbeaf],0x1234");  // works, but warns! 
//__asm__("mov DWORD PTR 0xdeadbeaf,0x1234");  // doesn't compile 

__asm__(".att_syntax prefix"); 
+0

Wie ich in meiner Antwort angemerkt habe, glaube ich nicht, dass Noprefix und Präfix irgendwelche sind anders in dieser Hinsicht. Die Dokumentation sagt nur, dass% vor den Registernamen wirkt. Also sollte der gleiche Block unter noprefix auch unter prefix funktionieren. –

+0

@Tom: Leider ist das nicht der Fall - die 'noprefix' Version wird einen" Fehler: Unerwartetes Token ': '" ausgeben, wenn sie mit 'Präfix' verwendet wird: – Christoph

+0

@Tom: die Version, die eine Warnung ausgibt, funktioniert. – Christoph