Showing results for 
Search instead for 
Did you mean: 

Hardfault when accessing a global variable in a position independent program compiled with -fPIE

Associate II

Hello board,

I seek to implement a position independent firmware to achieve a dual slot fota strategy:

  • The application firmware can be saved into one among two possible memory areas, the firmware does not know at compile time where it will be stored so it must be able to run regardless of the position.
  • A small bootloader is in charge of properly launching the firmware (the bootloader knows where the application firmware is stored).

I followed the steps described by the UM2609 guide for stm32CubeIDE chapter 2.8 which covers this exact requirement .

  1. The application firmware is compiled with the -fPIE option
  2. The instruciton "bl __libc_init_array */"is eliminated from the application firmware  startup code
  3. .got is inserted into the main firmware linker inside the .text section among GOT_START and GOT_END
  4. Stack pointer is loaded at _estack in application firmware reset handler
  5. A ram section is dedicated to holding the application firmware vector table
  6. The bootloader copies the application firmware vector table to ram and applies the appropriate offset to each entry.
  7. The bootloader deinits all peripherals and HAL and jumps to the application firmware

At this point:

  1. The main firmware reset handler is reached,
  2. Startup code executes,
  3. When it reaches the function HAL_Init inside main the application firmware goes into hardfault upon accessing a global variable, whose loaded address is outside ram memory spaceinstruction that triggers hardfaultinstruction that triggers hardfault
    1. Funnily enough, this exact variable location is properly displayed by the expression monitor
    2. debugging 2.jpg

At this point I think I am maybe missing something regarding global variables relocation, or am I doing something else wrong?

I hope any of you can shed light on this mistery as online information regarding this subject is very scarce!

Regards, Matteo


I updated my previous post, variables loaded at the wrong address are local static zero-initialized (or uninitialized) variables, which are not included in the .got, all other global and global static variables are instead correctly listed in the got.

So the question on how to force .got to consider local static variables living in the .bss space remains...

Bob S

See the 2nd answer here:

Talks about adding -mpic-data-is-text-relative


It turns out the solution is to DISABLE the pic-data-is-text-relative option adding -mno-pic-data-is-text-relative, 

source gcc board

Now the local static variables are addressed (and added) to the global offset table just like global and global static variables!

I don't know why the other stack overflow answers suggested the exact opposite...either a mistake or just different use case, anyway do not use -mpic-data-is-text-relative ! Disable it with -mno-pic-data-is-text-relative.

However, the war is not over!
The next obstacles turns out to be libc ( newlib-nano) functions, such as printf, sprintf etc, which by disassembly I see that they are definitiviely not position independent..the code jumps and fetches data not relative to program counter causing again hardfault.

So I guess, is there an easy way with Stm32CubeIde to recompile newlib-nano in a position independent fashion? Or import any other libc variant suitable for this purpose?