2010-02-27 45 views
2

再次,我玩MinGW內聯程序集。MinGW內聯程序集中的「錯誤:向後引用未知標籤...」

#include <stdio.h> 

int foobar(int); 

int main(){ 
int n = 0; 
printf("Number: "); 
scanf("%d", &n); 
printf("\n%d",foobar(n)); 
return 0; 
} 

int foobar(int num){ 
int result = 0; 
asm(".intel_syntax noprefix\n"); 
asm("mov eax, num\n"); 
asm("add eax, 110b\n"); 
asm("sub eax, 2\n"); 
    asm("mov result, eax\n"); 
return result; 
} 

編譯:

C:\Users\Andre\Codes>gcc asmtest.c -o asmtest -masm=intel

哎喲,有錯誤:

C:\Users\Andre\AppData\Local\Temp\ccqny4yb.s: Assembler messages: C:\Users\Andre\AppData\Local\Temp\ccqny4yb.s:53: Error: backward ref to unknown label "110:"

有什麼不對嗎?我認爲我的代碼已經有效了嗎?

+0

如果它是未知的,它是如何知道它是向後? – bmargulies 2010-02-28 17:05:42

回答

1

GCC與AT & T風格的程序集配合使用效果最佳,而GAS並未實現所有的Intel語法。你的直接問題來自110b不被解釋爲一個數字,但那不是全部。

您不能直接在GCC的內聯彙編語法中引用變量。你必須把它寫這樣的(使用默認-masm=att):

int foobar(int num) { 
    int result; 
    asm("mov %1, %%eax\n\t" 
     "add $6, %%eax\n\t" 
     "sub $2, %%eax\n\t" 
     "mov %%eax, %0" 
     : "=g" (result) 
     : "g" (num) 
     : "eax", "cc"); 
    return result; 
} 

第一個冒號是一個逗號分隔的輸出操作數列表之後。由於"=g" (result)是第一個約束,因此result的別名爲%0"=g"向GCC指示%0可以是任何通用寄存器或存儲器,並且將僅被寫入。 (+而不是=將表示可讀寫,GCC可能會決定重複使用同一個寄存器用於多種目的,因此您必須明確告訴它如何使用所有內容)。

第二個冒號輸入操作數的逗號分隔列表。由於"g" (num)是第二個約束,因此num的別名爲%1"g"表示只能讀取。

第三個冒號後是逗號分隔的clobbers列表。這告訴GCC,即使他們不是輸入,也不輸出的內聯彙編可能會改變這些寄存器/內存,這樣GCC必須重新加載它是在他們對面的內聯彙編保留任何信息。在這裏,我們明顯改變了%eax,條件碼(標誌)寄存器也受到add/sub的影響。

看編譯器生成的組件:

 
$ cc -S -o- -m32 asmtest.c | sed -n /globl.foobar/,/-foobar/p 
.globl foobar 
     .type foobar, @function 
foobar: 
     pushl %ebp 
     movl %esp, %ebp 
     subl $16, %esp 
#APP 
# 15 "asmtest.c" 1 
     mov 8(%ebp), %eax 
     add $6, %eax 
     sub $2, %eax 
     mov %eax, -4(%ebp) 
# 0 "" 2 
#NO_APP 
     movl -4(%ebp), %eax 
     leave 
     ret 
     .size foobar, .-foobar 

編譯器已經決定使用的直接numresult堆疊位置。如果我們使用:"=r":"r"約束(這意味着唯一寄存器允許的),而不是:"=g":"g"(其允許寄存器或存儲器位置),則編譯器將它們複製到/從之前寄存器/後的內聯組件。

 
$ cc -S -o- -m32 asmtest.c | sed -n /globl.foobar/,/-foobar/p 
.globl foobar 
     .type foobar, @function 
foobar: 
     pushl %ebp 
     movl %esp, %ebp 
     subl $16, %esp 
     movl 8(%ebp), %edx 
#APP 
# 15 "asmtest.c" 1 
     mov %edx, %eax 
     add $6, %eax 
     sub $2, %eax 
     mov %eax, %edx 
# 0 "" 2 
#NO_APP 
     movl %edx, -4(%ebp) 
     movl -4(%ebp), %eax 
     leave 
     ret 
     .size foobar, .-foobar 

如果你真的想使用Intel語法,把它放在一個單獨的.s的源文件,以NASM獨立組裝,然後將物體連接在一起。

 
$ cat asmtest.c 
#include <stdio.h> 

int foobar(int); 
/* int foobar(int) __attribute__((fastcall)); */ 

int main() { 
    int n = 0; 
    printf("Number: "); 
    scanf("%d", &n); 
    printf("%d\n", foobar(n)); 
    return 0; 
} 
$ cat foobar.s 
global foobar 
foobar: 
     mov eax,[esp+4] # take this line out if C prototype is marked fastcall 
     sub eax,110b 
     add eax,2 
     ret 
$ nasm -f elf foobar.s 
$ cc -m32 asmtest.c foobar.o 
$ ./a.out 
Number: 30 
26 

(雖然-f elf是不適用於Windows正確的。也許-f win32?而由於Windows的愚蠢,你可能在裝配中使用的名稱_foobar。)

+0

非常感謝。這樣可行。現在我想知道,GCC如何知道%0是結果的別名,而%1是num的別名。我仍然不明白。 順便說一句,這3條線是什麼意思? 「結果」 :「g」(num) :「eax」);「g」(num) : – anta40 2010-02-27 15:54:31

+0

@ anta40更多詳細信息已添加。但是,您應該閱讀GCC手冊的整個http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html部分。 – ephemient 2010-02-27 17:37:45

相關問題