Optimizing with GCC

Something related to this that I found makes a big difference for me is the compiler switches:

-ffunction-sections -fdata-sections -Wl,--gc-sections

This puts every function and every data object into its own section. The -gc-sections link option then strips out sections that are not used. This happens even if they are global and appear in the same module (source file) as items that *are* used.

You also need to modify the link control file changing

*(.data) to *(.data.*) and *(.text) to *(.text.*)

To pick up the modified section names.

Has anyone managed to make this work ?

I've tried on an FreeRTOS example where a header file [lib_AT91SAM7S256.h] with _MANY_ inline functions was included in a source file. In the MAP file I could see a reference to all of the functions from the header. That section alone took up ~3.5K.

Should'nt GCC be able to remove dead code from the executables ?

Cheers RaceMouse

Reply to
RaceMouse
Loading thread data ...

Sure. I've been using that for years and years for a couple different targets. It's always worked fine for me.

You're seeing references to inline functions? Do you have optimization enabled? Inlining used to be disabled when optimization was off.

Yes, but removing dead code and section garbage collection are two different things.

--
Grant Edwards                   grante             Yow!  YOU PICKED KARL
                                  at               MALDEN'S NOSE!!
                               visi.com
Reply to
Grant Edwards

Hi again,

I was too quick when sending the message : The thing is :

I also tried it but it didn't work. I could see in the MAP file that the startup code wasn't at address 0. Did you use some special compiler derctives when doing this or... ?

/RaceMouse

Grant Edwards wrote:

Reply to
RaceMouse

What is "it"?

The garbage collection didn't work?

What target are you using? Are you that binutils for your target architecture supports garbage collection of unused sections? [Not all of them used to -- I had to add support to the H8 binutils when I wanted to use that feature.]

Please try to be precise when describing your problem. Do you mean there was no startup code, or the startup code was located somewhere other than the desired location of 0?

Well, I used the ones mentioned above.

--
Grant Edwards                   grante             Yow!  Yow! It's a hole
                                  at               all the way to downtown
                               visi.com            Burbank!
Reply to
Grant Edwards

HI again,

I will try to be more precise :-)

** ToolChain:

I use Binutils 2.16.1, GCC 4.1.0 and Newlib 1.14. I compile for an AT91SAM7S256, where --target is arm7tdmi.

** Situation:

In lib_AT91SAM7S256.h there are a large number of inline functions defined. I have included that file in DrvLed.c because I need it for some I/O. I use 4 or 5 of theese functions and there are a total of

150-200-isch.

** Before using "-ffunction-sections -fdata-sections -Wl,--gc-sections":

Map-file showed a startup object size 0x44 @ address 0. It also showed DrvLec.o, where all the references to the inline functions defined in lib_AT91SAM7S256.h was listed below. The size of DrvLed.o was ~3.5K

** After using "-ffunction-sections -fdata-sections -Wl,--gc-sections":

The Map-file didn't show the startup-code anywhere. There were no object files listed in .text or .text.* sections. I have the Map-file @ work and can attact [a snippet] of it tomorrow i you like ?

/RaceMouse

Grant Edwards wrote:

Reply to
RaceMouse

The tool for locating pieces of code is the linker script.

You need a special script tailored to your hardware. The script is able to locate each section separately if so needed. To get the startup code in a specified location, translate it into an own section and command the linker script to loacate it to where you want it (at 0, maybe).

For details about linker scripts, get the GNU ld manual from the GNU website .

--

Tauno Voipio
tauno voipio (at) iki fi
Reply to
Tauno Voipio

Here's what's probably happening: The startup code isn't called by any other code, so it's being thrown out. Now, the "main()" function isn't being called by anything, so it's being thrown out. Now there are a bunch of other fuctions that aren't called by anybody, so they're being thrown out, and so on...

You have to add some KEEP() directives to the linker script to keep it from throwing out sections that aren't referenced by any other sections but that still need to be kept in the linked output file. Start with the startup code. There's probably a call to main() in the startup code, so that will get pulled back in, and so on...

--
Grant Edwards                   grante             Yow!  Dizzy, are we
                                  at               "REAL PEOPLE" or "AMAZING
                               visi.com            ANIMALS"?
Reply to
Grant Edwards

...

Hello RaceMouse.

I think it is working fine, but the linker has got carried away and "optimised out" the entire program!

Try adding the line

ENTRY(__start)

At the top of the linker script. This forces the linker to include the startup code, which then forces the rest to be included (if used).

--

John Devereux
Reply to
John Devereux

That was my theory too.

I must admit I was not aware of KEEP()! I achieved the same end result using the ENTRY() keyword. Should have added that to my original "instructions".

--

John Devereux
Reply to
John Devereux

Hi,

KEEP() sounds like a possible explanation. I'll give it a try tomorrow @ work and report back :-)

/RaceMouse

Grant Edwards wrote:

Reply to
RaceMouse

If there's a visible entry symbol in the startup code, then ENTRY() is probably the right way to do it.

--
Grant Edwards                   grante             Yow!  Life is a POPULARITY
                                  at               CONTEST! I'm REFRESHINGLY
                               visi.com            CANDID!!
Reply to
Grant Edwards

Hi again,

I managed to get the whole lot compiled and linked. I added the "ENTRY(start)" just above the "SECTIONS" directive in the linker script.

The Map-file shows me the following entries: .text 0x00100000 0xd0 /cygdrive/c/DOCUME~1/rfi/LOCALS~1/Temp/cciZS6WF.o 0x00100000 start 0x001000b0 endless_loop

The thing is that the software behaves very differently now (OS not running). Before this optimization process the startup section too up

0x44 bytes. Now it takes up 0xD0 bytes. Since the OS is not running i suspect it is some missing startup code that causes the trouble. My linker script contains the following :

ENTRY(start)

SECTIONS { . = 0; .startup : { *(.startup) }>flash

Any ideas ?

/RaceMouse

Grant Edwards wrote:

Reply to
RaceMouse

Hi again,

SECTIONS { . = 0; .startup : { KEEP(*(.startup)) }>flash

.text :

The KEEP() directive did the trick. The OS is now running and uses ~3.7K Flash.

Thanks for the help :-)

/RaceMouse

John Devereux wrote:

Reply to
RaceMouse

Hello again RaceMouse!

I would be grateful if you could send me your modified project - 3.7K is quite impressive I only got it down to 5K. I could update the docs and/or download to provide information on how you achieved this (you can get my email from the Contacts page of the FreeRTOS.org site).

Regards, Richard.

formatting link

*Now for ARM Cortex-M3!*
Reply to
Richard

Cool. I take it that this is "FreeRTOS"? How much flash did it take up before?

No problem. I am glad someone found the original post useful!

I wonder why the ENTRY() keyword was not sufficient - that was all I needed to "anchor" the startup section. I think perhaps you did not have a (global) symbol called "start" in that section. On my system it is "__start" and the linker **does not complain** if the ENTRY() symbol is not defined anywhere.

--

John Devereux
Reply to
John Devereux

Hi,

Initially it took up ~44K, but then I realized that "configUSE_TRACE_FACILITY" was true. After this I ended up on ~9K.

The final optimization with garbage collection made the rest.

I didn't get et either why the ENTRY() wouldn't work. After looking carefully through the Map-file I didn't see any .startup section, so I guess that particular section was collected by --gc-sections.

/RaceMouse

John Devereux wrote:

Reply to
RaceMouse

Will do...

It does, however, not contain any semaphores, queues, lists etc. Just one single task with some blinking LED's... That might explain the size...

/RaceMouse

Richard wrote:

Reply to
RaceMouse

By way of explanation, configUSE_TRACE_FACILITY uses some string handling functions to generate a table of task state information - bringing in a lot of library stuff hence the jump in size when the optimisations documented by this thread are not applied.

Regards, Richard.

formatting link

*Now for ARM Cortex-M3!*
Reply to
Richard

And of course that is the whole point of the optimisation - it strips out functionality that is unused.

--

John Devereux
Reply to
John Devereux

Your'e right,

I enabled configUSE_TRACE_FACILITY _AND_ garbage collection and code size only increased by ~90 bytes...

/RaceMouse

Richard wrote:

Reply to
RaceMouse

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.