I am building a project which has relocatable code on bare metal. It is a Cortex M3 embedded application. I do not have a dynamic linker and have implemented all the relocations in my startup code.
Mostly it is working but my local static variables appear to be incorrectly located. Their address is offset by the amount that my executable is offset in memory - ie I compile my code as if it is loaded at memory location 0 but I actually load it in memory located at 0x8000. The static local variable have their memory address offset by 0x8000 which is not good.
My global variables are located properly by the GOT but the static local variables are not in the GOT at all (at least they don't appear when I run readelf -r
). I am compiling my code with -fpic
and the linker has -fpic
and -pie
specified. I think I must be missing a compile and/or link option to either instruct gcc
to use the GOT for the static local variables or to instruct it to use absolute addressing for them.
It seems that currently the code adds the PC to the location of the static local variables.
I think I have repeated what you are seeing:
Which gives:
I also added startup code and compiled a binary and disassembled to further understand/verify what is going on.
So if you were to change where .text is loaded and were to change where both .got and .bss are loaded relative to .text and that is it then the contents of .got would be wrong and the global variable would be loaded from the wrong place.
if you were to change where .text is loaded, leave .bss where the linker put it and move .got relative to .text. then the global would be pulled from the right place and the local would not
if you were to change where .text is loaded, change where both .got and .bss are loaded relative to .text and modify .got contents to reflect where .text is loaded, then both the local and global variable would be accessed from the right place.
So the loader and gcc/ld need to all be in sync. My immediate recommendation is to not use a static local and just use a global. That or dont worry about position independent code, it is a cortex-m3 after all and somewhat resource limited, just define the memory map up front. I assume the question is how do I make gcc use the .got for the local global, and that one I dont know the answer to, but taking a simple example like the one above you can work through the many command line options until you find one that changes the output.
This problem is also discussed here: https://answers.launchpad.net/gcc-arm-embedded/+question/236744
Starting with gcc 4.8 (ARM), there's a command line switch called
-mpic-data-is-text-relative
which causes static variables being addressed through the GOT as well.