GCC内联汇编:限制 [英] GCC inline assembly: constraints
问题描述
我难以理解的作用制约GCC内联汇编(x86)的发挥。我已阅读手册,这正好说明每个约束做什么。问题是,即使我明白每个约束做什么,我有为什么要使用一个约束了另一个,或影响可能是什么了解甚少。
I'm having difficulty understanding the role constraints play in GCC inline assembly (x86). I've read the manual, which explains exactly what each constraint does. The problem is that even though I understand what each constraint does, I have very little understanding of why you would use one constraint over another, or what the implications might be.
我意识到这是一个非常广泛的话题,所以一个小例子应有助于缩小的焦点。下面是一个简单的汇编程序这只是增加了两个数字。如果发生整数溢出,它 1
的值写入到输出C变量。
I realize this is a very broad topic, so a small example should help narrow the focus. The following is a simple asm routine which just adds two numbers. If an integer overflow occurs, it writes a value of 1
to an output C variable.
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
);
现在这个工作正常,但我不得不任意的制约拨弄,直到我得到它才能正常工作。本来,我用了以下的限制:
Now this works fine, except I had to arbitrarily fiddle with the constraints until I got it to work correctly. Originally, I used the following constraints:
:"=r"(b), "=m"(c) // Output list
:"r"(a), "m"(b) // Input list
请注意,而不是一个0,我用 B
一个M的约束。这有一个奇怪的副作用,在那里,如果我与优化标志编译和调用的函数两次,由于某种原因,加法运算的结果也将得到保存在 C
。我终于了解匹配约束的,它允许你指定一个变量是要同时用作输入和输出操作数。当我改变了M(B)
到0(B)
它的工作。
Note that instead of a "0", I use an "m" constraint for b
. This had a weird side effect where if I compiled with optimization flags and called the function twice, for some reason the result of the addition operation would also get stored in c
. I eventually read about "matching constraints", which allows you to specify that a variable is to be used as both an input and output operand. When I changed "m"(b)
to "0"(b)
it worked.
但我真的不明白,你为什么会用一个约束另一些人。我的意思是,是的,我明白,R是指变量应该是在寄存器和M是指它应该是在内存中 - 但我不的真正的明白了选择一个的影响另一个是,为什么如果我选择的约束的某种组合加法操作无法正常工作。
But I don't really understand why you would use one constraint over another. I mean yeah, I understand that "r" means the variable should be in a register and "m" means it should be in memory - but I don't really understand what the implications of choosing one over another are, or why the addition operation doesn't work correctly if I choose a certain combination of constraints.
问题:1)在上面的例子中code,为什么在事业
来获得写入? 2)有哪些进入更详细的关于约束的任何教程或在线资源?米约束B,
C
Questions: 1) In the above example code, why did the "m" constraint on b
cause c
to get written to? 2) Is there any tutorial or online resource which goes into more detail about constraints?
推荐答案
下面是一个例子,以更好地说明为什么你应该仔细选择的限制(同样的功能是你的,但也许写得有点更简洁):
Here's an example to better illustrate why you should choose constraints carefully (same function as yours, but perhaps written a little more succinctly):
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;
}
所以,使用的制约因素:①
,研究
和先按g
。
-
①
意味着只有EAX
,ECX
,EDX
或EBX
可以选择。这是因为设置*
指令必须写一个8位寻址寄存器(人
,啊
,...)。 b 在%B0
表示,用最低的8位部分(使用
的人
,CL
,...)。 - 对于大多数双操作数指令,该操作数中的至少一个必须是一个寄存器。所以不要使用
M
或先按g
为;使用研究
的操作数的至少一个。 - 对于最后一个操作数,这不要紧,无论它的注册或内存中,因此使用
先按g
(普通)。
q
means onlyeax
,ecx
,edx
, orebx
could be selected. This is because theset*
instructions must write to an 8-bit-addressable register (al
,ah
, ...). The use ofb
in the%b0
means, use the lowest 8-bit portion (al
,cl
, ...).- For most two-operand instructions, at least one of the operands must be a register. So don't use
m
org
for both; user
for at least one of the operands. - For the final operand, it doesn't matter whether it's register or memory, so use
g
(general).
在上面的例子中,我选择使用先按g
(而不是研究
)的在
,因为引用通常作为内存指针来实现,所以使用研究
约束将需要先复制指涉到寄存器,然后复制背部。使用先按g
,指涉可以直接更新。
In the example above, I chose to use g
(rather than r
) for a
because references are usually implemented as memory pointers, so using an r
constraint would have required copying the referent to a register first, and then copying back. Using g
, the referent could be updated directly.
至于为什么你的原始版本改写你的 C
通过另外的价值,是因为你指定的 = M
中输出插槽,而不是(说) + M
;这意味着,编译器允许重复使用的输入和输出相同的存储器位置
As to why your original version overwrote your c
with the addition's value, that's because you specified =m
in the output slot, rather than (say) +m
; that means the compiler is allowed to reuse the same memory location for input and output.
在你的情况,这意味着两种结果(因为使用相同的内存位置 B
和 C
)
In your case, that means two outcomes (since the same memory location was used for b
and c
):
- 添加并没有溢出:那么,
C
得到了与的值覆盖b
(的结果加)。 - 加入做溢出:那么,
C
变成1(和B
有可能成为1还,这取决于如何生成的code)。
- The addition didn't overflow: then,
c
got overwritten with the value ofb
(the result of the addition). - The addition did overflow: then,
c
became 1 (andb
might become 1 also, depending on how the code was generated).
这篇关于GCC内联汇编:限制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!