带参数重新排序代码的内联汇编
Inline assembly with argument reorders code
我有一个关于 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" );编译器障碍,但它不起作用。
通过对 funcb
地址的 "r"
约束,您指示汇编器根据寄存器值执行 "jump with link"。但是ARM指令集中没有这样的指令。
如果将 "r"
约束放宽到 "g"
,代码可能会更接近您的期望。
您所说的 "re-ordering" 实际上并不是 asm volatile
代码的重新排序。所有汇编代码均按源代码顺序出现。发生的事情是编译器在它们之间交错了一些编译器生成的指令。这是@Notlikethat 指出的。这是操作数设置的预期。
gcc manual points out that this usage of naked
is unsupported:
Only basic asm statements can safely be included in
__attribute__((naked))
functions (see Basic Asm). While using
extended asm or a mixture of basic asm and C code may appear to work,
they cannot be depended upon to work reliably and are not supported.
Basic Asm 表示 asm
没有操作数的语句,所以 asm volatile ( "bl %0" : : "r"(func_b) );
是问题所在。
正如@artless_noise 在删除的答案中指出的那样,您不需要或不需要寄存器中的函数指针。你应该只使用 asm("bl func_b");
.
使用 "g"
约束(如 mfro 的回答所建议的那样)将使编译器选择一个内存操作数,因此您最终会得到 bl func_b
。这在技术上仍然不受支持,而且毫无意义,所以不要这样做。
如果您想编写一个 naked
函数来获取参数,请在 ABI 中查找哪些寄存器以找到它们。不要使用内联汇编操作数来获取函数参数或访问全局变量。
我有一个关于 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" );编译器障碍,但它不起作用。
通过对 funcb
地址的 "r"
约束,您指示汇编器根据寄存器值执行 "jump with link"。但是ARM指令集中没有这样的指令。
如果将 "r"
约束放宽到 "g"
,代码可能会更接近您的期望。
您所说的 "re-ordering" 实际上并不是 asm volatile
代码的重新排序。所有汇编代码均按源代码顺序出现。发生的事情是编译器在它们之间交错了一些编译器生成的指令。这是@Notlikethat 指出的。这是操作数设置的预期。
gcc manual points out that this usage of naked
is unsupported:
Only basic asm statements can safely be included in
__attribute__((naked))
functions (see Basic Asm). While using extended asm or a mixture of basic asm and C code may appear to work, they cannot be depended upon to work reliably and are not supported.
Basic Asm 表示 asm
没有操作数的语句,所以 asm volatile ( "bl %0" : : "r"(func_b) );
是问题所在。
正如@artless_noise 在删除的答案中指出的那样,您不需要或不需要寄存器中的函数指针。你应该只使用 asm("bl func_b");
.
使用 "g"
约束(如 mfro 的回答所建议的那样)将使编译器选择一个内存操作数,因此您最终会得到 bl func_b
。这在技术上仍然不受支持,而且毫无意义,所以不要这样做。
如果您想编写一个 naked
函数来获取参数,请在 ABI 中查找哪些寄存器以找到它们。不要使用内联汇编操作数来获取函数参数或访问全局变量。