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

4 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Eri*_*hil 5

这是你的asm结构所说的:

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

那么,会发生什么:

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

所以,这有效,但效率低下.你可以用这个得到同样的效果:

asm volatile("movl $0, %[MyName]"
    : [MyName] "=r" (x)
);
Run Code Online (Sandbox Code Playgroud)

这说的是:

  • 没有输入(因为第二个":"不存在).
  • 和以前一样,=告诉编译器这些指令会写一个结果.
  • r说的结果将被写入寄存器,但是编译器到达挑选寄存器.
  • [MyName]告诉编译器来改变%[MyName],它出现在汇编代码,在登记编译精选的名称.
  • 和以前一样,在(x)汇编代码之后使用寄存器中的值作为x的新值.
  • 最后,指令movl $0, %[MyName]说将0移动到%[MyName]命名的寄存器.

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

能够像我一样命名操作数[MyName]是GCC的一个新功能.如果您的版本没有它,您可以这样做:

asm volatile("movl $0, %0"
    : "=r" (x)
);
Run Code Online (Sandbox Code Playgroud)

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