我有以下代码:
#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)。
答案 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。所以,会发生什么:
所以,这有效,但效率低下。你可以用这个效果:
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。