views:

581

answers:

6

Hey!

I'm producing a hex file to run on an ARM processor which I want to keep below 32K. It's currently a lot larger than that and I wondered if someone might have some advice on what's the best approach to slim it down?

Here's what i've done so far

  1. So I've run 'size' on it to determine how big the hex file is.
  2. Then 'size' again to see how big each of the object files are that link to create the hex files. It seems the majority of the size comes from external libraries.
  3. Then I used 'readelf' to see which functions take up the most memory.
  4. I searched through the code to see if I could calls to those functions.

Here's where I get stuck, there's some functions which I don't call directly (e.g. _vfprintf) and I can't find what calls it so I can remove the call (as I think I don't need it).

So what are the next steps?

thanks for your help.

Response to answers:

  • As I can see there are functions being called which take up a lot of memory. I cannot however find what is calling it.
  • I want to omit those functions (if possible) but I can't find what's calling them!! Could be called from any number of library functions I guess.
  • The linker is working as desired, I think, it only includes the relevant library files. How do you know if only the relevant functions are being included? Can you set a flag or something for that?
  • I'm using GCC
A: 

You could look at something like executable compression.

TraumaPony
That wouldn't help if the _running_ program is not supposed to be more than 32K.
Subtwo
It would if it only decompressed 32k at a time.
TraumaPony
+1  A: 

Just to double-check and document for future reference, but do you use Thumb instructions? They're 16 bit versions of the normal instructions. Sometimes you might need 2 16 bit instructions, so it won't save 50% in code space.

A decent linker should take just the functions needed. However, you might need compiler & linke settings to package functions for individual linking.

MSalters
Thanks, hadn't thought about the Thumb stuff. To be honest I don't know if it is being used, I think so but will investigate further.Yes the linker only adds the functions used, i'm pretty sure. But I just can't work out what is calling the function? I need like a map of who calls what maybe?
Richard
A: 

Ok so in the end I just reduced the project to it's simplest form, then slowly added files one by one until the function that I wanted to remove appeared in the 'readelf' file. Then when I had the file I commented everything out and slowly add things back in until the function popped up again. So in the end I found out what called it and removed all those calls...Now it works as desired...sweet!

Must be a better way to do it though.

Richard
+5  A: 

General list:

  • Make sure that you have the compiler and linker debug options disabled
  • Compile and link with all size options turned on (-Os in gcc)
  • Run strip on the executable
  • Generate a map file and check your function sizes. You can either get your linker to generate your map file (-M when using ld), or you can use objdump on the final executable (note that this will only work on an unstripped executable!) This won't actually fix the problem, but it will let you know of the worst offenders.
  • Use nm to investigate the symbols that are called from each of your object files. This should help in finding who's calling functions that you don't want called.

In the original question was a sub-question about including only relevant functions. gcc will include all functions within every object file that is used. To put that another way, if you have an object file that contains 10 functions, all 10 functions are included in your executable even if one 1 is actually called.

The standard libraries (eg. libc) will split functions into many separate object files, which are then archived. The executable is then linked against the archive. By splitting into many object files the linker is able to include only the functions that are actually called. (this assumes that you're statically linking)

There is no reason why you can't do the same trick. Of course, you could argue that if the functions aren't called the you can probably remove them yourself.

If you're statically linking against other libraries you can run the tools listed above over them too to make sure that they're following similar rules.

Andrew Edgecombe
If you are going to investigate symbols then you DO want to be compiling with debug options ON and not stripping the exe.
Tarski
I would also suggest fiddling around with -mthumb, since thumb executables are generally smaller than arm ones.
strager
+1  A: 

Another optimization that might save you work is -ffunction-sections, -Wl,--gc-sections, assuming you're using GCC. A good toolchain will not need to be told that, though.

Explanation: GNU ld links sections, and GCC emits one section per translation unit unless you tell it otherwise. But in C++, the nodes in the dependecy graph are objects and functions.

MSalters
A: 

On deeply embedded projects I always try to avoid using any standard library functions. Even simple functions like "strtol()" blow up the binary size. If possible just simply avoid those calls.

In most deeply embedded projects you don't need a versatile "printf()" or dynamic memory allocation (many controllers have 32kb or less RAM).

Instead of just using "printf()" I use a very simple custom "printf()", this function can only print numbers in hexadecimal or decimal format not more. Most data structures are preallocated at compile time.

Seika