gcc optimizer question - uncalled function

Go To Last Post
21 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Greetings,
I was under the impression that funtions that were not called would be optimized out of the code. The project that I am currently working on was at the program memory limit. On a whim I commented out an old test function and got back 8% of the program space.
So:
I have been diggging through the forum and other various online doc trying to find information about what happens to functions that are never called.
I do not understand how unused functions are handled. Is there a keyword, attribute, file location, or header construct that will help the optimizer?
What about uncalled functions in libraries?

I welcome any advice, tutorials or suggested reading material.
Thanks
Kirk

PS I'm using the winavr default -Os option

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I was under the impression that funtions that were not called would be optimized out of the code.

An individual function will not be optimized out since the compiler doesn't know that it is not being used, it is the linker that knows that. But the linker can't change the object files after the compiler has created them. What can be done by the linker is to eliminate an entire object file if none of the functions in it are used.

To get things to do what you want, you need to keep all of your test functions in a separate .c file or files. Then when they are no longer being called, those object files can be eliminated by the linker.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Using these will remove unused functions.

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

If you use a library then only the referenced functions will be added (assuming you put each function in a seperate file).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Steve,
Thanks, that makes sense to me. It seems that a consequence of this is that if I use someone's library, (say an LCD library) that there will likely be functions in the library that I do not need. These will be compiled into my code. Yuck.

Kirk

PS A bit off topic, but a related question relates to the file location of various source files. Should I put all the files of a project in the project directory? It seems (on the surface) that it would be nice to keep all the code that is used on various projects (like uart & LCD) in one place and point to that directory in the makefile. Will this cause problems?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

It seems (on the surface) that it would be nice to keep all the code that is used on various projects (like uart & LCD) in one place and point to that directory in the makefile. Will this cause problems?

Ther has been reports here about problems when such "sub-projects" are not in the directory sub-tree rooted by the project. Below the projet root you should be fine.

Still, such a reuse sounds much like building a lib would be the thing to do. In such a case, don't forget atomicdogs tip!

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> An individual function will not be optimized out since the compiler
> doesn't know that it is not being used ...

...unless it's declared "static". In that case, the compiler can already
decide it's not being used, and does not emit code for it.

"static" (i.e., only module-local visibility) not being the default is
one of the basic failures of the C language, alas too late to be corrected.
Now, we can only get around it by hard-wiring the word "static" into our
fingers when writing a declaration/definition of a function or object
located at file scope.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

use someone's library, (say an LCD library)

But those things are not "library"s. A library is a collection of individual .o files put together in a .a - the AVR-LibC runtime library is like this. Take the library containing strcpy, strcmp and strlen for example. This will have been written as separate strcpy.c, strcmp.c and strlen.c, each of these will have been compiled to strcpy.o, strcmp.o and strlen.o and these are then combined into libc.a. When your program calls strlen() and strcpy() but not strcmp() then when the linker binds your code against the library it will only extract strcpy.o and strlen.o and add those to the final binary but strcmp.o will be left behind. This is how true libraries work. Sometimes functions will be grouped. It wouldn't make a lot of sense to have malloc() without free() so the likelihood is that those two are in a single .o file

When you talk about "libraries" I suspect you are talking about code collections in .c source files such as Pete Fleury or Pascal Stang's code collections. In this case it's your job to select only the subset of files that should be built in. If you only want UART support there'd be little point adding Stang's lcd.c as well. The problem you face is that even his uart.c may contain 10 functions only 6 of which you are directly/indirectly using. That's where function-sections and gc-sections comes into play. The first builds each function into a separately named code section (a bit like the individual .o's in a .a) and then the gc-sections (gc=garbage collect) tells the linker to omit those sections which aren't referenced. So this kind of does a similar job to the original author splitting each function into a separate .c and then grouping the .o's in a .a

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

atomicdog wrote:
Using these will remove unused functions.
-ffunction-sections 
-Wl,--gc-sections 

If you use a library then only the referenced functions will be added (assuming you put each function in a seperate file).


I presume that these are to be in the CFLAGS portion of my Makefile. I have not found where these are documented.

Thanks
Kirk

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I presume that these are to be in the CFLAGS portion of my Makefile.

The -f is CFLAG and the --gc is an LDFLAG

(that is one is applied when compiling to put each function in a separate section and one is used when linking to have the linker discard the sections that have no referer)

I'd be astonished is a recursive grep of /winavr/doc did not lead to their describing manual entries?

EDIT: yup, thought so:

C:\WinAVR-20100110\doc>findstr /s /C:"function-section" *
gcc\HTML\gcc-4.3.2\gcc\HPPA-Options.html:-ffunction-section
s option, or when using the -mgas
gcc\HTML\gcc-4.3.2\gcc\Optimize-Options.html:     
-ffunction-secti ons
-fdata-sections
Place each function or d ata item into its own section in the output gcc\HTML\gcc-4.3.2\gcc\Option-Index.html:
  • ffunction-sections: Optimize Options
  • gcc\HTML\gcc-4.3.2\gcc\Option-Summary.html: -ffunction-sections -fgcse -fgcse-after-reload -fgcse-las -fgcse-lm

    and

    C:\WinAVR-20100110\doc>findstr /s /C:"gc-section" *
    binutils\bfd.html\howto-manager.html:the –gc-sections option is given, the
     linker will zero out the entries
    binutils\ld.html\Input-Section-Keep.html:

    When link-time garbage collection is in use (--gc-sections), binutils\ld.html\LD-Index.html:

  • --gc-sections: Opt ions
  • binutils\ld.html\LD-Index.html:
  • --no-gc-sections: Options
  • binutils\ld.html\LD-Index.html:
  • --no-print-gc-sections: Options
  • binutils\ld.html\LD-Index.html:
  • --print-gc-sections: Options
  • binutils\ld.html\Options.html:


    --gc-sections
    --no-gc- sections
    Enable garbage collection of unused input sections. It is ig nored on binutils\ld.html\Options.html:--no-gc-sections on the command line. binutils\ld.html\Options.html:

    --gc-sections de cides which input sections are used by binutils\ld.html\Options.html:


    --print-gc-section s
    --no-print-gc-sections
    List all sections removed by garbage collection. The listing is binutils\ld.html\Options.html:collection has been enabled via the --gc-sections) option. The binutils\ld.html\Options.html:be restored by specifying --no- print-gc-sections on the command binutils\ld.html\PowerPC64-ELF64.html:the action of --gc-sect ions or linker script /DISCARD/.

    • 1
    • 2
    • 3
    • 4
    • 5
    Total votes: 0

    To generate tight code, you should also add:

    -fno-inline-small-functions
    --combine
    -fwhole-program

    Peter

    • 1
    • 2
    • 3
    • 4
    • 5
    Total votes: 0

    I've tried all of these things in the past, and none of them work for me whatsoever. I've added them into AVRStudio verbatim, and everything compiles just fine (except for what danni suggests), but it has no effect. File size is just as big. However, if I physically remove the offending functions by precompiling them out with an #ifdef flag, then the size drops to half, showing that the functions are indeed not used.

    Specifically, I have a bootloader function that uses the same SD code as other programs. However, as it's a simplified bootloader, I don't need most of what's in the SD and SPI files.

    I've seen these same two or three comments, time after time, so they must mean something. Any ideas what I'm doing "wrong", so to speak?

    • 1
    • 2
    • 3
    • 4
    • 5
    Total votes: 0

    Show us your compiler output.
    Also the map file will tell you what functions and compilation units (*.o) were included and why.
    I believe in regards to -fwhole-program you need to have all the files compiled at the same time.

    • 1
    • 2
    • 3
    • 4
    • 5
    Total votes: 0

    Without

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

    rm -rf SDbootloader.o fat1216.o mmc.o  SDbootloader.elf dep/* SDbootloader.hex SDbootloader.eep SDbootloader.lss SDbootloader.map
    Build succeeded with 0 Warnings...
    avr-gcc -I"D:\Documents and Settings\Administrator\My Documents\STK500\bootloader_SD\..\car_logger.v8" -I"D:\Documents and Settings\Administrator\My Documents\STK500\bootloader_SD\..\car_logger.v8\includes"  -mmcu=atmega324p -Wall -gdwarf-2 -std=gnu99 -ffu
    nction-sections -Wl,--gc-sections -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums  -DBOOTLOADER1  -MD -MP -MT SDbootloader.o -MF dep/SDbootloader.o.d  -c  ../SDbootloader.c
    
    avr-gcc -I"D:\Documents and Settings\Administrator\My Documents\STK500\bootloader_SD\..\car_logger.v8" -I"D:\Documents and Settings\Administrator\My Documents\STK500\bootloader_SD\..\car_logger.v8\includes"  -mmcu=atmega324p -Wall -gdwarf-2 -std=gnu99 -ffu
    nction-sections -Wl,--gc-sections -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums  -DBOOTLOADER1  -MD -MP -MT fat1216.o -MF dep/fat1216.o.d  -c  ../fat1216.c
    
    avr-gcc -I"D:\Documents and Settings\Administrator\My Documents\STK500\bootloader_SD\..\car_logger.v8" -I"D:\Documents and Settings\Administrator\My Documents\STK500\bootloader_SD\..\car_logger.v8\includes"  -mmcu=atmega324p -Wall -gdwarf-2 -std=gnu99 -ffu
    nction-sections -Wl,--gc-sections -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums  -DBOOTLOADER1  -MD -MP -MT mmc.o -MF dep/mmc.o.d  -c -Wl,--gc-sections  -ffunction-sections ../../car_logger.v8/mmc.c
    
    avr-gcc -mmcu=atmega324p -Wl,-Map=SDbootloader.map -Wl,-section-start=.text=0x7000 SDbootloader.o fat1216.o mmc.o    -lm  -o SDbootloader.elf
    avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature  SDbootloader.elf SDbootloader.hex
    avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O ihex SDbootloader.elf SDbootloader.eep || exit 0
    avr-objdump -h -S SDbootloader.elf > SDbootloader.lss
    
    AVR Memory Usage
    ----------------
    Device: atmega324p
    
    Program:    4146 bytes (12.7% Full)
    (.text + .data + .bootloader)
    
    Data:        555 bytes (27.1% Full)
    (.data + .bss + .noinit)
    
    
    Build succeeded with 0 Warnings...

    With

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

    Build started 30.3.2010 at 23:47:33
    avr-gcc -I"D:\Documents and Settings\Administrator\My Documents\STK500\bootloader_SD\..\car_logger.v8" -I"D:\Documents and Settings\Administrator\My Documents\STK500\bootloader_SD\..\car_logger.v8\includes"  -mmcu=atmega324p -Wall -gdwarf-2 -std=gnu99 -ffu
    nction-sections -Wl,--gc-sections   -DBOOTLOADER1   -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wl,--gc-sections  -ffunction-sections   -MD -MP -MT SDbootloader.o -MF dep/SDbootloader.o.d  -c  ../SDbootloader.c
    
    avr-gcc -I"D:\Documents and Settings\Administrator\My Documents\STK500\bootloader_SD\..\car_logger.v8" -I"D:\Documents and Settings\Administrator\My Documents\STK500\bootloader_SD\..\car_logger.v8\includes"  -mmcu=atmega324p -Wall -gdwarf-2 -std=gnu99 -ffu
    nction-sections -Wl,--gc-sections   -DBOOTLOADER1   -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wl,--gc-sections  -ffunction-sections   -MD -MP -MT fat1216.o -MF dep/fat1216.o.d  -c  ../fat1216.c
    
    avr-gcc -I"D:\Documents and Settings\Administrator\My Documents\STK500\bootloader_SD\..\car_logger.v8" -I"D:\Documents and Settings\Administrator\My Documents\STK500\bootloader_SD\..\car_logger.v8\includes"  -mmcu=atmega324p -Wall -gdwarf-2 -std=gnu99 -ffu
    nction-sections -Wl,--gc-sections   -DBOOTLOADER1   -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wl,--gc-sections  -ffunction-sections   -MD -MP -MT mmc.o -MF dep/mmc.o.d  -c -Wl,--gc-sections  -ffunction-sections
     ../../car_logger.v8/mmc.c
    
    avr-gcc -mmcu=atmega324p -Wl,-Map=SDbootloader.map -Wl,-section-start=.text=0x7000 SDbootloader.o fat1216.o mmc.o    -lm  -o SDbootloader.elf
    avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature  SDbootloader.elf SDbootloader.hex
    avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O ihex SDbootloader.elf SDbootloader.eep || exit 0
    avr-objdump -h -S SDbootloader.elf > SDbootloader.lss
    
    AVR Memory Usage
    ----------------
    Device: atmega324p
    
    Program:    4146 bytes (12.7% Full)
    (.text + .data + .bootloader)
    
    Data:        555 bytes (27.1% Full)
    (.data + .bss + .noinit)
    
    
    Build succeeded with 0 Warnings...

    As you can see, no difference in size.

    By manually cutting out unused functions (not the case in the above compiler code), I'm down to the last 122 bytes of code before my SD card bootloader goes to under 2048 bytes, a pretty important number when you realize that because of the limited choice in bootloader sizes those last 122 bytes are costing me another extra 2048 bytes of space!

    • 1
    • 2
    • 3
    • 4
    • 5
    Total votes: 0

    You need to pass in -Wl,--gc-sections during the link stage. Some how you're doing it multiple times when compiling the separate files. With the -c switch nothing is linked so I don't think it's needed at all when just compiling. But you will need it at the last stage (linking). So the invocation point that created the elf file is were you need -Wl,--gc-sections.

    • 1
    • 2
    • 3
    • 4
    • 5
    Total votes: 0

    http://www.tty1.net/blog/2008-04...

    this website explains the various makefile optimisations.

    • 1
    • 2
    • 3
    • 4
    • 5
    Total votes: 0

    Geoff wrote:
    http://www.tty1.net/blog/2008-04...

    this website explains the various makefile optimisations.

    Great! I mixed and matched and wound up with an SD bootloader that's under 2KB (real K, not Ki). The ones that made the big difference were -fno-inline-small-functions (saved 106 bytes) and -Wl,--relax (saved 76 bytes). So not only am I under the limit, but I'm well under it if I have to add a couple lines of code back in.

    Now to see if the bootloader still works...

    • 1
    • 2
    • 3
    • 4
    • 5
    Total votes: 0

    Quote:

    (real K, not Ki).

    You mean it's under 2,000 bytes? (K=1000, Ki=1024)

    (Bloody IEEE-1541, mumble, mumble: http://en.wikipedia.org/wiki/IEE... )

    • 1
    • 2
    • 3
    • 4
    • 5
    Total votes: 0

    clawson wrote:
    Quote:

    (real K, not Ki).

    You mean it's under 2,000 bytes? (K=1000, Ki=1024)

    Yes. Thus (real K, not Ki). It's at 1994. Of course, I have yet to verify that it really does work, and since the 1994 figure includes lots of gumming around in FatFS's mmc.c routine, in order to remove timers and other non-essentials, I have to check that it really does work before claiming that 1994 is a definitive number.

    • 1
    • 2
    • 3
    • 4
    • 5
    Total votes: 0

    Well, now there's something a little bit wrong with -Wl,---gc-sections. It overrides a flash memory segment setting I made in AVRStudio. Normally, for the bootloader to work I need to put a CRC at the very end of the file, right before the bootloader section. Unfortunately, --gc-sections overrides this and trims off all the empty space. Is there anyway to have my cake and eat it, too? To have -Wl,--gc-sections eliminate the unused functions, but without eliminating empty space?

    • 1
    • 2
    • 3
    • 4
    • 5
    Total votes: 0

    Quote:

    Is there anyway to have my cake and eat it, too?

    A manual linker script to place your special section at a fixed address? It looks like the 324P uses /winavr/avr/lib/ldscripts/avr5.x - take a local copy and, after editing, pass a -T to the linker.

    Cliff

    • 1
    • 2
    • 3
    • 4
    • 5
    Total votes: 0

    kubark42 wrote:
    WIs there anyway to have my cake and eat it, too?
    [TUT][GCC]Adding CRC and App Length to Hex files

    Stu

    Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

    Newbie? Be sure to read the thread Newbie? Start here!