带参数的内联汇编重新排序代码

时间:2016-03-12 08:50:03

标签: c assembly arm inline

我对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”);编译屏障,但它不起作用。

2 个答案:

答案 0 :(得分:1)

"r"地址上使用funcb约束,指示汇编程序使用链接"跳转#34;基于寄存器值。但是,ARM指令集中没有这样的指令。

如果您将"r"约束放宽到"g",代码可能会更接近您的期望。

答案 1 :(得分:1)

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

gcc manual points out that this usage of naked is unsupported

  

只能安全地包含基本的asm语句   __attribute__((naked))函数(参见Basic Asm)。使用时   扩展的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或访问全局变量。