4
\$\begingroup\$

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?

\$\endgroup\$
  • \$\begingroup\$ Which version of avr-gcc and avr-libc are you using in both cases? Arduino ships with its own copy of the tool-chain and compiles with various flags set, which you can observe by compiling with verbose output in the Arduino IDE (hold down shift while clicking compile in the < 1.0 IDE , or select it in the preferences dialogue in the >= 1.0 IDE). \$\endgroup\$ – vicatcu Jun 12 '12 at 15:20
7
\$\begingroup\$

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

\$\endgroup\$
  • \$\begingroup\$ @vicatcu I will as soon as the system permits it. There's a two day waiting period for accepting one's own answer on Stack Exchange. \$\endgroup\$ – Adam Davis Jun 12 '12 at 18:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.