簡體   English   中英

Linux匯編程序錯誤“'asm'中不可能的約束”

[英]Linux assembler error “impossible constraint in ‘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)

決議
看到接受的答案 - 似乎不再支持'modified'子句。

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

似乎工作。 我相信寄存器約束的語法在某些時候發生了變化,但它並沒有很好的記錄。 我發現編寫原始組件更容易,避免麻煩。

約束是單個字母(可能帶有額外的裝飾),您可以指定幾個備選方案(即,中間操作數或寄存器是“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;
}

如果想要使用多線,那么這也將有效..

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

應添加'\\'以使編譯器接受多行字符串(指令)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM