Jos*_*ica 11 c x86 assembly gcc inline-assembly
假设我有一些内联汇编,需要一个特定char的值ah,bh,ch,或dh。我怎么能告诉 GCC 把它放在那里?我没有看到相关的约束来做到这一点,但 GCC 手册说“如果你必须使用特定的寄存器,但你的机器约束没有提供足够的控制来选择你想要的特定寄存器,局部寄存器变量可能会提供一个解决方案",所以我试过:
void f(char x) {
register char y __asm__("ah") = x;
__asm__ __volatile__(
"# my value ended up in %0" :: "a"(y)
);
}
Run Code Online (Sandbox Code Playgroud)
但它没有用。它al改为:
movb 4(%esp), %al
# my value ended up in %al
Run Code Online (Sandbox Code Playgroud)
特定于 x86 的Q约束看起来也很接近我想要的,所以我尝试用它代替a,但结果相同。我还尝试使用更通用的r.
有趣的是,当我编译铿锵而不是GCC(是否带a,Q或r),然后我得到了想要的结果:
movb 4(%esp), %ah
# my value ended up in %ah
Run Code Online (Sandbox Code Playgroud)
我还尝试使用bh、ch和dh代替ah,它们的每种组合都会产生类似的结果。
我还尝试编译为 64 位而不是 32 位。在那里,GCC 仍然做着基本相同的错误:
movl %edi, %eax
# my value ended up in %al
Run Code Online (Sandbox Code Playgroud)
Cannot encode high byte register in REX-prefixed instruction除非我关闭优化(我打开了LLVM 错误 #45865),否则Clang 完全无法编译,在这种情况下,它最终确实在正确的位置获得了值:
movb %dil, -1(%rsp)
movb -1(%rsp), %al
movb %al, -2(%rsp)
movb -2(%rsp), %ah
# my value ended up in %ah
Run Code Online (Sandbox Code Playgroud)
这是我应该报告的 GCC 中的错误,还是这不应该起作用并且仅在 Clang 中偶然起作用?如果是后者,有没有办法做我想做的事,还是我必须mov自己从大会内部的其他地方解决它?
显然,约束不允许选择嵌套寄存器,但您可以h向指令引用添加修饰符。输入操作数的文档中提到了这一点。例如,
void f(char x) {
char a;
__asm__ __volatile__(
"mov %0, %h1" :: "X"(x), "a"(a)
);
}
Run Code Online (Sandbox Code Playgroud)
产生
f:
xorl %eax, %eax
mov 4(%esp), %ah
ret
Run Code Online (Sandbox Code Playgroud)
我一直没能摆脱那个xor清除的东西eax。我的猜测是代码生成器将“%h1”解释为具有 8 位集的 32 位字,而不是字符寄存器引用。例如,这个:
char f(char x) {
char a;
__asm__ __volatile__(
"movb %0, %h1" :: "X"(x), "a"(a)
);
return a;
}
Run Code Online (Sandbox Code Playgroud)
...编译为相同的代码,即使它返回\0,不是很直观。