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