4

我有以下代码:

#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)。

4

1 回答 1

5

这是您的 asm 构造的内容:

  • "=a"(x)中,您告诉编译器程序集将 ( =) 写入 %eax ( a) 寄存器,并且您希望编译器将该结果分配给 x ( (x))。
  • "a"(0)中,您告诉编译器您希望它(0)在 %eax ( a) 中放置一个 0 ( ),程序集会读取它。
  • 然后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。

于 2012-08-24T13:28:31.810 回答