Reputation: 13
I have a question about ARM inline assembly code. I am trying to call a function from a naked function, as shown below. It unexpectedly reorders the code.
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" );
}
I got the following assembly code:
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
My desired code should be:
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
I have tried the asm volatile ( "" ::: "memory" ); compiler barrier but it does not work.
Upvotes: 0
Views: 455
Reputation: 365312
What you're calling "re-ordering" is not actually re-ordering of the asm volatile
code. All the asm code appears in source order. What's happening is that the compiler interleaves some compiler-generated instructions between them. This is what @Notlikethat pointed out. This is expected for operand setup.
The 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 means asm
statements without operands, so asm volatile ( "bl %0" : : "r"(func_b) );
is the problem.
As @artless_noise pointed out in a deleted answer, you don't need or want a function pointer in a register. You should just use asm("bl func_b");
.
Using a "g"
constraint (as mfro's answer suggests) will let the compiler choose a memory operand, so you end up with bl func_b
. This is still technically unsupported, and pointless anyway, so don't do it.
If you want to write a naked
function that takes args, look up in the ABI what registers to find them in. Don't use inline-asm operands to get function args or access globals.
Upvotes: 1
Reputation: 3335
with the "r"
constraint on the funcb
address, you instruct the assembler to do a "jump with link" based on a register value. There is no such instruction in the ARM instruction set, however.
If you relax the "r"
constraint to "g"
, the code will probably be closer to what you desire.
Upvotes: 1