2009-09-25 10 views
10

Zaczynam od asemblera pod Linuksem. Mam zapisany następujący kod jako testasm.c
i skompilowałem go z: gcc testasm.c -otestasm
Kompilator odpowiada: "niemożliwe ograniczenie w" ASM "".Błąd asemblera systemu Linux "niemożliwe ograniczenie w '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; 
} 

Jak mogę rozwiązać ten problem? (mam skopiowane przykład z here.)

Debian Lenny, jądro 2.6.26-2-amd64
wersja gcc 4.3.2 (Debian 4.3.2-1.1)

Rozdzielczość:
Zobacz zaakceptowaną odpowiedź - wygląda na to, że klauzula "zmodyfikowana" nie jest już obsługiwana.

Odpowiedz

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

wydaje się działać. Wierzę, że składnia ograniczeń rejestru zmieniła się w pewnym momencie, ale nie jest to dobrze udokumentowane. Ułatwiam pisanie nieprzetworzonego zestawu i unikam kłopotów.

+0

To działa, dziękuję. Wygląda na to, że nie podoba mi się już "zmodyfikowana" klauzula, więc domyślam się, że będę musiał naciskać i zmieniać, co zmienię. – slashmais

+2

Zmodyfikowana klauzula nadal działa; Myślę, że problem polega na tym, że "wyjście" domyślnie określa również "zmodyfikowany", więc przyczyną problemu był eax reprezentowany w obu obszarach. –

0

Jeśli ktoś chce korzystać multilinii, to będzie również działać ..

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

„\” należy dodać do kompilatora zaakceptować multilinii ciąg (z instrukcjami).

+0

To nie jest dobra rada. Określasz rejestry, które mają być używane na listach wejściowych i wyjściowych, ale nadal używają zakodowanych na stałe rejestrów wewnątrz rzeczywistego bloku złożenia. Powinieneś używać zamiast tego '% 0' i'% 1'. –

+0

@ Danielanam Kozar: Przyjęta odpowiedź miała wszystko w jednym wierszu. Tak więc użyłem tego samego/podobnego kodu, aby pokazać, jak to zrobić w wielolinie. Nie próbowałem modyfikować zakodowanych na stałe rejestrów używanych w pierwotnie zaakceptowanej odpowiedzi, ponieważ uważałem, że łatwiej będzie zrozumieć, kiedy porównuje się linię multi do singla. –

5

Ograniczenia to pojedynczych liter (ewentualnie z dodatkowymi zdobieniami) i można podać kilka alternatyw (tj. Bezpośredni operand lub rejestr to "ir"). Zatem ograniczenie "eax" oznacza ograniczenia "e" (podpisana 32-bitowa stała całkowita), "a" (rejestr eax) lub "x" (jakikolwiek rejestr SSE). To jest trochę inne, co OP oznaczało ... i wyjście na "e" najwyraźniej nie ma sensu. Ponadto, jeśli jakiś operand (w tym przypadku dane wejściowe i wyjściowe) musi być taki sam jak inny, odwołujesz się do niego za pomocą ograniczenia liczbowego. Nie ma potrzeby mówić, że eax zostanie spłaszczony, to wynik. Możesz odwoływać się do argumentów w kodzie wstawianym przez% 0,% 1, ..., nie trzeba używać jawnych nazw rejestrów. Tak poprawna wersja kodu w sposób zamierzony przez OP byłoby:

#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; 
} 

Lepszym rozwiązaniem byłoby umożliwienie% 2 za coś, a% 0 rejestr (jak x86 pozwala, ale trzeba by sprawdź swój podręcznik maszyny):

#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; 
} 
Powiązane problemy