EmbeddedRelated.com
Forums
Memfault Beyond the Launch

Position independent code with fixed data and bss

Started by Christopher Collins July 6, 2015
On Mon, 06 Jul 2015 17:44:11 -0700, Christopher Collins wrote:

> MCU: (ARM Cortex M4) > Build environment: arm-none-eabi-gcc 4.8.4 20140725 > > My goal is to build an image that can be run from any properly-aligned > offset in internal flash (i.e., position-independent). I found the > following set of gcc flags that achieves this goal: > > # Generate position independent code. > -fPIC > > # Access bss via the GOT. > -mno-pic-data-is-text-relative > > # GOT is not PC-relative; store GOT location in a register. > -msingle-pic-base > > # Store GOT location in r9. > -mpic-register=r9 > > This works, but now I am wondering if there is a way to reduce the size > of the resulting binary. In particular, the above flags cause all > global variables to be accessed via the global offset table (GOT). > However, I don't need this extra indirection, because the data and bss > sections will always be at fixed offsets in SRAM. The only part of the > image that needs to be position independent is the code itself. > Ideally, I would like to gcc to treat all accesses to global variables > as though it weren't generating position-independent code. > > Any ideas? All input is greatly appreciated. > > Chris
As Don has mentioned, try making sure ALL your data elements are in named sections and then use a linker script to place those sections at some abs address in sram. The linker can do some amazing fixups. But maybe not this one. I dont have time to try different methods. The bigger problem is your startup code is going to have to know which flash section to jump to and set the interrupt vector table correctly. You will have to have some smarts in a "boot loader" type code that will know which section to pick. That will some how have to be written into the flash each time you upload a new version. I suspect what you want to be able to do is have multiple versions in flash and be able to revert to a old version some how. A different way to do this is have some boot loader code where you tell it the slot the code will be stored in. NO-PIC the code and link for a given slot. When you upload, your boot loader determines via carefully crafted RO variables or function addresses, that the image does indeed fit into slot X. The boot loader then modifies some flash block to say which section is active. The boot loader is actually a boot loader and a pre-loader that always runs on reset. It looks at some reserved flash block (64 bytes is your minimum), says "this slot is active" and fixes up the interrupt vector table, jumps to the slot start routine. -- Chisolm Republic of Texas
Christopher Collins wrote:
> On 2015-07-08, Les Cargill <lcargill99@comcast.com> wrote:
<snip>
> > Are you expecting the linker to change the indirect access in the second > listing to something that looks like the first one, assuming I specify > the correct sections in the linker script and other C files?
I would hope so.
> I have not > had any luck in getting this to happen. >
<rends garment>
> If the answer is that gcc just doesn't support the behavior I'm looking > for, that is OK. I am not demanding a solution from the group :). > > Thanks again, > Chris >
-- Les Cargill
On 08.7.2015 &#1075;. 09:04, Christopher Collins wrote:
> .... > If the answer is that gcc just doesn't support the behavior I'm looking > for, that is OK. I am not demanding a solution from the group :).
I don't know the answer you are after but I am sort of surprised such a widely used tool is unable to do something so simple. Makes me feel good about my choice from 20+ years ago to go my own path :-). Dimiter ------------------------------------------------------ Dimiter Popoff, TGI http://www.tgi-sci.com ------------------------------------------------------ http://www.flickr.com/photos/didi_tgi/
Christopher Collins wrote:
[PIC]
> This works, but now I am wondering if there is a way to reduce the size of > the resulting binary. In particular, the above flags cause all global > variables to be accessed via the global offset table (GOT). However, I > don't need this extra indirection, because the data and bss sections > will always be at fixed offsets in SRAM.
One step in reducing binary size would be to put variables into a big struct. This tells the compiler that you don't need a separate offset for each variable, but just one, so it reduces the number of GOT address loads. This is a general trick that applies whenever PIC is used. If you manage to pack *all* variables of your program into a struct, you can finally replace the variable name in the struct reference ("vars.x") by a fixed address using a #define ("#define vars (*(struct varstruct*) 0x12340000)"). Stefan
Les Cargill wrote:
> Christopher Collins wrote: >> The problem is that the compiler does not know that COMMONDATA is at an >> absolute address. When I compile the file which accesses my_data, gcc >> is in "PIC mode," so it generates code to look up my_data in the GOT. >> By time the linker looks at the linker script and notices that >> COMMONDATA is a separate section, it is already too late; the object >> files already contain GOT references for each global access. >> >> At least this is my interpretation of what is happening. > > COMMONMDATA should be "fixed up" by the linker, not the compiler > itself. "gcc -c ...." should generate unresolved references to > the variables in COMMONDATA ( as viewable by objdump) , and > you'll need linker-script-fu to get all that sorted out.
This will not work, because the *compiler* generates different unresolved references for PIC than for non-PIC. PIC adds another indirection. Stefan
On 2015-07-09, Stefan Reuther <stefan.news@arcor.de> wrote:
> > One step in reducing binary size would be to put variables into a big > struct. This tells the compiler that you don't need a separate offset > for each variable, but just one, so it reduces the number of GOT address > loads. This is a general trick that applies whenever PIC is used. > > If you manage to pack *all* variables of your program into a struct, you > can finally replace the variable name in the struct reference ("vars.x") > by a fixed address using a #define ("#define vars (*(struct varstruct*) > 0x12340000)"). >
The OP still needs to robustly know what address to use here in the #define so when they create an instance of the struct in their program they should place the variable into it's own unique section. That way, they can use a custom linker script which places the section at the start of SRAM. However, don't forget to use KEEP() in the linker script to stop the section from being discarded. Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world
Stefan Reuther wrote:
> Les Cargill wrote: >> Christopher Collins wrote: >>> The problem is that the compiler does not know that COMMONDATA is at an >>> absolute address. When I compile the file which accesses my_data, gcc >>> is in "PIC mode," so it generates code to look up my_data in the GOT. >>> By time the linker looks at the linker script and notices that >>> COMMONDATA is a separate section, it is already too late; the object >>> files already contain GOT references for each global access. >>> >>> At least this is my interpretation of what is happening. >> >> COMMONMDATA should be "fixed up" by the linker, not the compiler >> itself. "gcc -c ...." should generate unresolved references to >> the variables in COMMONDATA ( as viewable by objdump) , and >> you'll need linker-script-fu to get all that sorted out. > > This will not work, because the *compiler* generates different > unresolved references for PIC than for non-PIC. PIC adds another > indirection. > > > Stefan >
So it would appear. *Sigh*. -- Les Cargill
On 2015-07-09, Stefan Reuther <stefan.news@arcor.de> wrote:
> Les Cargill wrote: >> Christopher Collins wrote: >>> The problem is that the compiler does not know that COMMONDATA is at an >>> absolute address. When I compile the file which accesses my_data, gcc >>> is in "PIC mode," so it generates code to look up my_data in the GOT. >>> By time the linker looks at the linker script and notices that >>> COMMONDATA is a separate section, it is already too late; the object >>> files already contain GOT references for each global access. >>> >>> At least this is my interpretation of what is happening. >> >> COMMONMDATA should be "fixed up" by the linker, not the compiler >> itself. "gcc -c ...." should generate unresolved references to >> the variables in COMMONDATA ( as viewable by objdump) , and >> you'll need linker-script-fu to get all that sorted out. > > This will not work, because the *compiler* generates different > unresolved references for PIC than for non-PIC. PIC adds another > indirection. > > > Stefan
Thank you, Stefan. This has been my observation as well. I have surrendered to the fact that gcc does not support the specific behavior I was hoping for. Also, thank you to everyone else who offered suggestions. I didn't give all the solutions due appreciation, mostly because there are further requirements that I neglected to mention, and which render them inappropriate for my particular problem. That said, I did learn from all of them, and they may come in handy in the future. Chris
Hi Christ,

Did you find a solution for this?

Omar


Memfault Beyond the Launch