Undefined symbol: `stdout` with picolibc - despite the symbol being defined in my startup code (only with LTO)

127 views Asked by At

I'm trying to convert an embedded project from CMake (via a brief detour to meson) to Bazel. We are using the llvm-embedded toolchain which uses picolibc. I manually setup the toolchain more or less based on bazel-embedded (which doesn't support llvm-embedded directly).

So far, everything seems to work, except that the link fails with undefined symbol: stdout, which gets referenced from tinystdio/puts.c, part of picolibc. Indeed, "Picolibc and Operating Systems" explains that we have to provide that symbol. We do that as part of our startup C-file, basically exactly copying that documentation.

With both CMake and meson, that links perfectly, but I can't get it to link with bazel. Some of the differences I did notice are that bazel uses the C driver (clang) instead of the C++ driver (clang++), see bazel issue 11122. The assumption is that the difference is mostly unimportant, the C++ linking issues can be resolved by either linking directly to libc++ and libc++abi, or by passing --driver-mode=g++.

Also, it does link correctly without -flto=thin. While for this blinky test we don't really need LTO, we do rely on LTO in our larger builds, and we need it to get working.

Here is the full linker command line created by bazel in one of the failed attempts:

/path/to/LLVMEmbeddedToolchainForArm-17.0.1-Darwin-AArch64/bin/clang
  -o bazel-out/.../blinky
  bazel-out/.../blinky.o
  ...some-dependency-libs.a...
  bazel-out/.../libapollo4-fam-picolibc-startup.a
  -nodefaultlibs -nostdlib
  -T mcus/apollo4l/llvm-picolibc.ld
  -Wl,--start-group
    -lc -lc++ -lc++abi -lunwind -lclang_rt.builtins -lm -lcrt0
    bazel-out/.../libapollo4-fam-picolibc-startup.a
  -Wl,--end-group
  -Wl,--as-needed -Wl,--no-undefined
  -Wl,-v -v -Wl,-S -Wl,--gc-sections
  '-march=armv7em' '-mfloat-abi=hard' '-mfpu=fpv4-sp-d16' -mlittle-endian
  -Os '-flto=thin' '-fuse-ld=lld' '--driver-mode=g++'
  -fno-exceptions -fno-rtti
  '-mabi=aapcs' -mthumb '--target=armv7em-none-eabi'
  -static

The stdout symbol is provided in libapollo4-fam-picolibc-startup.a. The -nodefaultlibs -nostdlib, and then packing all stdlibs between -Wl,--start-group, -Wl,--end-group is my heaviest gun I have been able to muster, to no effect.

For comparison, here is the successful meson command line:

/path/to/LLVMEmbeddedToolchainForArm-17.0.1-Darwin-AArch64/bin/clang++
  -o blinky
  blinky.afx.p/blinky.cpp.o
  -flto=thin -Wl,--as-needed -Wl,--no-undefined
  -fuse-ld=/path/zo/LLVMEmbeddedToolchainForArm-17.0.1-Darwin-AArch64/bin/ld.lld
  -ffunction-sections
  -fdata-sections
  -fomit-frame-pointer
  --target=armv7em-none-eabi
  -mfpu=fpv4-sp-d16
  -Wl,--start-group
    libstartup.a
    ...dependency-libs.a...
    -T/path/to/llvm-picolibc.ld
    -Wl,-Map,/path/to/blinky.map
    /path/to/LLVMEmbeddedToolchainForArm-17.0.1-Darwin-AArch64//lib/clang-runtimes/arm-none-eabi/armv7m_soft_fpv4_sp_d16/lib/libcrt0.a
  -Wl,--end-group

Here, the stdout is found in libstartup.a.

I don't know what else to try.

0

There are 0 answers