Not linking unused functions?

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

Hi,
We cannot find how to get the linker to ignore unused functions.

E.g., if we have two functions in a common library file foobar.c, foo() and bar(), and we only use foo(), bar() still seems to be linked when we look at the link map.

We've looked at 'man ld' but we can't see anything that looks likely.

How can we stop this, please...?

Would turning the common files into a 'library.a' file help? We want to avoid this because every project uses its own definitions, etc.

Alf

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

Try using -ffunction-sections, which should result in the unlinked functions being thrown away from the binary.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

you can use #defines to describe what your project needs, and then have #ifdef statements to pull out things from your "library" file.

that's what I use. (though more for code configuration in a single project than function removal from different projects.... in my case, I've written different handler functions for different modem/GPS/combinations, and don't want all of the code for all possible devices being compiled into my microcontroller - but it's the same basic idea for what you might want to do, I think)

ie

#define USE_FOO
#define USE_BAR

.
.
.
#ifdef USE_FOO
int foo();
#endif

#ifdef USE_BAR
int bar();
#endif

.
.
.

#ifdef USE_FOO
int foo()
{
}
#endif

#ifdef USE_BAR
int bar()
{
}
#endif

I have a header file called _setup.h that I put these defines in, and then refer to that in the relevant .h and .c files I want to control.

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

> E.g., if we have two functions in a common library file foobar.c

That's not how libraries usually work. The usual way of things is
to use a "one file, one function" approach (except for things that
inherently belong together). When using that approach, if you
afterwards create a library xxx.a (using avr-ar) out of the individual
.o files, the linker will only pick those modules that are really
needed.

Individual .o files given on the command-line will however always be
linked.

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

What a shame no one bothered to explain this in the user manual ...

... oh, wait a minute, they did:

http://www.nongnu.org/avr-libc/u...

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

abcminiuser wrote:
Try using -ffunction-sections, which should result in the unlinked functions being thrown away from the binary.

- Dean :twisted:

Dean, that's not complete.

One must use -ffunction-sections (compiler switch) AND -Wl,-gc-sections (linker switch) to have the linker "garbage collect" (or remove) unused sections. The -ffunction-sections switch places all functions within their own section. You must use both together to make this work.

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

clawson wrote:
What a shame no one bothered to explain this in the user manual ...

... oh, wait a minute, they did:

http://www.nongnu.org/avr-libc/u...

Thanks! I wrote that because I got tired of repeating myself when answering the same questions over again.

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

JulianHigginson:
The #ifdef FLAG (actually better to use #ifndef NOT_FLAG) only works for libraries which we have written: libraries from elsewhere in the company or the Net don't have this, and we don't want to start peppering that code with our own #ifndef's.

EW:
Thanks for the -ffunction-sections AND -Wl,-gc-sections: one project I just tried it on went from 15508 down to 14584 bytes: about 900 bytes of saving.

Definitely a 'keeper'.

Thanks muchly,
(at about 20m elevation)
Best regards,
Alf Lacis

Last Edited: Tue. Nov 6, 2007 - 02:04 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson:

clawson wrote:
What a shame no one bothered to explain this in the user manual ...

... oh, wait a minute, they did:

http://www.nongnu.org/avr-libc/u...

Yes, I saw this page already before this post.... it did not provide the answer that EW gave of the compiler and linker options which I've added to the various makefiles:

CFLAGS += -ffunction-sections
LDFLAGS += -Wl,-gc-sections

However, thanks for your input.

Alf

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

Yeah but it's the best way to make a library (rather than later trying to remove the stuff that "accidentally" got included). Say, for example, that you later made the lib available to others, will they know (or remember) to use ffunction-section and gc-sections? If you make it a "normal" lib where each function is in a separate .o and is therefore only bound in if called then it works for everyone wiht no special stuff being required (just like libc in fact)

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

dear Alf,

I echo Cliff.

Put all your library source in one directory tree.
Include every function object in your Makefile.
Compile every function as a separate file.
Create a single header file for the library function prototypes and any typedefs. Do not have any internal stuff in this header.

Make all the objects via Make.
Use avr-ar to build the libalfred.a via Make.

If you are posh you can generate the documentation too.

Then release and libalfred.a with the source to the unsuspecting public.

The public says thankyou. The public needs no special compiler switches.

David.

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

Hi, david.prentice & clawson,

Yes, I hear you... and I've done this where it's practical and useful: at the pointy end of a new company's startup, or a new large standalone project.

The situation with the embedded targets with the company I joined 3 months ago, can be summed up with three ideas: history, money, and customer contentment.

    (1) The company has 12-year-long history of different embedded targets, with hundreds of thousands of devices shipped, across scores of product lines;

    (2) the 'libraries' are really just places in the directory tree to hold collections of code source;

    (3) the sources are full of #ifdef...#endif fences and other build switches that are different for practically every target, and therefore *must* be compiled for each target;

    (4) the targets are different CPUs: i.e., Phillips, Renesas(Hitachi), and a few different ATmegas, and even the board layout may mean that the same external device is on another port or bit; and, you probably guessed, this is catered for by build switches, not configuration code;

    (5) the compilers are varied, e.g., several versions of WIN-AVR-GCC (depending on the project!), Cygwin(for PC tools), Renesas/HEW (others?);

    (6) because of 2 thru 5, and they way the company has grown, the code is highly coupled, and detangling it now would cause problems that we don't need to generate for our historical products;

Considering all this: while I like libraries, I do not think that creating compiled libraries is the 'best' thing to do in this company. (And besides, it's not my call anyway.) Sometimes the 'best' thing to do (I know this may gall) is nothing. "If it ain't broke, don't fix it."

Best Regards, and I thank you for your inputs,
Alf Lacis

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

dear Alf,

I take your point about conditional code. It is not worth the aggravation for complex code. I would leave as a source library that hangs off your project rather than a system library directory.

With simple 64 bit operations this will only be conditional on the AVR model.

So a compiled library IS possible. It just gets a separate incarnation in each "model" tree e.g. avr5 ...

As a source library, the library would be compiled in the project directory. Your project Makefile includes two new dependencies:

MY_LIB     = alf
MY_LIBOBJS = lib_obj1.o lib_obj2.o ...
lib$(MY_LIB).a: $(MY_LIBS)
           avr-ar rv $@ $?
# or let ar handle the update.
#          avr-ar ruv $@ $(MY_LIBS)

project.elf: lib$(MY_LIB).a $(OBJS)

Just written this off the top of my head, rather than looking at one of my own project Makefiles.

David.

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

Thanks, David,

That's not a bad way of doing it, tho I haven't tried it yet.

Thanks, & Regards,
Alf Lacis
http://au.geocities.com/lacis_alfredo

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

Quote:
/main.c:1: warning: -ffunction-sections may affect debugging on some targets

Quote:
avr-objcopy -O ihex -R .eeprom -j .text -j .data main.elf main.hex
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 -O ihex main.elf main.eep
avr-objdump -h -S main.elf > main.lss
avr-nm -n main.elf > main.sym
avr-objcopy --debugging --change-section-address .data-0x800000 --change-section-address .bss-0x800000 --change-section-address .noinit-0x800000 --change-section-address .eeprom-0x810000 -O coff-ext-avr main.elf ./main.cof
avr-objcopy: main.elf: no recognized debugging information

Size after:
AVR Memory Usage
----------------
Device: atmega128

Program: 0 bytes (0.0% Full)
(.text + .data + .bootloader)

Data: 0 bytes (0.0% Full)
(.data + .bss + .noinit)


Is this correct behavior?

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

I used to get that warning on an old version of AVR-GCC - it seems to be gone with the newer releases. IIRC, it was actually there in error, and was put in as a safety by the mainline GCC code for some targets, to remind the developers to test out the switch.

It all boiled down to the -ffunction-sections putting each function into its own section, which confused some debuggers (which expected all the data to be in the one section) I think.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Not linking unused functions? Nine Months Later: GCC ARM Toolkit
(Yes, I know this is not strictly AVR, but we're all software engineers. This Forum will be crawled by Google, etc, so they will find the reference to the ARM processor, and may help some of us later: it's all karma, right?)

I'm now doing some code for an Atmel ARM AT91SAM7X256, using a GCC toolkit.

I'm pleased to say that the optimization works the same for the ARM as it did for the ATmega... lots of unused functions have been optimized out of the link map.

You may recall the Makefile flags were:

CFLAGS += -ffunction-sections
LDFLAGS += -Wl,-gc-sections

With the build tool I'm using, the -f option is passed to the compiler:

-ffunction-sections

For the linker, the option string is (you don't need the "-Wl," if passing straight to the linker):

-gc-sections

I hope this will have been useful,
Regards,
Alf Lacis
http://alfredo4570.customer.netspace.net.au

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

Yes, since GCC is the same, whether for ARM or for AVR, those switches should work.

A small word of caution: It is up to the target back-end, whether or not garbage collection on unused sections is done. So it happens to work on ARM and AVR, but I cannot guarantee that it work on other GCC targets. However, it should work on targets that are well supported, I think.

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

(Tacking onto the end of this post after several years.)

--gc-sections doesn't work with the latest gcc-avr (4.5.3).

Is it called something different? Reverting back to older version for time being.

Regards,
Alf Lacis
http://alfredo4570.net

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

Quote:

with the latest gcc-avr (4.5.3).

(a) that's not the "latest" (there are issues of 4.7 in fact)

(b) where did this 4.5.3 come from?

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

Ubuntu Linux 11.10 repository.

I'm not at my own PC right now, but looking at the repository for 11.04 in this other PC I see that it has 4.3.5 in the repository so I may have dyslexed the version numbers (but it's Ubuntu 11.04, not 11.10, so I am not entirely sure.)

Regards,
Alf Lacis
http://alfredo4570.net

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

Don't use repo versions - the archive maintainers seem to know as much about building an avr-gcc toolchain as Atmel! For a well constructed toolchain that is packaged for Ubuntu see:

www.wrightflyer.co.uk/avr-gcc/

(I just host these on my website - they are actually built by Bingo600 using the script in the sticky thread at the top of this forum).

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

Just an addition really to say ... this thread was a bit of a life saver for our/my project.

 

Kicking against the flash limit on a 168 in an existing product with no possibility of an upgrade to a 328, we've been playing all the usual games for a while now ... static functions -- which are really great and really should be the default on your code snippet/template etc, conditional compilations to play the hokey-cokey with what you need and don't need, const/pure functions and parameters where appropriate.

 

Short of throwing everything into one file and letting the static declarations and the use of __attribute__ ((unused)) take maximum effect we were getting to the bottom of the barrel.

 

-ffunction-sections to the rescue ... this effectively extends the attribute/unused across multiple modules and gives us a more sane and flexible approach to our coding standards and structures ... end result a smaller footprint and the maintainability that we needed in the project code.

 

Small foot note ... if you're going down the --function-sections road ... don't forget the ... -Wl,-gc-sections for the linker to take advantage of the separate sections.

 

Thanks for a great resource of accumulated knowledge and wisdom!

 

Mike

 

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

If you use AS6.2 both -ffunction-sections and -gc-sections are on by default when you create new projects. (also -fdata-sections too).