Linux汇编错误“asm中的不可能约束条件”

11

我刚开始学习在Linux下的汇编。我已将以下代码保存为testasm.c,并通过gcc testasm.c -otestasm进行编译。
编译器回复:"impossible constraint 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;
}

我该如何解决这个问题? (我从这里复制了示例。)

Debian Lenny,内核版本为2.6.26-2-amd64
gcc版本为4.3.2(Debian 4.3.2-1.1)

解决方案:
请参见被接受的答案-似乎不再支持“modified”子句。

3个回答

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

似乎可以工作。我认为寄存器约束语法在某个时候发生了变化,但文档中并没有很好地记录。我觉得编写原始汇编代码并避免麻烦更容易。


好的,谢谢。看起来它不再喜欢“修改”的子句了,所以我猜我需要推入和弹出任何我改变的东西。 - slashmais
3
修改后的从句仍然可用;我认为问题在于,“output”隐含地指定了“modified”,因此在两个字段中都表示eax导致了问题。 - Stephen Canon

7
约束条件是单个字母(可能带有额外装饰),您可以指定多个替代项(即,立即操作数或寄存器为“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;
}

0
如果想要使用多行,那么这也可以运行。
  __asm__ __volatile__ (
        "addl %%ebx,%%eax; \
         addl %%eax, %%eax;" 
        : "=a"(foo) 
        : "a"(foo), "b"(bar)
    );

'

在编译器接受多行字符串(指令)前,应添加“\”。

'

1
这不是很好的建议。您正在指定要在输入和输出列表中使用的寄存器,但仍在实际汇编块内使用硬编码寄存器。您应该改用%0%1 - Daniel Kamil Kozar
@DanielKamilKozar:被接受的答案把所有东西都放在了一行里。所以,我使用了相同/类似的代码来展示如何在多行中完成它。我没有尝试修改原始接受的答案中使用的硬编码寄存器,因为我认为当人们将多行与单行进行比较时,这样更容易理解。 - Rahul Sreeram

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接