I mentioned that ARM toolchains could generate different function prologs. Actually, i saw two obj files (vmlinux) with completely different function prologs:
The first case looks like:
push {some registers maybe, fp, lr} (lr ommited in leaf function)
The second case looks like:
push {some registers maybe, fp, sp, lr, pc} (i can confuse the order)
So as i see the second one pushes additionally pc and sp. Also i saw some comments in crash utility (kdump project) where was stated, that kernel stackframe should have format {..., fp, sp, lr, pc} what confuse me more, because i see that in some cases it is not true.
1.) Am i right about that some gcc extra flags are needed for pushing additionally pc and sp in function prolog? If yes what are they?.
2.) What is this used for? Basically, as i understand i can unwind stack with FP and LR only, why do i need this additional values?
3.) If this things dealth nothing with compilation flags - how can i force generation of this extended function prolog and again what is the purpose?
Thank you.
1.) Am i right about that some gcc extra flags are needed for pushing additionally pc and sp in function prolog? If yes what are they?.
There are many gcc options that will affect stack frames (-march
, -mtune
, etc may affect the instructions used for instance). In your case, it was -mapcs-frame
. Also, -fomit-frame-pointer
will remove frames from leaf functions. Several static functions maybe merged together into a single generated function further reducing the number of frames. The APCS can cause slightly slower code but is needed for stack traces.
2.) What is this used for? Basically, as i understand i can unwind stack with FP and LR only, why do i need this additional values?
All registers that are not parameters (r0-r3) need to be saved as they need to be restored when returning to the caller. The compiler will allocate additional locals on the stack so sp
will almost always change when fp
changes. For why the pc
is stored, see below.
3.) If this things dealth nothing with compilation flags - how can i force generation of this extended function prolog and again what is the purpose?
It is compiler flags as you had guessed.
; Prologue - setup
mov ip, sp ; get a copy of sp.
stm sp!, {fp, ip, lr, pc} ; Save the frame on the stack. See Addendum
sub fp, ip, #4 ; Set the new frame pointer.
...
; Epilogue - return
ldm sp, {fp, sp, lr} ; restore stack, frame pointer and old link.
... ; maybe more stuff here.
bx lr ; return.
A typical save is stm sp!, {fp, ip, lr, pc}
and a restore of ldm sp, {fp, sp, lr}
. This is correct if you examine the ABI/APCS documents. Note, there is no '!' to try and fix the stack. It is loaded explicitly from the stored ip
value.
Also, the saved pc
is not used in the epilogue. It is just discarded data on the stack. So why do this? Exception handlers (interrupts, signals or C++ exceptions) and other stack trace mechanisms want to know who saved a frame. The ARM always only have one function prologue (one point of entry). However, there are multiple exits. In some cases, a return like return function();
may actually turn into a b function
in the maybe more stuff here. This is known as a tail call. Also when a leaf function is called in the middle of a routine and an exception occurs, it will see a PC
range of leaf, but the leaf may have no call frame. By saving the pc
, the call frame can be examined when an exception occurs in leaf to know who really saved the stack. Tables of pc
versus destructor, etc. maybe stored to allow objects to be freed or to figure out how to call a signal handler. The extra pc
is just plain nice when tracing a stack and the operation is almost free due to pipe lining.
See also: ARM Link and frame register question for how the compiler uses these registers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With