代码之家  ›  专栏  ›  技术社区  ›  slashmais

Linux汇编程序错误“asm中不可能的约束”

  •  10
  • slashmais  · 技术社区  · 16 年前

    我从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;
    }
    

    我如何解决这个问题? (我从 here )

    Debian Lenny,内核2.6.26-2-amd64
    GCC 4.3.2版(Debian 4.3.2-1.1)

    分辨率 :
    请参阅已接受的答案-似乎不再支持“modified”子句。

    3 回复  |  直到 12 年前
        1
  •  9
  •   Stephen Canon    16 年前
    __asm__ __volatile__ ("addl %%ebx,%%eax" : "=a"(foo) : "a"(foo), "b"(bar));
    

    似乎有用。我相信寄存器约束的语法在某一点上发生了变化,但是它并没有被很好地记录下来。我发现编写原始程序集和避免麻烦更容易。

        2
  •  5
  •   vonbrand    12 年前

    约束条件是 单一的 字母(可能带有额外的修饰),您可以指定几个替代项(即,中间操作数或寄存器是“ir”)。因此约束“e a x”表示约束“e”(有符号32位整数常量)、“a”(寄存器e a x)或“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
  •  0
  •   Taylor Fireman    15 年前

    如果你想使用多行,那么这也可以。

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

    应添加'\'以便编译器接受多行字符串(指令)。

    推荐文章