GCC内联汇编:限制 [英] GCC inline assembly: constraints

查看:161
本文介绍了GCC内联汇编:限制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我难以理解的作用制约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,为什么在事业米约束B, C 来获得写入? 2)有哪些进入更详细的关于约束的任何教程或在线资源?

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 only eax, ecx, edx, or ebx could be selected. This is because the set* instructions must write to an 8-bit-addressable register (al, ah, ...). The use of b 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 or g for both; use r 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 of b (the result of the addition).
  • The addition did overflow: then, c became 1 (and b might become 1 also, depending on how the code was generated).

这篇关于GCC内联汇编:限制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆