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
編譯器已經決定使用的直接num
和result
堆疊位置。如果我們使用:"=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
。)
如果它是未知的,它是如何知道它是向後? – bmargulies 2010-02-28 17:05:42