Link error with newlib 4.3.0 on ARMv7

Basic Information:

Printer Model: Generic
MCU / Printerboard: All ARMv7 MCUs
klippy.log → Build outputs

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

1 Like

Fast fix to this if you’re an Arch Linux user:

pacman -U /var/cache/pacman/pkg/arm-none-eabi-newlib-4.2.0.20211231-1-any.pkg.tar.zst

(or whichever version of arm-non-eabi-newlib-4.2* that’s in your /var/cache/pacman/pkg/

2 Likes

And if the package is no longer in your pacman cache, you get it here or you can use the downgrade script.

2 Likes

Love you guys! <3<3<3<3

Hello. any update about this? downgrade is not a option for me

greetings

The official answer is to not use Arch Linux to build mainline Klipper

hi. and future update? distros move to newer toolchains more later than sooner.

greetings