我对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”);编译屏障,但它不起作用。
答案 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或访问全局变量。