Dear nxp community,
I am having a hard time getting progress with position independent code and I hope somebody can find the time to help and explain some bits and pieces. We have a c++ project, that might complicate things even more, I wouldn't know why, really, but I see some remarks on internet here and there. Anyway, here goes... please bear with me.
Before I started, I googled, a lot. Found some useful pages:
- Position-Independent Code with GCC for ARM Cortex-M
- Lengthy q&a on stackoverflow guided by old_timer
Our goal is one that is mentioned frequently: have one binary which we can move to any place in flash and execute from that location. For the obvious purpose of having 2 fw images on flash, which can be jumped to by the bootloader.
To get started, I just created a new project for imx rt 1024, and let the user led blink once the main function starts executing. Easy visual feedback when I am successful in my position independent code (PIC) experiment.
project settings -> c++ build -> settings -> managed linker script. I changed the location of the linker scripts one folder up, so that I don't have to bother with debug folder getting nuked when I clean my project. Fixed the path of the linker script. I also copy pasted in the "referenced" linker scripts so that I end up with 1 linker script, which I can play around with.
Compiled, uploaded, blinky blinky, so of to the next step.
I moved the vector tables out of the .text section, and gave it its own section. Just to get my hands dirty in linker script. I also added the .got section so that it will be exported to my elf file once I actually have a .got section (thus, once I actually start compiling with -fpic).
Again, compiled, uploaded, blinky blinky, so of to the next step.
NOTE: again, just to be clear, the .got section contains nothing yet. I just created it up front to have as little changes as possible between "working" and "not working" situation
Now, before I can really move my code to any position, I understand, I need to do more. But "just to get started" I thought let's just compile with -fpic, and leave the code on the linker defined position in flash.
Assumption: because I am not actually moving my code in flash yet, compiling it with -fpic will generate a .got with entries populated by the compiler/linker, so I should be able to "just run" with position independent code.
Obviously, that assumption is wrong. My application crashes. I don't know why.
What I did, is described in the following steps.
- Open project properties
- C/C++ build => Settings
- MCU C++ Compiler / Miscellaneous
- Check Position Independent Code (-fPIC)
- Add `-mpic-register=r9` and `-msingle-pic-base` and `-mno-pic-data-is-text-relative` as "other flags".
Repeat steps for MCU C Compiler, so that both C and C++ will now compile with -fpic (and a bunch of other compiler settings).
When I compile my program, and disassemble the .axf file, I can see that I now indeed have a .got table with some preinitialized entries. I checked some addresses, they point to obvious places, like my stackpointer, beginning of SRAM (dtc), and a bunch of interrupt handlers.
So far so good. But when I upload my app, it crashes.
Because of unknown reasons to me, this results in having to follow some steps to mass erase the flash in serial download mode (using the dip switches on the back of my evk) power cycling the board, and retry.
When I put a breakpoint in startup code, I can see the jump to reset handler is fine. It enters the function, and I can execute code that I wrote myself (reading out variables I defined in linker script e.g.). It even jumps to the `SystemInit` function. So I guess that counts for something. The got table is doing something here, right? Otherwise the jump to `SystemInit` would fail. Or is this also a wrong assumption on my side?
In any event, the code crashes when I tries to set the very first pointer in `SystemInit`.
SCB->CPACR |= ((3UL << 10*2) | (3UL << 11*2)); /* set CP10, CP11 Full Access in Secure mode */
The exception is an Imprecise bus error. Which after 1 year of imr rt 1024 means close to nothing to me, other than "I messed up".
SCB points to 0xe000ed00 in case of compiling without PIC.
But when I try to read out the address of SCB when compiling with PIC, the cpu immediately crashes.
I can still see that the peripheral SCB points to the correct location. 0xE000ED00. But the data associated with it seems corrupt.
Any help is greatly appreciated!
For completeness I added my test project.
Solved! Go to Solution.
Hi @bp1979 ,
You add the following compiler options:
-msingle-pic-base -mpic-register=r9 -mno-pic-data-is-text-relative -fPIC
But you didn't initialize it before initialize SP pointer. So, the SP gets a wrong address. You should exchange their position
void ResetISR(void) {
// Disable interrupts
__asm volatile ("cpsid i");
// must be added here, please refer to assemle code
__asm volatile ("LDR r9, = __global_offset_table_flash_start__");
__asm volatile ("MSR MSP, %0" : : "r" (&_vStackTop) : );
Regards,
Jing
Hi @jingpan
thx for the answer. It got me one step further! When I try to compile my freertos port in the same example program, it works fine. But when I then compile with PIC again, it crashes. I'll see if I can get a handle on that. Otherwise I will reach out and make a new ticket. But with your fix the simple program (led blinking without freertos) works ! thx!!
Hi @bp1979 ,
You add the following compiler options:
-msingle-pic-base -mpic-register=r9 -mno-pic-data-is-text-relative -fPIC
But you didn't initialize it before initialize SP pointer. So, the SP gets a wrong address. You should exchange their position
void ResetISR(void) {
// Disable interrupts
__asm volatile ("cpsid i");
// must be added here, please refer to assemle code
__asm volatile ("LDR r9, = __global_offset_table_flash_start__");
__asm volatile ("MSR MSP, %0" : : "r" (&_vStackTop) : );
Regards,
Jing
Hi jingpan,
I have same problem. In your solution,
__global_offset_table_flash_start__
What does it mean?
MEMORY
{
ITCM (rwx): ORIGIN = 0x00000000, LENGTH = 512K
DTCM (rwx): ORIGIN = 0x20000000, LENGTH = 512K
RAM (rwx): ORIGIN = 0x20200000, LENGTH = 512K
FLASH (rwx): ORIGIN = 0x60030200, LENGTH = 7744K /* 7936K - 192K (Bootloader LENGTH)*/
ERAM (rwx): ORIGIN = 0x70000000, LENGTH = 16384K
}
In my case, it's 0x60030200, right?