再次,我使用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&gt; gcc asmtest.c -o asmtest -masm = intel
哎呀,有错误:
C:\用户\安德烈\应用程序数据\本地\ TEMP \ ccqny4yb.s: 汇编程序消息: C:\用户\安德烈\应用程序数据\本地的\ Temp \ ccqny4yb.s:53: 错误:向后引用未知标签 “110:”
这里有什么问题?我认为我的代码已经有效了吗?
答案 0 :(得分:1)
GCC最适合AT&amp; T样式汇编,而GAS并未实现所有英特尔语法。您的直接问题来自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可能决定重复使用同一个寄存器用于多种目的,因此您必须明确告诉它将如何使用所有内容。)< / p>
第二个冒号后面是逗号分隔的输入操作数列表。由于"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"
(允许寄存器或内存位置),编译器会在内联汇编之前/之后将它们复制到寄存器中。 / p>
$ 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
如果您真的想使用英特尔语法,请将其放在单独的.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
。