我用 Clang 兼容的“GNU 扩展 asm”编写了这段代码:
namespace foreign {
extern char magic_pointer[];
}
extern "C" __attribute__((naked)) void get_address_of_x(void)
{
asm volatile("movq %[magic_pointer], %%rax\n\t"
"ret"
: : [magic_pointer] "p"(&foreign::magic_pointer));
}
我希望它编译成以下程序集:
_get_address_of_x:
## InlineAsm Start
movq $__ZN7foreign13magic_pointerE, %rax
ret
## InlineAsm End
ret /* useless but I don't think there's any way to get rid of it */
但我却得到了这个“废话”:
_get_address_of_x:
movq __ZN7foreign13magic_pointerE@GOTPCREL(%rip), %rax
movq %rax, -8(%rbp)
## InlineAsm Start
movq -8(%rbp), %rax
ret
## InlineAsm End
ret
显然,Clang 将 &foreign::magic_pointer
的值分配给 %rax
(这对于 naked
函数来说是致命的),然后进一步将其“溢出”到一个根本不存在的堆栈帧上,这样它就可以在内联 asm block 中再次将其拉下来。
那么,如何让 Clang 准确生成我想要的代码,而不需要手动进行名称修改呢?我的意思是我可以写
extern "C" __attribute__((naked)) void get_address_of_x(void)
{
asm volatile("movq __ZN7foreign13magic_pointerE@GOTPCREL(%rip), %rax\n\t"
"ret");
}
但如果有什么办法可以帮助的话,我真的不想这样做。
在点击“p”
之前,我尝试了“i”
和“n”
约束;但它们似乎不能与 64 位指针操作数正常工作。 Clang 不断向我发送有关无法将操作数分配给 %flags
寄存器的错误消息,这似乎出了一些疯狂的问题。
对于那些有兴趣解决这里的“XY问题”的人:我真的在尝试编写一个更长的程序集 stub 来调用另一个函数foo(void *p, ...)
其中参数 p
设置为此魔术指针值,其他参数根据输入此程序集 stub 时 CPU 寄存器的原始值设置。 (因此,naked
函数。)任意的公司政策一开始就阻止在 .S
文件中写入该死的东西;此外,我真的想写foreign::magic_pointer
而不是__ZN7foreign...etc...
。无论如何,这应该解释为什么在这种情况下严格禁止将临时结果溢出到堆栈或寄存器。
也许有一些写法
asm volatile(".long %[magic_pointer]" : : [magic_pointer] "???"(&foreign::magic_pointer));
让 Clang 准确插入我想要的重定位?
最佳答案
我想这就是你想要的:
namespace foreign {
extern char magic_pointer[];
}
extern "C" __attribute__((naked)) void get_address_of_x(void)
{
asm volatile ("ret" : : "a"(&foreign::magic_pointer));
}
在此上下文中,“a”是一个约束,指定必须使用 %rax
。然后,Clang 会将 magic_pointer
的地址加载到 %rax
中,为执行内联汇编做准备,这就是您所需要的。
这有点狡猾,因为它定义了 asm 文本中未引用的约束,我不确定这在技术上是否允许/定义良好 - 但它确实适用于最新的 clang。
在 clang 3.0-6ubuntu3 上(因为我很懒,使用 gcc.godbolt.org ),使用 -fPIC
,这是你得到的 asm:
get_address_of_x: # @get_address_of_x
movq foreign::magic_pointer@GOTPCREL(%rip), %rax
ret
ret
没有-fPIC
:
get_address_of_x: # @get_address_of_x
movl foreign::magic_pointer, %eax
ret
ret
关于c++ - 通过 GNU 扩展 asm 约束加载 64 位整数常量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13827337/