Linking fails on RISC-V

I am trying to play with baremetal Zig on ESP32-C3 RISC-V MCU.
I am using ESP-IDF blinky example with Zig 0.12 (1856+94c63f31f). When it was built with default GCC and cmake it will compile and link without problems.

But now I am trying to build it like Zig project it fails to link with messages like:

Even when I am using vectors.o built by GCC problem is same.
All object files and static libraries built with Zig can be linked with GCC, eg:

${TOOLCHAIN}/bin/riscv32-esp-elf-gcc \
-march=rv32imc_zicsr_zifencei \
...
-o ${FILE}.elf \
lib1_built_with_zig.a \
lib2_built_with_zig.a \
...
libN_built_with_zig.a

So, my understanding that everything is good until linking phase with LLVM’s LD.
“Zig build” uses this command for linking:

/usr/local/llvm16/bin/ld.lld \
--error-limit=0 \
-O0 \
-z stack-size=16777216 \
--gc-sections \
-znow \
-m elf32lriscv \
-static \
-L ${ESP_IDF}/zig/lib/ \
-T ${ESP_IDF}/zig/src/cpu/esp32c3/ld/esp32c3.ld \
-o ${FILE}.elf \
lib1.a \
lib2.a \
...
libN.a \
${ESP_IDF}/zig/lib/libc-imc.a \
--as-needed /home/user/.cache/zig/o/<sha>/libcompiler_rt.a \
--allow-shlib-undefined

How can I link it with zig build/lld?
Or if that is not possible, how can I specify riscv32-esp-elf-gcc as a linker for “zig build”?

2 Likes

I’m interested in this as well.

Can you link to the source repo you’re trying to compile?

Have you seen MicroZig?

Disclosure: I haven’t tested these myself because I don’t understand how to run the examples, but I thought I’d share in case they make more sense to you.

1 Like

Finally I was able to fix this!
Minimal reproducer available at github
It wasn’t as much as Zig’ s problem as it is LLVM’s.
Fix was to include ‘“ax”, %progbits’ in asm file (otherwise whole “.ram.vector_table” section would be discarded):

diff --git a/src/vectors.S b/src/vectors.S
index 642a887..1b3d41e 100644
--- a/src/vectors.S
+++ b/src/vectors.S
@@ -1,4 +1,4 @@
- .section .ram.vector_table
+ .section .ram.vector_table, "ax", %progbits

I saw MicroZig but I was unable to compile even simpliest example. At least that is what I thought.

build output
rm -rf zig-cache zig-out
unset ZIG_LOCAL_CACHE_DIR
zig build
run regz (chip.zig): error: warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended
warning(svd): failed to load register: error.TodoDimElementsExtended

It “fails” but .bin and .elf files are available in zig-out/firmware folder.
To flash it, I use Rust tool (which is much quicker than ESP IDF’s tool):

espflash flash --format direct-boot --monitor zig-out/firmware/blinky-esp32-c3.elf

Tested on FreeBSD and Linux.
You’ll need to unset shell env variable ZIG_LOCAL_CACHE_DIR (if it is set) for some reason.

Thorny is the way to blinky on bare, bare metal.

2 Likes

Thanks for sharing!

Can you check the Github link you shared? It 404s for me, so it looks like it’s actually set to private.

Can you try now? Now it should be public

Yes, it’s visible now. Thanks!

Hi Johnny, thanks for posting and finding a solution, I was running into similar problems with my ESP32 C3 Zig adventure (GitHub - afaber999/ZigEsp32c3BareMetal: ZIG based minimal SDK for baremetal programming of ESP32 C3), was a real struggle to setup the interrupt vector table.