英特尔与GCC的asm语法:未定义的引用

时间:2016-04-01 14:36:38

标签: c gcc

我正在运行Ubuntu 64位,我有这段代码:

#include <stdio.h>

int main() {
    int x, y;
    int z = 0;

    printf("Enter two numbers: ");
    scanf("%d %d", &x, &y);

    asm(".intel_syntax noprefix\n"   

       "MOV EAX, _x\n"   
       "MOV ECX, _y\n"   
       "ADD EAX, ECX\n"
       "MOV _z, EAX\n"

       ".att_syntax\n"); 

     printf("%d + %d = %d \n", x, y, z);

    return 0;
}

根据在学校的讲座,它应该可以工作,但是当我尝试用GCC编译它时,我得到了这个错误:

/tmp/ccU4vNLr.o: In function `main':
Jung_79913_211.c:(.text+0x4a): undefined reference to `_x'
Jung_79913_211.c:(.text+0x51): undefined reference to `_y'
Jung_79913_211.c:(.text+0x5a): undefined reference to `_z'
collect2: error: ld returned 1 exit status

我知道GCC默认使用AT&amp; T asm语法,但我需要在大学使用英特尔systax。所以问题是,我怎么能让它发挥作用?

1 个答案:

答案 0 :(得分:3)

两件事:首先,在Linux上,您不要在汇编中使用下划线为C符号添加前缀,因此xyz代替_x_y_z。其次,这三个变量是自动变量。您不能像这样引用自动变量,因为没有为它们创建符号。相反,您需要告诉编译器将这些变量移交到程序集中。您还需要将寄存器eaxecx标记为已破坏,因为您的程序集会修改它们。有关详细信息,请阅读this documentation。以下是如何使用您的代码:

asm(
   "MOV EAX, %1\n"   
   "MOV ECX, %2\n"   
   "ADD EAX, ECX\n"
   "MOV %0, EAX\n"
   : "=r" (z) : "r" (x), "r" (y) : "eax", "ecx");

您还需要使用-masm=intel进行编译才能正常工作,否则gcc将在AT&amp; T语法中插入对寄存器的引用,从而导致编译错误。更好的是,如果您计划为gcc编写大量内联汇编,请学习AT&amp; T语法。