Basic Information:
Printer Model: Generic
MCU / Printerboard: All ARMv7 MCUs
→ Build outputsklippy.log
Describe your issue:
Arch Linux recently updated to newlib v4.3.0. Klipper firmware compilation fails when linking against this new version. (First reported by user Koz on discord)
Build output
Version: v0.11.0-164-g92655e351
Linking out/klipper.elf
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libg_nano.a(libc_a-closer.o): in function `_close_r':
/build/arm-none-eabi-newlib/src/build-nano/arm-none-eabi/thumb/v7-m/nofp/newlib/../../../../../../newlib-4.3.0.20230120/newlib/libc/reent/closer.c:47: warning: _close is not implemented and will always fail
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libg_nano.a(libc_a-signalr.o): in function `_getpid_r':
/build/arm-none-eabi-newlib/src/build-nano/arm-none-eabi/thumb/v7-m/nofp/newlib/../../../../../../newlib-4.3.0.20230120/newlib/libc/reent/signalr.c:83: warning: _getpid is not implemented and will always fail
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libg_nano.a(libc_a-signalr.o): in function `_kill_r':
/build/arm-none-eabi-newlib/src/build-nano/arm-none-eabi/thumb/v7-m/nofp/newlib/../../../../../../newlib-4.3.0.20230120/newlib/libc/reent/signalr.c:53: warning: _kill is not implemented and will always fail
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libg_nano.a(libc_a-lseekr.o): in function `_lseek_r':
/build/arm-none-eabi-newlib/src/build-nano/arm-none-eabi/thumb/v7-m/nofp/newlib/../../../../../../newlib-4.3.0.20230120/newlib/libc/reent/lseekr.c:49: warning: _lseek is not implemented and will always fail
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libg_nano.a(libc_a-readr.o): in function `_read_r':
/build/arm-none-eabi-newlib/src/build-nano/arm-none-eabi/thumb/v7-m/nofp/newlib/../../../../../../newlib-4.3.0.20230120/newlib/libc/reent/readr.c:49: warning: _read is not implemented and will always fail
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libg_nano.a(libc_a-writer.o): in function `_write_r':
/build/arm-none-eabi-newlib/src/build-nano/arm-none-eabi/thumb/v7-m/nofp/newlib/../../../../../../newlib-4.3.0.20230120/newlib/libc/reent/writer.c:49: warning: _write is not implemented and will always fail
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/12.2.0/thumb/v7-m/nofp/libgcc.a(unwind-arm.o): in function `get_eit_entry':
/build/arm-none-eabi-gcc/src/gcc-12.2.0/libgcc/unwind-arm-common.inc:366: undefined reference to `__exidx_start'
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: /build/arm-none-eabi-gcc/src/gcc-12.2.0/libgcc/unwind-arm-common.inc:366: undefined reference to `__exidx_end'
collect2: error: ld returned 1 exit status
make: *** [Makefile:72: out/klipper.elf] Error 1
I compared newlib v4.2 and v4.3 on both ARMv7 (STM32F103) and ARMv6 (rp2040) with verbose output (CFLAGS_klipper.elf += -v -Wl,--verbose
): linker_verbose_logs.zip (18.3 KB)
One notable difference is that (libgcc.a)unwind-arm.o
get slinked with newlib v4.3 (but not on ARMv6). The likely culprit is a reference to the external symbol __aeabi_unwind_cpp_pr0
from libc_a-setjmp.o
:
$ nm -a /usr/arm-none-eabi/lib/thumb/v7-m/nofp/libc_nano.a
libc_a-setjmp.o:
[...]
00000000 n .ARM.attributes
00000000 r .ARM.exidx
00000000 r .ARM.extab
[...]
00000000 t .text
U __aeabi_unwind_cpp_pr0
0000000d T longjmp
00000001 T setjmp
This reference is not present in older version nor in the ARMv6 builds.
It can be removed with this newlib patch:
diff --git a/newlib/libc/machine/arm/setjmp.S b/newlib/libc/machine/arm/setjmp.S
index 5e5952296..02cc45eca 100644
--- a/newlib/libc/machine/arm/setjmp.S
+++ b/newlib/libc/machine/arm/setjmp.S
@@ -192,6 +192,7 @@ SYM (\name):
.macro FUNC_END name
RET
.cfi_endproc
+ .cantunwind
.fnend
SIZE (\name)
.endm
This fixes the linker error, but not the warnings related to _close
/_lseek
/_read
/_write
which are a separate issue.
The .cantunwind
directive is used to exclude functions from the exception index table and unwind information. I’m not familiar with these mechanisms, but I don’t see how the stack can be unwound through setjmp/longjmp. One could reasonably argue that a C project built with --specs=nano.specs --specs=nosys.specs
, like klipper, should not require an exception index table. Thus there is a chance that this could have been an omission that should be fixed in newlib.
Newlib commits adding this directive in other assembly routines are related to “M-profile PACBTI-enablement”, a ARMv8 security feature. I must admit that I have no idea why these changes affect ARMv7 (and not ARMv6).
In any case, since Klipper users will likely encounter this newlib version, it might be worth to include a fix in Klipper itself, at the cost of few additional bytes from the exception index table. Discord user Monkeh suggested this linker script snippet:
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
__exidx_end = .;
} > rom
Laikulo implemented and improved this fix here: klipper/armcm_link.lds.S at feature/armcm_exidx · Laikulo/klipper · GitHub