gcc内联asm错误-忽略参数

gcc内联asm错误-忽略参数,gcc,assembly,x86,Gcc,Assembly,X86,我试图为BTS指令编写一个小包装函数。因此,与其说是显而易见的,不如说: bool bts( volatile uint32_t* dst, int idx ) { uint32_t mask = 1 << idx; bool ret = !!(dst & mask); dst |= mask; return ret; } 当构建优化代码时,这是正常的,但当构建非优化代码时,idx总是为0。从生成的asm来看,它似乎不是从rdx寄存器而是从堆栈中获取它 我做

我试图为BTS指令编写一个小包装函数。因此,与其说是显而易见的,不如说:

bool bts( volatile uint32_t* dst, int idx ) {
  uint32_t mask = 1 << idx;
  bool ret = !!(dst & mask);
  dst |= mask;
  return ret;
}
当构建优化代码时,这是正常的,但当构建非优化代码时,idx总是为0。从生成的asm来看,它似乎不是从rdx寄存器而是从堆栈中获取它


我做错了什么?

实际上,GCC首先将所有数据复制到堆栈中。这样做是为了获得更好的调试体验(当使用-O0编译时,不应“优化”变量)。但问题的原因似乎是您过早地删除了
%1
,也就是说,GCC假定您只会在读取输入后写入输出,并为
%1
%2
分配共享寄存器(对于我尝试过的版本,分别是al和eax)

您可以使用
“=&r”
约束而不是
“=r”
来防止这种情况发生


参见

,您也可以考虑使用<代码> SEC> <代码>代替<代码> XOR+ADC 。我认为这里不需要“内存”缓冲。没有理由
xor
,你应该使用一个约束,这样编译器就可以处理归零了。顺便说一句,这也解决了你的问题。或者,您可以使用
setc
sbb
。我已经尝试了
setc
sbb
,它们都可以工作。我只是想了解我的
adc
version:)有什么问题,请参见。如果您希望它是原子的,您需要使用
锁定bts
<代码>易失性不会这样做。如果没有,则可以使用
“+rm”
约束。不管怎样,看看我的asm。它使用
setc
而不是
adc
,这在Broadwell之前的Intel CPU上更为有效。setc的优点是不必先将寄存器归零。如果不先将寄存器归零,就不会出现需要“&”的寄存器之间的冲突。这意味着您不仅可以使用更少的语句,还可以使用更少的寄存器(好的,少1个)。我还注意到dst是不稳定的。这是一个多线程的东西吗?如果是,是否需要使用
锁定
前缀?虽然您可能没有使用GCC6,但如果您使用了,您甚至可以省略setc并使用标志。谢谢米哈伊尔-这就是我要找的!
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;
}