Linking errors when using clang for the STM32C011

I finally got a simple Swift LED blink example running on my STM32C0116-DK. I based it on the stm32-blink example from the swift-embedded-examples repo. However, I found that when I tried to link using clang I'd get the following errors. Either I get an error about ELF number 40 not being supported when using the default linker (ld.gold):

# Link objects into executable
clang --target=armv6m-none-none-eabi -nostdlib -static -Wl,-gc-sections -Wl,-T,./STM32C011F6.ld .build/blink.o .build/Startup.o -o .build/blink.elf
/usr/bin/ld.gold: fatal error: .build/blink.o: unsupported ELF machine number 40
clang: error: ld.lld command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:47: .build/blink.elf] Error 1

Or, if I use ld.lld I get an error about __aeabi_lmul not being defined:

ld.lld: error: undefined symbol: __aeabi_lmul
>>> referenced by blink.o
>>>               .build/blink.o:($s5blink16STM23C011F6BoardO5delay11milisecondsySi_tFZ)
clang: error: ld.lld command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:51: .build/blink.elf] Error 1

When I use arm-none-eabi-gcc to link, it works fine and I have a binary that works on the target. And I'm able to get a nice and small binary as well due to the use of the nano and nosys specs.

Any ideas on why I'd be getting these erros when linking? I am building on a Ubuntu 22.04 host with the Swift 6.1 snapshot from 9/11 (main-snapshot-2024-09-11):

Swift version 6.1-dev (LLVM c0b51febacb534a, Swift 4693a4765f04f22)
Target: x86_64-unknown-linux-gnu

Here's the Makefile in the project that I uploaded to GitHub. In there you can see the clang args that aren't working with the errors they throw:

1 Like

For the next person who tries this- so far the only answer I've gotten is that clang doesn't support the nano and nosys specs that gcc for ARM does, and as such it doesn't really work.

I did experiment with clang to try to manually link the libraries from /lib/arm-none-eabi/newlib/thumb/v6-m/nofp/ while disabling the default libraries with -nostdlib or -nodefaultlibs and it always resulted in the undefined symbol of __aebi_lmul.

So, I think that to use clang to link, either a version of the standard aeabi functions will need to be built and linked separately (GitHub - bobbl/libaeabi-cortexm0: ARM Run-Time ABI for the Cortex-M0 processor), OR the full stdlib will need to be included and then the compiler_rt would need to be cross compiled for armv6m.

I did do the first option above and it works. I built the libaeabi-cortexm0 library, included it in the project, and linked it like this:

clang --target=$(TARGET) $(CPU_FLAGS) $(COMMON_FLAGS) -fuse-ld=lld \ 
	-nostdlib -laeabi-cortexm0 -L./lib/ \
	-static -Wl,-gc-sections -Wl,-T,$(SRCROOT)/STM32C011F6.ld

So there's one option. I also found that manually linking libgcc.a that is included with the arm-none-eabi works, but requires telling clang where to find it:

clang --target=$(TARGET) $(CPU_FLAGS) $(COMMON_FLAGS) -fuse-ld=lld \
	-nostdlib -lgcc -L/lib/gcc/arm-none-eabi/10.3.1/thumb/nofp/ \
	-static -Wl,-gc-sections -Wl,-T,$(SRCROOT)/STM32C011F6.ld

In the end it works, but requires some actual heavy lifting. Either way, I hope this can help someone else who is searching on how to do some linking for the STM32C011 or similar.

2 Likes