Position Independent Code Hardfaults With Function Pointers
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:

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.
