cancel
Showing results for 
Search instead for 
Did you mean: 

Position Independent Code Hardfaults With Function Pointers

geirlandunico
Associate III

Hi all,

My goal is to have position independent binaries for my application (on an STM32H7) so that I can update the device while running out of flash (swapping between two different program locations).

I followed this tutorial: https://techblog.paalijarvi.fi/2022/01/16/portable-position-independent-code-pic-bootloader-and-firmware-for-arm-cortex-m0-and-cortex-m4/ which uses the following compiler flags -fpic, -mpic-register=r9, -msingle-pic-base, and -mno-pic-data-is-text-relative

My application was working while interfacing with UART.  I could self update and run out of both program partitions without issue.  When I tried to swap the interface to ethernet, I was unable to boot up because of a hardfault.  Investigating further, the hardfault was occurring within the lan8742.c when trying to run the LAN8742_Init() function on the line calling "pObj->IO.Init();" which is calling the function "ETH_PHY_IO_INIT" which is placed in a data structure initialized like so:

 

lan8742_IOCtx_t LAN8742_IOCtx = {ETH_PHY_IO_Init,

ETH_PHY_IO_DeInit,

ETH_PHY_IO_WriteReg,

ETH_PHY_IO_ReadReg,

ETH_PHY_IO_GetTick};

 

I've seen posts online (and the comments on that tutorial/blog) mentioning issues with function pointers when compiling with position independent flags but I haven't seen any solutions.  I tried manually adding lines that add the firmware location offset before calling these functions (using the gu32FirmwareOffset variable) which solved this specific issue but further down the line, another hardfault occurred for what seemed to be the same issue (with a different function).

I could certainly continuously follow along the program fixing any hardfaults that occur but this seems very tedious and not very scalable.  Is there a compiler flag that fixes this?  Or someway of automatically, on startup, updating these function pointers?  I could certainly just cycle through all of the .data region in RAM and add the offset to anything pointing towards the beginning of FLASH but that'll cause an issue for any data that isn't a function pointer but happens to lie within that region of values.  I'm still new to linkers/map locations but by looking at where the function pointers are placed:

geirlandunico_0-1730302974524.png

The top yellow highlight is the location of the first issue and the second was the second issue.  They both seem to be stored in this ".data.rel" location within the map.  I'm assuming this .rel has something to do with relocation but I don't have much experience with this and couldn't find much information on it online.  Is there a way to dynamically reference this section of RAM so that on startup I can add the offset (to anything pointing to the wrong section of flash) within this subsection without potentially harming other data in memory.  It does seem like this section isn't contiguous (.data.tcp_port is sandwiched in there) which has me concerned that this may not be possible.

 

As a side note, my original code with UART actually does use function pointers without issue.  The difference seems to be that the function pointers I used are being passed in directly to a function while the cases mentioned above seem to be creating data structures with function pointers as the initial value (which I believe would be a compile time creation) which causes the issue.  So position independent code (at least with the flags I was using) seem to use position relative function pointers unless those function pointers are initializing variables.

4 REPLIES 4
Pavel A.
Evangelist III

>My goal is to have position independent binaries for my application (on an STM32H7) so that I can update the device while running out of flash

Welcome to the club. Ideas of PIC code are attractive and have been discussed here. But IIRC no one succeeded - maybe besides happy owners of the IAR compiler.

So IMHO a better path would be relocatable image instead of PIC. The "loader" or update routine would patch the XIP code while writing it to flash, using list or table of relocations. The data in internal RAM and registers pointers  remain absolute and won't need relocation. The final patched binary will be exactly same as the GCC produces now, without any overhead.

But I don't know if the GNU linker or binutils can do this. Since it is opensource, someone can try.

So then you'd advise leaving it as it is (fpic working for variables and most function calls) but then manually patching the bin files to update those specific .data.rel portions?

If you're follow other peoples tutorials, ask THEM about them, directly.

The processor provides a wealth of information about why it's unhappy and in the HardFault_Handler, start there, and unpack what's amiss.

Function pointers to Thumb code will be ODD addresses, check that.

Use the debugger, disassemble the code being jumpped too, step across the transition.

Most internal calls/branches will be relative. Many constants (literals) and values in tables, will not.

A dissassembly of the code in context, will tell you a lot about what the MCU is going to do when it encounters it.

Have a HardFault_Handler() that outputs actionable data, so you can go directly to the cause.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

No, I am simply out of ideas and haven't seen other solutions that work well (= developers are happy). Option fpic has runtime overhead.