2009-09-25 10 views
10

Ich beginne mit Assembler unter Linux. Ich habe den folgenden Code als testasm.c
gespeichert und kompilierte es mit: gcc testasm.c -otestasm
Der Compiler antwortet: "unmögliche Einschränkung in 'asm'".Linux Assembler Fehler "unmögliche Einschränkung in 'asm'"

#include <stdio.h> 
int main(void) 
{ 
    int foo=10,bar=15; 

    __asm__ __volatile__ ("addl %%ebx,%%eax" 
     : "=eax"(foo) 
     : "eax"(foo), "ebx"(bar) 
     : "eax" 
    ); 

    printf("foo = %d", foo); 

    return 0; 
} 

Wie kann ich dieses Problem lösen? (ich das Beispiel von here kopiert haben.)

Debian Lenny, kernel 2.6.26-2-amd64
gcc Version 4.3.2 (Debian 4.3.2-1.1)

Auflösung:
Siehe die akzeptierte Antwort - es scheint, die 'modifizierte' Klausel wird nicht mehr unterstützt.

Antwort

9
__asm__ __volatile__ ("addl %%ebx,%%eax" : "=a"(foo) : "a"(foo), "b"(bar)); 

scheint zu funktionieren. Ich glaube, dass sich die Syntax für Registerbeschränkungen irgendwann geändert hat, aber es ist nicht besonders gut dokumentiert. Ich finde es einfacher, rohe Montage zu schreiben und den Ärger zu vermeiden.

+0

Das funktioniert, danke. Scheint, dass es den "modifizierten" Teil nicht mehr mag, also denke ich, dass ich pushen muss, was auch immer ich ändere. – slashmais

+2

Die modifizierte Klausel funktioniert immer noch; Ich denke, das Problem ist, dass "output" implizit auch "modified" ("modifiziert") angibt, also verursachte das Vorhandensein von eax in beiden Feldern das Problem. –

0

Will man mehrzeilige verwenden, dann wird dies auch funktionieren ..

__asm__ __volatile__ (
     "addl %%ebx,%%eax; \ 
     addl %%eax, %%eax;" 
     : "=a"(foo) 
     : "a"(foo), "b"(bar) 
    ); 

‚\‘ sollte für den Compiler hinzugefügt werden, um eine mehrzeilige Zeichenfolge (die Befehle) zu übernehmen.

+0

Das ist kein sehr guter Rat. Sie geben die Register an, die in Eingabe- und Ausgabelisten verwendet werden sollen, verwenden jedoch weiterhin fest codierte Register im tatsächlichen Assembly-Block. Sie sollten stattdessen "% 0" und "% 1" verwenden. –

+0

@DanielKamilKozar: Die akzeptierte Antwort hatte alles in einer Zeile. Also habe ich den gleichen/ähnlichen Code verwendet, um zu zeigen, wie man es in Multiline macht. Ich habe nicht versucht, die hardcoded Register zu ändern, die in der ursprünglichen angenommenen Antwort verwendet wurden, da ich dachte, dass es leichter zu verstehen ist, wenn man die Mehrfachleitung mit einzeln vergleicht. –

5

Die Einschränkungen sind einzelne Buchstaben (möglicherweise mit zusätzlichen Dekorationen), und Sie können mehrere Alternativen angeben (d. H. Ein Initialoperand oder -register ist "ir"). So bedeutet die Beschränkung "eax" Beschränkungen "e" (vorzeichenbehaftete 32-Bit-Ganzzahlkonstante), "a" (Register eax) oder "x" (irgendein SSE-Register). Das ist etwas anders als das, was OP bedeutete ... und Ausgabe zu einem "e" macht eindeutig keinen Sinn. Wenn ein Operand (in diesem Fall eine Eingabe und eine Ausgabe) identisch mit einem anderen Operanden sein muss, verweisen Sie außerdem auf eine Zahlenbeschränkung. Es gibt keine Notwendigkeit zu sagen, dass Eax verprügelt wird, es ist eine Ausgabe. Sie können sich auf die Argumente im Inline-Code beziehen, indem Sie% 0,% 1, ... verwenden und keine expliziten Registernamen verwenden müssen. So ist die richtige Version für den Code, wie OP bestimmt wäre:

#include <stdio.h> 

int main(void) 
{ 
    int foo=10, bar=15; 

    __asm__ __volatile__ (
     "addl %2, %0" 
     : "=a" (foo) 
     : "0" (foo), "b" (bar) 
    ); 

    printf("foo = %d", foo); 

    return 0; 
} 

Eine bessere Lösung wäre 2 zu ermöglichen%, etwas zu sein, und% 0 ein Register (als x86 erlaubt, aber man müßte Überprüfen Sie Ihre Maschine Handbuch):

#include <stdio.h> 

int main(void) 
{ 
    int foo=10, bar=15; 

    __asm__ __volatile__ (
     "addl %2, %0" 
     : "=r" (foo) 
     : "0" (foo), "g" (bar) 
    ); 

    printf("foo = %d", foo); 

    return 0; 
}