假设我有一个内联程序集,它需要ah
、bh
、ch
或dh
中的一个特定的char
值。我如何告诉GCC把它放在那里?我没有看到这样做的相关约束,但是GCC手册说“如果你必须使用特定的寄存器,但是你的机器约束没有提供足够的控制来选择你想要的特定寄存器,局部寄存器变量可能会提供一个解决方案”,所以我尝试了:
void f(char x) {
register char y __asm__("ah") = x;
__asm__ __volatile__(
"# my value ended up in %0" :: "a"(y)
);
}
字符串
但它不起作用。它把它放在al
中:
movb 4(%esp), %al
# my value ended up in %al
型
特定于x86的Q
约束看起来也很接近我想要的,所以我尝试用它来代替a
,但结果是一样的。
有趣的是,当我使用Clang而不是GCC(无论是a
,Q
还是r
)编译时,我确实得到了想要的结果:
movb 4(%esp), %ah
# my value ended up in %ah
型
我还尝试用bh
、ch
和dh
代替ah
,它们的每一种组合都导致了类似的结果。
我也试着编译成64位而不是32位。在那里,GCC仍然做了基本上相同的错误事情:
movl %edi, %eax
# my value ended up in %al
型
Clang完全无法用Cannot encode high byte register in REX-prefixed instruction
编译,除非我关闭了优化(我打开LLVM issue #45210时提到了这一点),在这种情况下,它最终在正确的位置获得了值:
movb %dil, -1(%rsp)
movb -1(%rsp), %al
movb %al, -2(%rsp)
movb -2(%rsp), %ah
# my value ended up in %ah
型
这是我应该报告的GCC中的一个bug,还是这是不应该工作的东西,只是偶然在Clang中工作?如果是后者,有没有一种方法可以做到我想要的,或者我必须在程序集内从其他地方自己解决mov
?
32-bit Godbolt link。64-bit Godbolt link。
1条答案
按热度按时间cbeh67ev1#
显然,约束不允许选择嵌套寄存器,但你可以在指令引用中添加
h
修饰符。这在输入操作数的文档中有提到。例如,字符串
产生
型
我无法摆脱清除
eax
的xor
。我猜测代码生成器将“%h1”解释为设置了8位的32位字,而不是字符寄存器引用。例如:型
.编译为相同的代码,即使它返回
\0
,不是很直观。