2

我用 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_pointerinto的值%rax(这对函数来说是致命的naked),然后进一步将其“溢出”到一个甚至不存在的堆栈帧上,这样它就可以在 inline asm 块中再次将其拉出。

那么,我怎样才能让 Clang 生成我想要的代码,而不需要手动修改名称呢?我的意思是我可以写

extern "C" __attribute__((naked)) void get_address_of_x(void)
{
    asm volatile("movq  __ZN7foreign13magic_pointerE@GOTPCREL(%rip), %rax\n\t"
                 "ret");
}

但如果有任何方法可以帮助它,我真的不想这样做。

在开始之前"p",我尝试了"i"and"n"约束;但它们似乎不适用于 64 位指针操作数。Clang 不断给我错误消息,告诉我无法将操作数分配给%flags寄存器,这似乎是一些疯狂的事情出错了。


对于那些有兴趣在这里解决“XY问题”的人:我真的在尝试编写一个更长的程序集存根,它调用另一个函数foo(void *p, ...),其中参数p设置为此魔术指针值,其他参数基于原始设置输入此程序集存根时 CPU 寄存器的值。(因此,naked功能。)任意公司政策阻止只是在.S文件中写入该死的东西; 此外,我真的很想foreign::magic_pointer而不是__ZN7foreign...etc.... 无论如何,这应该解释为什么在这种情况下将临时结果溢出到堆栈或寄存器是严格禁止的。


也许有一些方法可以写

asm volatile(".long %[magic_pointer]" : : [magic_pointer] "???"(&foreign::magic_pointer));

让 Clang 准确插入我想要的重定位?

4

2 回答 2

2

我认为这就是你想要的:

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 将加载 in 的地址magic_pointer%rax准备执行您的内联 asm,这就是您所需要的。

这有点狡猾,因为它定义了 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
于 2012-12-11T20:26:07.547 回答
1

在这里。

我最终只是编写了一个帮助extern "C"函数来返回魔法值,然后从我的汇编代码中调用该函数。我仍然认为 Clang 应该以某种方式支持我原来的方法,但在我的实际案例中,这种方法的主要问题是它不能扩展到 x86-32。在 x86-64 上,将任意地址加载到%rdx可以在带有%rip-relative的单个指令中完成mov。但是在 x86-32 上,加载任意地址-fPIC会变成大量代码、.indirect_symbol指令、两次内存访问……我只是不想尝试手动编写所有这些。所以我最终的汇编代码看起来像

asm volatile(
    "...save original register values...;"
    "call  _get_magic_pointer;"
    "movq  %rax, %rdx;"
    "...set up other parameters to foo...;"
    "call  _foo;"
    "...cleanup..."
    );

更简单更清洁。:)

于 2012-12-13T20:43:01.573 回答