Electronic – arduino – Easiest way to get rid of __clz_tab in winavr compiled code

arduinoavravr-gcccompilerlinker-script

I've ported a program from the arduino environment to a makefile build using winavr, which, in turn, is based on avr-gcc (just like arduino).

However, my program started crashing, and after some investigation I found I was running out of data memory due to a 256 byte increase in the heap, even though I hadn't changed the program at all.

Looking at the map file I see a new table being included, __clz_tab, which is 256 bytes, and resides in RAM.

How do I get rid of this table and reclaim my RAM?

Best Answer

libc, included with gcc and avr-gcc, has a function that's used to count leading zeros when converting from an int or uint into a float or a double. This function uses a 256 byte table to speed up the zero counting operation, which is fine for computers with lots of memory, but not so great for microcontrollers where 256 bytes is 1/4 or 1/8 of the total ram available.

avr-gcc includes a library, libm.o which has alternate definitions for some functions, including the function that requires __clz_tab. This definition requires less memory, and so you need to instruct the linker to link against libm.

This is done by adding -lm to the linker command line.

However, the position of this command parameter matters - it will only resolve links to symbols before this parameter, so to make the most of it the -lm parameter should be as close to the end of the command line as possible.

In my Makefile it looks like this:

CXX=avr-gcc
CFLAGS=$(MCU) $(CPU_SPEED) -g  -Os -w -Wl,--gc-sections -ffunction-sections -fdata-sections
LFLAGS= -Wl,--section-start=.text=0x0000,-Map=program.map
INCLUDE=-I ../include/arduino/
LIBS=-L ../lib -larduino -lm

default: program.hex 

program.hex: program.elf
    avr-objcopy -O ihex $< $@

program.elf: bcu_usb.cpp main.cpp programmer.cpp
    $(CXX) $(CFLAGS) $(LFLAGS) $(INCLUDE) $^ -o $@ $(LIBS)

Note that the last item on the compiler command line is $(LIBS) and the last item in LIBS is the -lm which ensures that the compiler gives precedence to the definitions in libm when there are multiple definitions available.

Recent versions of avr-gcc have resolved this issue so this doesn't happen even without the -lm, however the arduino IDE is still installing and using the older versions of avr-gcc, and winavr hasn't been updated since this bug was fixed.

You can read the bug report here:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29524

Related Topic