2010-10-10 5 views
33

In meinen laufenden Experimenten mit GCC Inline Assembly ist mir ein neues Problem bezüglich Etiketten und Inline Code aufgefallen.Etiketten in GCC Inline Assembly

Betrachten Sie den folgenden einfachen Sprung:

__asm__ 
(
    "jmp out;" 
    "out:;" 
    : 
    : 
); 

Dies tut nichts, außer Sprung zum out Label. Wie es ist, kompiliert dieser Code gut. Wenn Sie es jedoch in eine Funktion einfügen und dann mit Optimierungsflags kompilieren, beschwert sich der Compiler: "Fehler: Symbol 'out' ist bereits definiert".

Was scheint zu geschehen ist, dass der Compiler diesen Assemblercode jedes Mal wiederholt, wenn er die Funktion einfügt. Dies führt dazu, dass das Label out dupliziert wird, was zu mehreren out Etiketten führt.

Also, wie kann ich das umgehen? Ist es wirklich nicht möglich, Etiketten in der Inline-Montage zu verwenden? Diese tutorial on GCC inline assembly erwähnt, dass:

Thus, you can make put your assembly into CPP macros, and inline C functions, so anyone can use it in as any C function/macro. Inline functions resemble macros very much, but are sometimes cleaner to use. Beware that in all those cases, code will be duplicated, so only local labels (of 1: style) should be defined in that asm code.

Ich habe versucht, mehr Informationen über diese „lokalen Labels“ zu finden, aber kann nicht scheinen, etwas zu finden, in Bezug Montage Inline. Es sieht so aus, als würde das Tutorial sagen, dass eine lokale Bezeichnung eine Zahl gefolgt von einem Doppelpunkt ist (wie 1:), also habe ich versucht, eine solche Bezeichnung zu verwenden. Interessanterweise kompilierte der Code, aber zur Laufzeit löste er einfach einen Segmentierungsfehler aus. Hmm ...

Also irgendwelche Vorschläge, Hinweise, Antworten ...?

Antwort

44

Eine Deklaration eines lokalen Labels ist in der Tat eine Nummer, gefolgt von einem Doppelpunkt. Aber eine Referenz zu einem lokalen Etikett braucht ein Suffix von f oder b, je nachdem, ob Sie nach vorne oder nach hinten schauen wollen - d. H. 1f bezieht sich auf die nächste 1: Label in Vorwärtsrichtung.

Also die Erklärung der Bezeichnung als 1: ist korrekt; aber um es zu referenzieren, müssen Sie jmp 1f sagen (weil Sie in diesem Fall vorwärts springen).

+1

@MichaelGraczyk Lokale Beschriftungen sind keine x86-spezifische Funktion. GAS unterstützt sie unabhängig vom CPU- oder Objektdateiformat, und so auch fast alle anderen Unixy-Assembler (wie ich es noch nie gesehen habe, auch 1995). – zwol

+1

Tatsächlich würde 'jmp 1' als Sprung zu Position 1 betrachtet, also der Segfault. – greggo

24

Nun, diese Frage wird nicht jünger, aber es gibt zwei andere interessante Lösungen.

1) In diesem Beispiel wird% = verwendet. % = in einer Assembler-Vorlage wird durch eine Zahl ersetzt, die für jedes insn in der gesamten Kompilierung eindeutig ist. Dies ist nützlich, um lokale Labels zu erstellen, auf die in einem gegebenen insn mehr als einmal Bezug genommen wird. Beachten Sie, dass Sie (anscheinend) mindestens eine Eingabe haben müssen (obwohl Sie diese wahrscheinlich nicht verwenden müssen).

int a = 3; 
asm (
    "test %0\n\t" 
    "jnz to_here%=\n\t" 
    "jz to_there%=\n\t" 
    "to_here%=:\n\t" 
    "to_there%=:" 
    ::"r" (a)); 

Diese Ausgänge:

test %eax 
jnz to_here14 
jz to_there14 
to_here14: 
to_there14: 

Alternativ können Sie die asm goto (Hinzugefügt in v4.5 glaube ich) verwenden. Dadurch können Sie zu c-Beschriftungen statt nur asm-Beschriftungen springen:

asm goto ("jmp %l0\n" 
: /* no output */ 
: /* no input */ 
: /* no clobber */ 
: gofurther); 

printf("Didn't jump\n"); 

// c label: 
gofurther: 
printf("Jumped\n"); 
+4

Ich liebe Stackoverflow für solche Sachen. – demonkoryu