cstatic-linkingundefined-referenceavr-gccmissing-symbols

C application linking failing with "undefined reference to __mulhi3"


I designed a static library for use in my AVR projects, but I'm having trouble linking it to an application. It reports this error:

libteleobjects/libteleobjects.a(telesignals.c.obj): In function `telesignal_get_event_data':                                                               
/home/claudio/git/ucp-usc64/libteleobjects/telesignals.c:559: undefined reference to `__mulhi3'
/home/claudio/git/ucp-usc64/libteleobjects/telesignals.c:561: undefined reference to `__mulhi3'
/home/claudio/git/ucp-usc64/libteleobjects/telesignals.c:561: undefined reference to `__mulhi3'
/home/claudio/git/ucp-usc64/libteleobjects/telesignals.c:561: undefined reference to `__mulhi3'

I found an interesting investigation to the same problem here, but since his solution is all about ADA I have no idea how to fix it in my case, which is a C application. It gave me nice tips though, like using avr-nm to search for this symbol in the system libraries. Unlike in his case, here the symbol __mulhi3 displays as U (undefined) even in the avr system libs where it was supposed to be found (libgcc.a for his libs from AVR-GCC 4.7.2 - mine is 4.8.0), so I guess the __mulhi3 is not defined at all(!?). I would expect it should appear as T (defined in the text section) in the system libs (.a files in /usr/avr/lib and subdirs). Any tips? As a sidenote, I'm using CMake as the build system.

EDIT:

Like suggested here and in the answer below, adding the math library to the end of linking would supposedly solve the problem, but CMake is already doing it and it didn't work yet:

Linking C executable ucp-usc64.elf
/usr/bin/cmake -E cmake_link_script CMakeFiles/ucp-usc64.dir/link.txt --verbose=1
/usr/bin/avr-gcc  -g -Os       -mcall-prologues -ffunction-sections -fdata-sections -Os -DNDEBUG -w -mcall-prologues -ffunction-sections -fdata-sections  -Wl,--gc-sections -lm -Wl,--gc-sections -lm -mmcu=atmega644p  CMakeFiles/ucp-usc64.dir/main.c.obj CMakeFiles/ucp-usc64.dir/modutr_callbacks.c.obj  -o ucp-usc64.elf  -lc -lm avr-drivers/libavr_drivers.a modutr-slave/lib/libmodutr_slave.a libteleobjects/libteleobjects.a -lc -lm 
libteleobjects/libteleobjects.a(telesignals.c.obj): In function `telesignal_get_event_data':
/home/claudio/git/ucp-usc64/libteleobjects/telesignals.c:559: undefined reference to `__mulhi3'
/home/claudio/git/ucp-usc64/libteleobjects/telesignals.c:561: undefined reference to `__mulhi3'
/home/claudio/git/ucp-usc64/libteleobjects/telesignals.c:561: undefined reference to `__mulhi3'
/home/claudio/git/ucp-usc64/libteleobjects/telesignals.c:561: undefined reference to `__mulhi3'
collect2: error: ld returned 1 exit status

Solution

  • The symbol __mulhi3 is indeed defined by libgcc.a, like previously hinted by this link. The problem was that, when CMake's variable CMAKE_BUILD_TYPE was set to Release, the following flags are used (set through CMAKE_CXX_FLAGS_RELEASE):

    -Os -DNDEBUG -mcall-prologues -ffunction-sections -fdata-sections -fno-exceptions

    and it appears the use of optimization -Os causes the internal GCC function __mulhi3 to be used. In that situation, somehow CMake wasn't looking for libgcc.a in the place where it is in my system, which is /usr/lib/avr/gcc/4.8.0/libgcc.a.

    I already knew beforehand undefined reference errors always happen when a library or object file defining a symbol is not linked in, and everybody helping me here were pointing in the right direction too, but I was really misled by the fact I was looking for libgcc.a in the wrong place like this:

    cd /usr/avr/lib
    find -name "*.a" -exec avr-nm {} \; | grep "__mulhi3"
    

    That was just returning loads of __mulhi3 marked as U, which meant it should be defined somewhere else. Just after checking up my package contents for avr-gcc I found libgcc.a was placed at /usr/lib/gcc/avr/4.8.0.

    Turns out in the end the whole problem was more related to CMake not being pointed the right place to look for libgcc.a, which I got to work by adding the line:

    set(CMAKE_EXE_LINKER_FLAGS "-L /usr/lib/gcc/avr/4.8.0")

    to CMakeLists.txt, which causes the following and successful linker invocation:

    /usr/bin/avr-gcc  -Wall -Os -DNDEBUG -w -mcall-prologues -ffunction-sections -fdata-sections  -L /usr/lib/gcc/avr/4.8.0 -Wl,--gc-sections -lm -mmcu=atmega644p  CMakeFiles/ucp-usc64.dir/main.c.obj CMakeFiles/ucp-usc64.dir/modutr_callbacks.c.obj  -o ucp-usc64.elf  -lc -lm avr-drivers/libavr_drivers.a libteleobjects/libteleobjects.a modutr-slave/lib/libmodutr_slave.a -lc -lm