11.1. On position independent firmware images
Compiling firmware images as a position independent code is hard as stated by various sources, eg. https://mcuoneclipse.com/2021/06/05/position-independent-code-with-gcc-for-arm-cortex-m/ or https://www.eevblog.com/forum/microcontrollers/bare-metal-arm-gcc-position-independent-code-possible/. Some even claim they are the only on the Earth to have solved the issue - but many things still don’t work - https://techblog.paalijarvi.fi/2022/01/16/portable-position-independent-code-pic-bootloader-and-firmware-for-arm-cortex-m0-and-cortex-m4/
As per the eevblog thread, the following flags are required:
1CFLAGS += -fPIC -mno-pic-data-is-text-relative -msingle-pic-base -mpic-register=r9
2LFLAGS += -fPIC
R9 value has to be initialised on startup:
1asm("ldr r9, =_data");
Oh but we are using FreeRTOS which trashes R9 content when a new thread is created. It needs a modification:
1diff --git a/lib/freertos/portable/GCC/ARM_CM4F/port.c b/lib/freertos/portable/GCC/ARM_CM4F/port.c
2index d5cbef4..85dec97 100644
3--- a/lib/freertos/portable/GCC/ARM_CM4F/port.c
4+++ b/lib/freertos/portable/GCC/ARM_CM4F/port.c
5@@ -208,7 +208,13 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
6 pxTopOfStack--;
7 *pxTopOfStack = portINITIAL_EXC_RETURN;
8
9- pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
10+ pxTopOfStack -= 2; /* R11, R10. */
11+
12+ extern uint32_t _data;
13+ pxTopOfStack--; /* R9 */
14+ *pxTopOfStack = (StackType_t)&_data;
15+
16+ pxTopOfStack -= 5; /* R8, R7, R6, R5 and R4. */
17
18 return pxTopOfStack;
19 }
Linker script modification (using libopencm3):
1diff --git a/lib/cortex-m-generic.ld b/lib/cortex-m-generic.ld
2index f7b1da01..819d6bd9 100644
3--- a/lib/cortex-m-generic.ld
4+++ b/lib/cortex-m-generic.ld
5@@ -100,6 +100,8 @@ SECTIONS
6 *(.data*) /* Read-write initialized data */
7 *(.ramtext*) /* "text" functions to run in ram */
8 . = ALIGN(4);
9+ _got = .;
10+ *(.got)
11 _edata = .;
12 } >ram AT >rom
13 _data_loadaddr = LOADADDR(.data);
Now it starts to behave until it goes to a Newlib function compiled without PIC support.
TODO: Newlib has to be recompiled with PIC support