[英]GCC inline assembly: constraints
我很难理解角色约束在GCC内联汇编(x86)中的作用。 我已经阅读了手册 ,它准确地解释了每个约束的作用。 问题在于,即使我理解每个约束的作用,我也很少理解为什么要使用一个约束而不是另一个约束,或者它可能带来什么。
我意识到这是一个非常广泛的话题,所以一个小例子应该有助于缩小焦点。 以下是一个简单的asm例程,它只添加了两个数字。 如果发生整数溢出,则将值1
写入输出C变量。
int32_t a = 10, b = 5;
int32_t c = 0; // overflow flag
__asm__
(
"addl %2,%3;" // Do a + b (the result goes into b)
"jno 0f;" // Jump ahead if an overflow occurred
"movl $1, %1;" // Copy 1 into c
"0:" // We're done.
:"=r"(b), "=m"(c) // Output list
:"r"(a), "0"(b) // Input list
);
现在这个工作正常,除了我必须随意摆弄约束,直到我让它正常工作。 最初,我使用了以下约束:
:"=r"(b), "=m"(c) // Output list
:"r"(a), "m"(b) // Input list
请注意,我使用b
的“m”约束而不是“0”。 这有一个奇怪的副作用,如果我用优化标志编译并调用该函数两次,由于某种原因,加法运算的结果也会存储在c
。 我最终读到了“ 匹配约束 ”,它允许您指定变量将用作输入和输出操作数。 当我将"m"(b)
改为"0"(b)
它起作用了。
但我真的不明白为什么你会使用一个约束而不是另一个约束。 我的意思是,是的,我知道,“R”是指变量应该是在寄存器和“m”意味着它应该是在内存中-但我真的不明白什么选择一个对另一个的影响是,为什么加如果我选择某种约束组合,则操作无法正常工作。
问题:1)在上面的示例代码中,为什么b
上的“m”约束导致c
被写入? 2)是否有任何教程或在线资源更详细地介绍约束?
这里有一个例子可以更好地说明为什么你应该仔细选择约束(与你的功能相同,但也许更简洁一点):
bool add_and_check_overflow(int32_t& a, int32_t b)
{
bool result;
__asm__("addl %2, %1; seto %b0"
: "=q" (result), "+g" (a)
: "r" (b));
return result;
}
因此,使用的约束是: q
, r
和g
。
q
表示只能选择eax
, ecx
, edx
或ebx
。 这是因为set*
指令必须写入8位可寻址寄存器( al
, ah
,...)。 使用b
在%b0
装置,用最低8位部分( al
, cl
,...)。 m
或g
; 将r
用于至少一个操作数。 g
(通用)。 另外,在上述的例子中,我选择使用g
(而不是r
用于a
因为引用通常作为存储器指针来实现,所以使用r
约束将要求第一复制指涉到寄存器,然后复制回来。 使用g
,可以直接更新指示对象。
至于为什么你的原始版本用加法值覆盖你的c
,那是因为你在输出槽中指定了=m
,而不是(比方说) +m
; 这意味着允许编译器为输入和输出重用相同的内存位置。
在您的情况下,这意味着两个结果(因为相同的内存位置用于b
和c
):
c
被b
的值覆盖(添加的结果)。 c
变为1(并且b
也可能变为1,具体取决于代码的生成方式)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.