Reputation: 3716
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
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
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
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