gpt4 book ai didi

c++ - GCC 内联汇编 : constraints

转载 作者:IT老高 更新时间:2023-10-28 22:21:10 25 4
gpt4 key购买 nike

我很难理解 GCC 内联汇编 (x86) 中的角色约束。我有 read the manual ,它准确地解释了每个约束的作用。问题是,即使我了解每个约束的作用,我也很少理解为什么要使用一个约束而不是另一个约束,或者可能会产生什么影响。

我意识到这是一个非常广泛的话题,所以一个小例子应该有助于缩小焦点。下面是一个简单的 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 中。我最终读到了“matching constraints”,它允许您指定一个变量将用作输入和输出操作数。当我将 "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;
}

因此,使用的约束是:qrg

  • q 表示只有 eaxecxedxebx 可以被选中。这是因为 set* 指令必须写入 8 位可寻址寄存器(alah、...)。在 %b0 中使用 b 表示,使用最低 8 位部分(alcl、 ...)。
  • 对于大多数双操作数指令,至少有一个操作数必须是寄存器。所以不要同时使用 mg ;对至少一个操作数使用 r
  • 对于最后的操作数,不管是寄存器还是内存,所以使用g(通用)。

在上面的示例中,我选择使用 g(而不是 r)来表示 a,因为引用通常实现为内存指针,因此,使用 r 约束需要先将所指对象复制到寄存器,然后再复制回来。使用g,可以直接更新所指对象。


至于为什么您的原始版本用添加的值覆盖了您的 c,那是因为您在输出槽中指定了 =m,而不是(比如说) +m;这意味着编译器可以重复使用相同的内存位置进行输入和输出。

在您的情况下,这意味着两种结果(因为 bc 使用相同的内存位置):

  • 加法没有溢出:然后,cb 的值(加法的结果)覆盖。
  • 加法确实溢出:然后,c 变为 1(并且 b 也可能变为 1,具体取决于代码的生成方式)。

关于c++ - GCC 内联汇编 : constraints,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3898704/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com