我有以下代码:
#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)。
最佳答案
这是你的 asm 结构说的:
- 在
"=a"(x)
中,您告诉编译器程序集将写入 (=
) 到 %eax (a
) 注册,您希望编译器将该结果分配给 x ((x)
)。 - 在
"a"(0)
中,您告诉编译器您希望它在 %eax (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。
关于c - 将 0 分配给 gcc 扩展程序集中的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12109376/