何时在扩展GCC内联汇编中使用特定操作数约束?

何时在扩展GCC内联汇编中使用特定操作数约束?,c,gcc,assembly,x86,inline-assembly,C,Gcc,Assembly,X86,Inline Assembly,在扩展GCC内联汇编中,我很难理解何时使用特定的输入操作数约束而不是另一个 例如: int x = 42; asm("movl %0, %%eax;" : /* no outputs */ : "r"(x) : "%eax"); 我知道“r”告诉编译器使用寄存器保存x的值,但是什么时候使用“g”或“m”更合适?使用“m”是否会破坏此代码,因为我使用的是注册目的地;操作数约束的“g”是否太“模糊”?使用的约束很大一部分是它所描述的类型是否在您的指令中起作用。在mov%0、

在扩展GCC内联汇编中,我很难理解何时使用特定的输入操作数约束而不是另一个

例如:

int x = 42;
asm("movl %0, %%eax;"
    : /* no outputs */
    : "r"(x)
    : "%eax");

我知道
“r”
告诉编译器使用寄存器保存
x
的值,但是什么时候使用
“g”
“m”
更合适?使用
“m”
是否会破坏此代码,因为我使用的是注册目的地;操作数约束的“g”是否太“模糊”?

使用的约束很大一部分是它所描述的类型是否在您的指令中起作用。在
mov%0、%%eax
中,可以将寄存器、内存引用或立即操作数替换为
%0
,汇编程序将接受它。因此,可以对约束使用
g

如果有
mov%0,4(%%esp)
,则不能允许
%0
作为内存引用,因为
4(%%esp)
是内存引用,并且没有接受两个内存引用的
mov
指令形式。因此,您需要使用诸如
r
之类的约束来要求
%0
成为寄存器


(请注意,此代码本身是无用的。只要
asm
完成,编译器就可以自由地使用
%eax
执行它想要的任何操作,因此没有理由期望
x
将保留在寄存器中。将某些内容移动到
%eax
只能在使用
%eax
的指令序列中使用。)在允许编译器再次拥有控制权之前。)

+1.同样有趣的是,64位的“版本”必须使用
“rme”
作为一种约束,因为64位立即数不能用
movq
加载。如果可能,使用
g
有什么好处吗?@VilhelmGray:这给了编译器灵活性。如果使用
m
但该值位于最近计算的寄存器中,则编译器必须将其存储到内存中。或者如果它是com堆积时间常数,但如果使用
r
,则编译器必须将该值放入寄存器,而
g
将允许它使用立即数操作数。