Re: How to generate frame pointers on Cortex-M?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 20/05/2019 18:08, Vicente Bergas wrote:
> On Monday, May 20, 2019 6:44:19 PM CEST, Richard Earnshaw (lists) wrote:
>> On 20/05/2019 15:45, Vicente Bergas wrote:
>>> Hello,
>>> i would like to have a debug build with frame pointers on an ARM
>>> Cortex-M4 MCU.
>>> These are the options passed to GCC 9.1.0:
>>>
>>> -fno-omit-frame-pointer
>>> -mthumb
>>> -march=armv7e-m
>>> -mtune=cortex-m4
>>> -mcpu=cortex-m4
>>> -mfloat-abi=hard
>>> -ffreestanding
>>> -std=c11
>>>
>>> I also tested several combinations of the following options:
>>>
>>> -mabi=aapcs
>>
>> This is the default these days.
>>
>>> -mabi=atpcs
>>> -mapcs-frame
>>> -mtpcs-frame
>>> -mtpcs-leaf-frame
>>
>> All of the above are deprecated relics of the old APCS, TPCS and ATPCS
>> ABIs.
>>
>>> -mno-sched-prolog
>>> -O1
>>> -O0
>>>
>>
>> These have no direct effect on use of the frame pointer.
>>
>>> But never got the fp register (r11) set up.
>>> This is one sample function from objdump (fp appears nowhere):
>>>
>>> 80005c0: b5b0      push  {r4, r5, r7, lr}
>>> 80005c2: af00      add   r7, sp, #0
>>> 80005c4: 4605      mov   r5, r0
>>> 80005c6: 2030      movs  r0, #48
>>> 80005c8: f7ff ffa6 bl    8000518
>>> 80005cc: 2078      movs  r0, #120
>>> 80005ce: f7ff ffa3 bl    8000518
>>> 80005d2: 241c      movs  r4, #28
>>> 80005d4: fa25 f304 lsr.w r3, r5, r4
>>> 80005d8: f003 030f and.w r3, r3, #15
>>> 80005dc: 2b09      cmp   r3, #9
>>> 80005de: bfcc      ite   gt
>>> 80005e0: 2037      movgt r0, #55
>>> 80005e2: 2030      movle r0, #48
>>> 80005e4: 4418      add   r0, r3
>>> 80005e6: f7ff ff97 bl    8000518
>>> 80005ea: 3c04      subs  r4, #4
>>> 80005ec: f114 0f04 cmn.w r4, #4
>>> 80005f0: d1f0      bne.n 80005d4
>>> 80005f2: bdb0      pop   {r4, r5, r7, pc}
>>>
>>> So, all in all, how can it be done?
>>
>> In answer to your question, it depends on why you want a frame pointer.
>>
>> If you mean to address local variables via a register other than SP,
>> then -fno-omit-frame-pointer is sufficient, but GCC will currently use
>> r7 in this case from thumb code.
>>
>> If you want to create a frame backtrace structure by which you can walk
>> the stack without dwarf based debug information being included, then GCC
>> does not currently have any means to do this from thumb2 code.
>>
>> Sorry.  We're thinking about what can be done here, but this is an ABI
>> issue and must be resolved there first.
>>
>> R.
> 
> Thanks Richard for such a quick answer.
> I wanted to print a backtrace when the HardFault interrupt is triggered.
> From what you say, that is not possible and it is not GCCs fault, is a lack
> on the ABI. That also explains why Clang neither keeps track of the frame
> pointer.
> Why is the register r11 reserved as "fp" and the ABI has no use for it?
> 
> Anyways, i'll put a stack on the application and push to it at every
> function entry point and pop from it at exit. Sigh.
> 
> Regards,
>  Vicenç.
> 

I'm not sure what you mean by 'reserved'.  The AAPCS does not reserve it.

GCC however, still occasionally needs to use a register for it's own
internal purposes of laying out a stack frame (when the value held in SP
cannot be kept invariant during a function).  In this case it creates
what it terms a frame pointer to point to the current stack frame and
uses that for addressing the local variables that reside on the stack
(normally it can eliminate this use and address such variables directly
via SP).  However, on Arm there's no mandated layout of the call saved
registers relative to where this register points and consequently it's
of no use for a forming a frame chain.

Things are further complicated due to the history of the architecture.
In the early days, when only the Arm (A32) instruction set existed, R11
was initially allocated as a traditional frame pointer and thus known as
FP.  There was a well formulized sequence for creating a stack frame
which included a frame chain.

But then the original thumb instruction set came along, which couldn't
use r11 for addressing memory (as it wasn't in the register subset
r0-r7,sp,pc which had instructions for making such accesses).  At such
point the APCS frame pointer (r11) became deprecated.  Furthermore,
compilers started using r7 for the internal uses of a frame pointer when
SP could not be used in thumb code, but continued to use r11 in Arm
code.  But it's then impossible to create a frame chain as Arm and Thumb
functions can call each other and it is far to expensive for a function
to have to work out which of r7 and r11 is a frame pointer at every call
site.  Frame pointers, however, were fortunately becoming much less
important to debugging by this point as object file formats such as ELF
could support rich debug information formats, such as Dwarf.  So the
decision was taken in the ATPCS to drop the concept of a global frame
pointer entirely, allowing compilers do generate whatever code sequences
provided the best code and to then use Dwarf to describe to debugging
tools how to reconstruct the call hierarchy when necessary.

However, there are some environments where a very simple stack-based
chain can prove very useful, because it is expensive to have to decode
the dwarf unwind data on the fly (it doesn't usually matter in debuggers
since the target program is normally stopped when unwinding is being
done).  So we are looking at what options are available to us at this
point.  In the mean time your only real option is either something you
construct yourself, or to use the information recorded in either the
dwarf data or the C++ exception unwinding tables (you can ask GCC to
include this even when compiling languages other than C).

R.



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux