j4x
j4x

Reputation: 3716

undefined reference to `__aeabi_unwind_cpp_pr1' for C-only code

I am building a bare-metal code for ARM926 and I need the generated output to be as tight as possible.

In my best effort, though, I still receive this error:

yocto/poky/build-idprint/tmp/work/idprint-poky-linux-gnueabi/idpr/1.0-r0/
recipe-sysroot/usr/lib/libc.a(raise.o):
(.ARM.exidx+0x0): undefined reference to `__aeabi_unwind_cpp_pr1'

In my Makefile I put this linker flags:

LD_OPT    = -Wl,-gc-sections -Wl,-build-id=none -flto
LD_LINK   = -static -nostartfiles -nostdlib -Wl,--start-group,-lgcc,-lc,--end-group
LDFLAGS   = -T $(BINARY).ld -Xlinker -Map=$(BINARY).map $(LD_OPT)

And the link command is

$(LINK.cc) $(OBJS) $(LD_LINK) src/lib_dummies.o -o $(BINARY).elf

Finally I have a custom linker script as simple as possible:

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(fiq_main)

SECTIONS
{
  . = 0x0;
  .text : {
    KEEP(*(.textEntry));
    *(.text*)
    *(.text .gnu.linkonce.t.*)
  }
  . = ALIGN(1024);
  _bss_start = .;
  .data : { *(.data) }
  .bss : { *(.bss) }
  _bss_end = .;
}

I added a custom dummy __aeabi_unwind_cpp_pr1 to my code (inspired from libgcc sources) but it didn't help.

I have read about quite a few pages around the web but none explained me why is libgcc trying to link a C++ function to my C-only project. Okay, $(LINK.cc) is evaluated to arm-poky-linux-gnueabi-g++ but I still se no sense trying to link a C++ function to libgcc. It would make sense if I was linking libstdc++. Moreover, $(LD) fails for othre reasons (can't find -lgcc).

No optimization flags I could find helped me with this either.

Look, it is very important that my code doesn't add any uneeded stuff. Everything started only because I need to use integer division (unresolved __aeabi_idiv...)


I omitted the optimization flags for simplicity but, if needed, please tell me and I'll add them.

Any help will be greatly appreciated. Thanks.

Upvotes: 3

Views: 1502

Answers (3)

droptop
droptop

Reputation: 1671

These issues usually arise when building for bare-metal targets (hence -nostdlib) with toolchains meant for GNU/Linux targets (e.g arm-none-linux-gnueabihf) instead of using the bare-metal toolchains (e.g arm-none-eabi). Always use the appropriate toolchain from here.

One problem you'd avoid are unresolved references to __aeabi_unwind_cpp_prX, which cannot be silenced with -fno-exceptions. The __aeabi_unwind_cpp_prX routines are defined in libgcc.a in the bare-metal toolchain whereas in the Linux toolchain, they live in libgcc_eh.a. So just linking with -nostdlib -lgcc is enough.

Another thing is the libc raise function, which the bare metal compiler would not emit references to.

Upvotes: 1

Changbin Du
Changbin Du

Reputation: 800

In my case, I found this issue only exists on arm32 but not aarch64. And it happens even when built with pure C code (so apparently no C++ exceptions). The linker complains about missing __aeabi_unwind_cpp_prX, but actually, they are never invoked by disassembling the binaries. Probably there's a bug in the linker? Anyway, the solution is to define their stub symbols and they will be orphan symbols in the final binary.

By the way, adding -fno-exceptions option to the compiler doesn't help with this problem.

Upvotes: 2

j4x
j4x

Reputation: 3716

Well,

after a very long battle, I ended with a relatively simple solution. In my Makefile, I changed the LD_LINK line to:

LD_LINK   = -static -nostartfiles -nostdlib -lgcc

(removed -Wl,--start-group,-lgcc,-lc,--end-group)

This led me to an undefined reference to raise. Then I added this few lines to an assembly source file:

    .global raise

raise:
    b raise

Note:

I tried creating a raise function in C but, due to name mangling and despite any tricks I've tried, the linker could never find it.

I'd be really happy if someone could show me how to do that in plain C.

Bonus:

My final binary is way smaller than what I was getting before, and it is just what I needed!

Upvotes: 1

Related Questions