我很难理解GCC内联汇编(x86)中约束的作用。 我已经读过手册,它详细解释了每个约束所做的事情。 问题是,即使我了解每个约束的作用,我对为什么会使用一个约束而不是另一个约束或其影响有很少的了解。
我意识到这是一个非常广泛的话题,因此一个小例子应该有助于缩小重点。 以下是一个简单的汇编程序,只需将两个数字相加。 如果发生整数溢出,则向输出C变量写入值
请注意,我在
但我真的不明白为什么你会使用一个约束条件而不是另一个。我的意思是,是的,我知道"r"表示变量应该在寄存器中,而"m"表示它应该在内存中 - 但我不太理解选择一个约束条件与选择另一个约束条件的影响,或者为什么如果我选择某些约束条件,加法操作就不能正常工作。
问题:1)在上面的示例代码中,为什么
我意识到这是一个非常广泛的话题,因此一个小例子应该有助于缩小重点。 以下是一个简单的汇编程序,只需将两个数字相加。 如果发生整数溢出,则向输出C变量写入值
1
。 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)是否有任何教程或在线资源详细介绍约束条件?
(只写)约束修饰符会给编译器重新使用相同的内存位置的权利,即使
b和
c`是具有不同内存位置的不同变量? - Channel72b
和c
是不同的变量,具有不同的内存位置”——这实际上是一个重要的假设,经常不适用。如果b
和c
是局部变量,很有可能它们都由寄存器支持,而不是内存位置。在这种情况下,内存位置只是一个临时的存储位置,纯粹是为了容纳您的m
约束而设置的,此时b
和c
可能会使用相同的临时位置。 - C. K. Youngb
和c
实际上都是由内存位置支持的,那么你就是正确的,通常它们不应该重叠。而且,如果一个由内存支持,另一个由寄存器支持...那么这两种情况都有可能。 - C. K. Young