【问题标题】:gcc inline asm bug - argument ignoredgcc 内联 asm 错误 - 参数被忽略
【发布时间】:2016-01-22 22:10:36
【问题描述】:

我试图为 BTS 指令编写一个小型包装函数。所以不是显而易见的:

bool bts( volatile uint32_t* dst, int idx ) {
  uint32_t mask = 1 << idx;
  bool ret = !!(dst & mask);
  dst |= mask;
  return ret;
}

这是我写的:

bool bts( volatile uint32_t* dst, int idx ) {
  bool ret;
  asm( "xor %1, %1\n\t"
       "bts %2, %0\n\t"
       "adc %1, %1"
       : "+m"(*dst), "=r"(ret) : "Ir"(idx) : "cc","memory" );
  return ret;
}

这在构建优化代码时表现良好,但在构建非优化代码时,它需要 idx 始终为 0。从生成的 asm 来看,它似乎没有从 rdx 注册但来自堆栈!

我做错了什么?

【问题讨论】:

  • 您也可以考虑使用setc 而不是xor + adc。而且我不相信这里需要“内存”破坏。
  • 没有理由xor,您应该使用约束,以便编译器可以处理归零。顺便说一句,这也解决了你的问题。或者,您可以使用setcsbb
  • 我试过setcsbb,它们都可以工作。我只是想了解我的adc 版本有什么问题:)
  • 另见stackoverflow.com/questions/34940356/…。如果你希望它是原子的,你需要使用lock btsvolatile 不会那样做。如果没有,您可以使用"+rm" 约束。无论如何,看看我的asm。它使用 setc 而不是 adc,这在 Broadwell 之前的 Intel CPU 上效率更高。
  • setc 的好处是您不必先将寄存器归零。而且,如果您不先将寄存器归零,则不会在需要“&”的寄存器之间发生冲突。这意味着您不仅可以使用更少的语句,还可以使用更少的寄存器(好的,少 1 个)。我还注意到 dst 是不稳定的。这是多线程的事情吗?如果是这样,您是否需要使用lock 前缀?虽然您可能没有使用 gcc v6,但如果您使用了,您甚至可以省略 setc 并使用标志 directly。 FWIW。

标签: gcc assembly x86


【解决方案1】:

确实,GCC 首先将所有数据复制到堆栈中。这样做是为了获得更好的调试体验(使用 -O0 编译时,不应“优化”变量)。但看起来问题的原因是你早早地破坏了%1,即GCC假设你只会在读取输入后写入输出,并为%1%2分配共享寄存器(al和eax分别用于我试过的版本)。

您可以使用"=&amp;r" 约束而不是"=r" 来防止这种情况发生。

另见When to use earlyclobber constraint in extended GCC inline assembly?

【讨论】:

  • 谢谢米哈伊尔——这就是我要找的东西!
猜你喜欢
  • 1970-01-01
  • 2020-02-17
  • 1970-01-01
  • 1970-01-01
  • 2018-04-16
  • 2012-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多