将0分配给gcc扩展程序集中的变量

时间:2012-08-24 12:25:27

标签: c assembly inline-assembly

我有以下代码:

#include <stdio.h>
void main(){
    int x=0, y=0,i=100;
    for (;i<1000; i++,x+=32){
        if (x == 25*32) {
            y+=32;
            asm volatile("pushl %%eax\n\t"
                         "movl $0, %%eax\n\t"
                         "popl %%eax\n\t"
                         :"=a"(x)
                         :"a"(0)
                         );
        }
        printf("%d %d\n", x, y);
    }
}

基本上,我想要做的是,将变量x设置为0,但我不太明白汇编代码的作用,它实际上将x设置为0,但我不确定最新情况。谁能解释一下发生了什么? (只是为了学习汇编和C)。

1 个答案:

答案 0 :(得分:5)

这是你的asm构造所说的:

  • "=a"(x)中,您告诉编译器程序集将写入(=)到%eax(a)寄存器,并且您希望编译器将该结果分配给x ((x))。
  • "a"(0)中,您告诉编译器您希望它在%eax((0))中放置0(a),并且程序集将读取它。
  • 然后push %%eax将%eax保存在堆栈上,movl $0, %%eax将0添加到%eax中,popl %%eax将保存的值恢复为%eax。

所以,会发生什么:

  • 编译器将0放在%eax中。
  • 您的指令在堆栈中保存0,将0移至%eax,并从堆栈中恢复0。
  • 编译器使用%eax中的0作为x。
  • 的值

所以,这有效,但效率低下。你可以用这个效果:

asm volatile("movl $0, %[MyName]"
    : [MyName] "=r" (x)
);

这说的是:

  • 没有输入(因为第二个“:”不存在)。
  • 和以前一样,=告诉编译器这些指令会写一个结果。
  • r表示结果将写入寄存器,但编译器会选择寄存器。
  • [MyName]告诉编译器将汇编代码中出现的%[MyName]更改为编译器选择的寄存器名称。
  • 和以前一样,(x)表示在汇编代码之后使用寄存器中的值作为x的新值。
  • 最后,指令movl $0, %[MyName]表示将0移至%[MyName]指定的寄存器。

因为编译器可以选择寄存器,所以不必以汇编语言保存和恢复它。编译器负责确保它不需要其他任何寄存器。

能够像[MyName]一样命名操作数是GCC中的一项新功能。如果你的版本没有,你可以这样做:

asm volatile("movl $0, %0"
    : "=r" (x)
);

没有名称,每个操作数都会得到一个从0开始的数字,并按照操作数出现在输入/输出说明符中的顺序递增。由于我们只有一个操作数,因此它是%0。