c++ - 通过 GNU 扩展 asm 约束加载 64 位整数常量?

标签 c++ assembly clang low-level

我用 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/

相关文章:

assembly - 将非常简单的 ARM 指令转换为二进制/十六进制

r - 叮当 7 : error: linker command failed with exit code 1 for macOS Big Sur

assembly - 什么是 cfi_adjust_cfa_offset 和 cfi_rel_offset?

macos - 在 mac 上安装 GNU GCC

c++ - "error: cannot use type ' void' as a range"究竟是什么意思?

c++ - SFML2 与 mingw32 : undefined references 的静态链接错误

c++ - Visual Studio 2012 - 两个项目 -> 链接器错误 (C++)

c++ - vs2008资源编辑器更改rc文件语言

c++ - 是否可以使用 Moz2D 图形 API 在桌面应用程序中绘图?

linux - 关于在 IA32 的 NASM 程序集中逐字符解析字符串的调试代码