Подтвердить что ты не робот

Ошибка сборщика Linux "невозможное ограничение в asm"

Я начинаю с ассемблера под Linux. Я сохранил следующий код как testasm.c
и скомпилировал его с помощью: gcc testasm.c -otestasm
Компилятор отвечает: "невозможное ограничение в 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;
}

Как я могу решить эту проблему? (Я скопировал пример из здесь.)

Debian Lenny, ядро ​​2.6.26-2-amd64
gcc версия 4.3.2 (Debian 4.3.2-1.1)

Разрешение:
См. Принятый ответ - кажется, что предложение "изменено" больше не поддерживается.

4b9b3361

Ответ 1

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

похоже, работает. Я считаю, что синтаксис ограничений регистра изменился в какой-то момент, но он не очень хорошо документирован. Мне легче писать сырую сборку и избегать хлопот.

Ответ 2

Ограничения - это одиночные буквы (возможно, с дополнительными украшениями), и вы можете указать несколько альтернатив (т.е. промежуточный операнд или регистр - "ir" ). Таким образом, ограничение "eax" означает ограничения "e" (подписанная 32-разрядная целочисленная константа), "a" (регистр eax) или "x" (любой регистр SSE). Это немного отличается от того, что означает OP... и вывод на "e" явно не имеет никакого смысла. Кроме того, если какой-либо операнд (в данном случае вход и выход) должен быть таким же, как другой, вы ссылаетесь на него с помощью ограничения числа. Нет необходимости говорить, что eax будет сбито, это выход. Вы можете ссылаться на аргументы встроенного кода на% 0,% 1,..., не нужно использовать явные имена регистров. Поэтому правильная версия для кода, как предполагалось OP, будет:

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

Лучшим решением было бы позволить% 2 быть чем угодно, а% 0 - регистром (как позволяет x86, но вам нужно будет проверить свое руководство по машине):

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

Ответ 3

Если вы хотите использовать многострочный, то это также сработает.

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

'\' следует добавить для компилятора для принятия многострочной строки (инструкции).