【问题标题】:Inline assembly with argument reorders code带参数重新排序代码的内联汇编
【发布时间】:2016-03-12 08:50:02
【问题描述】:

我有一个关于 ARM 内联汇编代码的问题。我正在尝试从裸函数调用函数,如下所示。它意外地重新排序了代码。

extern void func_b();
__attribute__((naked)) static void func_a(void)
{
    asm volatile ( "push    {r0-r7, lr}" );
    asm volatile ( "bl      %0" : : "r"(func_b) );
    asm volatile ( "pop     {r0-r7, lr}\n"
                   "subs    pc, lr, #4" );
}

我得到以下汇编代码:

305c:   f642 20c7   movw    r0, #10951  ; 0x2ac7
3060:   b5ff        push    {r0, r1, r2, r3, r4, r5, r6, r7, lr}
3062:   f2c0 0000   movt    r0, #0
3066:   4780        bl      r0
3068:   e8bd 40ff   ldmia.w sp!, {r0, r1, r2, r3, r4, r5, r6, r7, lr}
306c:   f3de 8f04   subs    pc, lr, #4

我想要的代码应该是:

305c:   b5ff        push    {r0, r1, r2, r3, r4, r5, r6, r7, lr}
305e:   f642 20c7   movw    r0, #10951  ; 0x2ac7
3062:   f2c0 0000   movt    r0, #0
3066:   4780        bl      r0
3068:   e8bd 40ff   ldmia.w sp!, {r0, r1, r2, r3, r4, r5, r6, r7, lr}
306c:   f3de 8f04   subs    pc, lr, #4

我已经尝试过 asm volatile ( "" ::: "memory" );编译器障碍,但它不起作用。

【问题讨论】:

标签: c assembly arm inline


【解决方案1】:

使用funcb 地址上的"r" 约束,您可以指示汇编器根据寄存器值执行“带链接跳转”。然而,在 ARM 指令集中没有这样的指令。

如果您将"r" 约束放松为"g",代码可能会更接近您想要的。

【讨论】:

  • 非常感谢,@mfro!它适用于“g”约束。我想我应该更多地研究它。
  • OP 的问题包括bl r0 的反汇编输出。 ARM 还会如何通过函数指针进行调用? (我大多只知道 x86,所以也许你是对的,并且有不同的指令。)无论如何,在裸函数中显然不支持使用扩展 asm。 (见我的回答)。
  • @Peter With blx r0(或者mov lr, pc; mov pc, r0,如果你觉得很傻)——bl 的唯一有效操作数是标签。
  • @Peter Cordes:没有像bl <register> 这样的指令。如果您组装上面给出的代码,您可能会收到有关未定义标签r0 的投诉。具有寄存器值的分支将是 bx <register>(并且需要更多开销)。
  • @Peter Cordes:是的,blx r0
【解决方案2】:

您所说的“重新排序”实际上并不是对 asm volatile 代码的重新排序。所有的 asm 代码都以源代码顺序出现。发生的事情是编译器在它们之间交错了一些编译器生成的指令。这就是@Notlikethat 所指出的。这是操作数设置所期望的。


gcc manual points out that this usage of naked is unsupported

只有基本的 asm 语句可以安全地包含在 __attribute__((naked)) 函数(请参阅基本汇编)。使用时 扩展 asm 或基本 asm 和 C 代码的混合可能会起作用, 不能依赖它们可靠地工作并且不受支持。

Basic Asm 表示asm 语句没有操作数,所以asm volatile ( "bl %0" : : "r"(func_b) ); 是问题所在。

正如@artless_noise 在已删除的答案中指出的那样,您不需要也不想要寄存器中的函数指针。你应该只使用asm("bl func_b");

使用"g" 约束(正如mfro 的回答所暗示的那样)将使编译器选择一个内存操作数,因此您最终得到bl func_b。这在技术上仍然不受支持,而且毫无意义,所以不要这样做。


如果您想编写一个接受 args 的 naked 函数,请在 ABI 中查找要在哪些寄存器中找到它们。不要使用 inline-asm 操作数来获取函数 args 或访问全局变量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-15
    • 2012-02-12
    • 1970-01-01
    • 2012-06-16
    相关资源
    最近更新 更多