MinGW内联汇编中的“错误:向后引用未知标签...”

时间:2010-02-27 01:26:44

标签: c gcc mingw inline-assembly

再次,我使用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:”

这里有什么问题?我认为我的代码已经有效了吗?

1 个答案:

答案 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

编译器决定直接使用numresult的堆栈位置。如果我们使用:"=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