ARM cross-compiler with newlib, LTO, undefined reference to libc symbols

Gabriel Marcano
Sat May 29 07:34:03 GMT 2021

 >> This is a continuation of trying to build some software for the Nintendo 3DS,
>> which is an ARM platform. After applying the patches in
>>, I no longer get an ICE,
>> but now I'm getting a lot of undefined references to libc symbols, like free
>> and snprintf and malloc. Thing is, if I build this application without LTO, it
>> builds fine, so there appears to be something strange going on in the LTO
>> process that makes it so ld can't figure out how to link libc with everything
>> else.
>> Some things I've tried and done:
>> - I've confirmed that the libc being linked has those symbols by checking the
>>   output of nm against that libc.a.
>> - I spent a few hours trying to step through ld to figure out how it
>>   determines when a symbol is undefined, but I didn't make much headway. I did
>>   find a place (_bfd_generic_link_add_one_symbol) where it appears to be
>>   setting some data structures to undefined, but I can't figure out how it's
>>   making that decision (it's some sort of table???).
>> - I replaced the libc.a (and honestly all of lib/ for the cross-compiler, I
>>   made a backup to restore it after the test) with the one from devKitARM
>>   (from the devKitPro group, they provide GCC toolchains for a bunch of
>>   Nintendo platforms), and I was still getting undefined references, so it
>>   doesn't seem to be a problem of how I'm building my own newlib library (or both
>>   of these libraries are built wrong).
>> - I tried to reproduce the problem with a simpler example, but I wasn't able
>>   to (I probably just don't know what I'm doing).
>> I'm more than willing to help collect information to track down the source of
>> the problem, but I'm going to need some pointers in the right direction. The
>> application in question has a somewhat convoluted build process (what is it
>> with embedded development communities and super fancy Makefiles?) and it also
>> requires specific patches against newlib (adds a new system library), so it's a
>> little hard for me to have someone else try to build this and reproduce it (the
>> "official" 3DS GCC toolchain suffers from the LTO ICE bug, so I can't check if
>> their libc behaves properly, and their toolchain is even more annoying to
>> build).
>> In summary, any tips on what I should be looking for to track down the cause?
>> Let me know if you need more information from me also.
>> Thanks,
>> Gabe Marcano
> I was able to reproduce the problem with a small example:
> main.c:
>   #include <string.h>
>   int f();
>   int main() {
>           return f();
>   }
>   void _exit(int v)
>   {
>           for(;;);
>   }
> t1.c:
>   #include <stdlib.h>
>   int f() { return (int)malloc(0x0);}
> With commands:
> arm-none-eabi-gcc -O -flto -g -c -o main.o main.c
> arm-none-eabi-gcc -O0 -flto -g -c -o t1.o t1.c
> arm-none-eabi-gcc -O -flto -g main.o t1.o -o main
> I was able to reproduce this with my non-3ds arm cross compiler that doesn't
> have the patch, so it seems
> unrelated to that issue. I had to pass -O0 to the t1.c compilation so it
> wouldn't just optimize the malloc out.
> Let me know if you need any more information, or if you think this is a
> binutils bug and I should go and report an issue there.
> Thanks,
> Gabe Marcano

To be clear, the error I'm seeing with the example is this:

 /usr/libexec/gcc/arm-3ds-none-eabi/ld: warning: cannot find entry symbol _start; defaulting to 0000000000008018
 /usr/libexec/gcc/arm-3ds-none-eabi/ld: /tmp/ccPp7lyA.ltrans0.ltrans.o: in function `f':
 /home/gabriel/tmp/t1.c:3: undefined reference to `malloc'
 collect2: error: ld returned 1 exit status

Without LTO, I just realized it doesn't build, but it's because I'm missing the
_sbrk newlib syscall definition, which is expected. Just adding the following
function to main.c lets the non-lto build complete:

  void *_sbrk(int incr) {
          return NULL;

Gabe Marcano

More information about the Gcc-help mailing list