How to link .o files with clang?

Hi! I’m trying to assemble a simple riscv32 assmbly code and generate an executable file. I buit llvm with the command

cmake -S llvm -B build -G Ninja -DLLVM_ENABLE_PROJECTS="clang;lld;mlir" -DCMAKE_BUILD_TYPE=Debug -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind;compiler-rt" -DLLVM_TARGETS_TO_BUILD=all -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++

and the building process finished successfully. After that, I wrote a simple riscv32 assembly code as follows:

# lld_example.s

    li a5,7
    jal x0,PASS1
    li a5,6

PASS1:
    li a5,8
    nop

I used the commad ./build/bin/clang -c -target riscv32 -march=rv32i ./example/lld_example.s -o ./example/lld_example.o to generate object file. The assembler did the work and here’s the disassembly output:

./example/lld_example.o:        file format elf32-littleriscv

Disassembly of section .text:

00000000 <.text>:
       0: 00700793      li      a5, 0x7
       4: 0000006f      j       0x4 <.text+0x4>
       8: 00600793      li      a5, 0x6

0000000c <PASS1>:
       c: 00800793      li      a5, 0x8
      10: 00000013      nop

However, the linker report some errors when I tried to link the file with the command ./build/bin/clang -target riscv32 -march=rv32i ./example/lld_example.o -o ./example/lld_example. Here’s the output.

ld.lld: error: unable to find library -lc
ld.lld: error: unable to find library -lm
ld.lld: error: cannot open llvm-project/build/lib/clang/19/lib/riscv32--/libclang_rt.builtins.a: No such file or directory
clang: error: ld.lld command failed with exit code 1 (use -v to see invocation

What did I do wrong?

You need the compiler and all the prerequisite libraries to make a full executable. The compiler builtins can be built via the compiler-rt runtime. Normally the C libraries are provided by your distribution, but the LLVM C library is currently in development. There’s some work to support RISC-V natively there, see https://www.youtube.com/watch?v=GytmaH64wFo.

Also, I’m assuming that the target you’re building on is not RISC-V and on Linux? That means you’re doing a cross-compiling build. That’d look something like this, but I’ve never done it before.

-DLLVM_RUNTIME_TARGETS='default;riscv32-unknown-linux-gnu
-DRUNTIMES_riscv32-unknown-linux-gnu_LLVM_ENABLE_RUNTIMES='compiler-rt'

That should give you the compiler-rt at least, then you can either find a C library for your platform, pass -nostdlib to ignore it, or try your hand at building the LLVM one, but I don’t think it’s fully functional yet.

The path component riscv32-- looks a bit odd. I’m wondering if parts of the target triple are not set. Is there a libclang_rt.builtins.a anywhere in the build?

Thanks for your help! I’m doing my work on a x86-64 linux pc. I have included compiler-rt in the -DLLVM_ENABLE_RUNTIMES, so it should have been built I think. Is there any documents about how to use “-DLLVM_RUNTIME_TARGETS”? I couldn’t find it in LLVM Frequently-used CMake variables.

Actually I’m not developing riscv programs. I just use llvm as a tool for learning and understanding how compiler workflow works and how elf works. And I will debug llvm to dig into its source code and add a new target later. That’s why I need a really short and simple riscv assembly program to call and debug the assembler and the linker. Is there any simple way to achieve that?

Thanks for your help! I missed a point that I’m actually using an x86-64 Linux PC, which means that I’m doing a cross-compiling build. I can find a libclang_rt.builtins.a in build/lib/clang/19/lib/x86_64-unknown-linux-gnu/libclang_rt.builtins.a.

This page Building LLVM with CMake — LLVM 20.0.0git documentation says LLVM_ENABLE_RUNTIMES would build compiler-rt using the just-built compiler. As libclang_rt.builtins.a is under x86_64-... I’m guessing it might build just one compiler-rt, using the default target, which would be the x86 host, as you used LLVM_TARGETS_TO_BUILD=all. What about trying LLVM_TARGETS_TO_BUILD=RISCV and seeing if you get a RISCV compiler-rt?

The cmake command cmake -S llvm -B build -G Ninja -DLLVM_ENABLE_PROJECTS="clang;lld;mlir" -DCMAKE_BUILD_TYPE=Debug -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind;compiler-rt" -DLLVM_TARGETS_TO_BUILD=RISCV -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ (just replaced -DLLVM_TARGETS_TO_BUILD=all with -DLLVM_TARGETS_TO_BUILD=RISCV) leads to build errors (make succeeded, but build failed):

-- LLVM_MAIN_SRC_DIR: " llvm-project-original/llvm"
CMake Error at  llvm-project-original/compiler-rt/cmake/Modules/CompilerRTUtils.cmake:399 (string):
  string sub-command REPLACE requires at least four arguments.
Call Stack (most recent call first):
  CMakeLists.txt:31 (construct_compiler_rt_default_triple)


-- Performing Test COMPILER_RT_HAS_FPIC_FLAG
-- Performing Test COMPILER_RT_HAS_FPIC_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_FPIE_FLAG
-- Performing Test COMPILER_RT_HAS_FPIE_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_FNO_BUILTIN_FLAG
-- Performing Test COMPILER_RT_HAS_FNO_BUILTIN_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_STD_C11_FLAG
-- Performing Test COMPILER_RT_HAS_STD_C11_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_VISIBILITY_HIDDEN_FLAG
-- Performing Test COMPILER_RT_HAS_VISIBILITY_HIDDEN_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_OMIT_FRAME_POINTER_FLAG
-- Performing Test COMPILER_RT_HAS_OMIT_FRAME_POINTER_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_FFREESTANDING_FLAG
-- Performing Test COMPILER_RT_HAS_FFREESTANDING_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_XRAY_COMPILER_FLAG
-- Performing Test COMPILER_RT_HAS_XRAY_COMPILER_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_FNO_LTO_FLAG
-- Performing Test COMPILER_RT_HAS_FNO_LTO_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_FNO_PROFILE_GENERATE_FLAG
-- Performing Test COMPILER_RT_HAS_FNO_PROFILE_GENERATE_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_FNO_PROFILE_INSTR_GENERATE_FLAG
-- Performing Test COMPILER_RT_HAS_FNO_PROFILE_INSTR_GENERATE_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_FNO_PROFILE_INSTR_USE_FLAG
-- Performing Test COMPILER_RT_HAS_FNO_PROFILE_INSTR_USE_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_WNO_PEDANTIC
-- Performing Test COMPILER_RT_HAS_WNO_PEDANTIC - Failed
-- Performing Test COMPILER_RT_HAS_NOGPULIB_FLAG
-- Performing Test COMPILER_RT_HAS_NOGPULIB_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_FLTO_FLAG
-- Performing Test COMPILER_RT_HAS_FLTO_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_FCONVERGENT_FUNCTIONS_FLAG
-- Performing Test COMPILER_RT_HAS_FCONVERGENT_FUNCTIONS_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_CODE_OBJECT_VERSION_FLAG
-- Performing Test COMPILER_RT_HAS_CODE_OBJECT_VERSION_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_WBUILTIN_DECLARATION_MISMATCH_FLAG
-- Performing Test COMPILER_RT_HAS_WBUILTIN_DECLARATION_MISMATCH_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_ZL_FLAG
-- Performing Test COMPILER_RT_HAS_ZL_FLAG - Failed
-- Performing Test COMPILER_RT_HAS_ATOMIC_KEYWORD
-- Performing Test COMPILER_RT_HAS_ATOMIC_KEYWORD - Failed
-- Performing Test COMPILER_RT_HAS_ASM_LSE
-- Performing Test COMPILER_RT_HAS_ASM_LSE - Failed
-- Performing Test COMPILER_RT_HAS_AARCH64_SME
-- Performing Test COMPILER_RT_HAS_AARCH64_SME - Failed
-- Looking for include file sys/auxv.h
-- Looking for include file sys/auxv.h - not found
-- Builtin supported architectures: 
CMake Error at  llvm-project-original/compiler-rt/cmake/Modules/CheckSectionExists.cmake:72 (message):
  error: unknown target triple 'unknown'

Call Stack (most recent call first):
  CMakeLists.txt:963 (check_section_exists)


-- Configuring incomplete, errors occurred!
See also " llvm-project-original/build/runtimes/builtins-bins/CMakeFiles/CMakeOutput.log".
See also " llvm-project-original/build/runtimes/builtins-bins/CMakeFiles/CMakeError.log".

Part of the CMakeError.log say that

Compiling the C compiler identification source file "CMakeCCompilerId.c" failed.
Compiler:  llvm-project-original/build/./bin/clang 
Build flags: 
Id flags:  

The output was:
1
error: unknown target triple 'unknown'


Compiling the C compiler identification source file "CMakeCCompilerId.c" failed.
Compiler:  llvm-project-original/build/./bin/clang 
Build flags: 
Id flags: -c 

The output was:
1
error: unknown target triple 'unknown'

Do you have any clues?

Sorry I forgot you need LLVM_DEFAULT_TARGET_TRIPLE=riscv32-unknown-unknown-elf or riscv32-unknown-linux or similar depending on the RISCV OS.

1 Like

Still get error messages.

LLVM_DEFAULT_TARGET_TRIPLE=riscv32-unknown-unknown-elf gets the error message:

[5853/5871] Performing build step for 'builtins'
[110/159] Building C object CMakeFiles/clang_rt.builtins-riscv32.dir/emutls.c.o
FAILED: CMakeFiles/clang_rt.builtins-riscv32.dir/emutls.c.o 
 llvm-project-original/build/./bin/clang --target=riscv32-unknown-unknown-elf -DVISIBILITY_HIDDEN  -g -fno-lto -std=c11 -fPIC -fno-builtin -fvisibility=hidden -fomit-frame-pointer -DCOMPILER_RT_HAS_FLOAT16 -fforce-enable-int128 -MD -MT CMakeFiles/clang_rt.builtins-riscv32.dir/emutls.c.o -MF CMakeFiles/clang_rt.builtins-riscv32.dir/emutls.c.o.d -o CMakeFiles/clang_rt.builtins-riscv32.dir/emutls.c.o -c  llvm-project-original/compiler-rt/lib/builtins/emutls.c
 llvm-project-original/compiler-rt/lib/builtins/emutls.c:10:10: fatal error: 'stdlib.h' file not found
   10 | #include <stdlib.h>
      |          ^~~~~~~~~~
1 error generated.
[113/159] Building C object CMakeFiles/clang_rt.builtins-riscv32.dir/enable_execute_stack.c.o
FAILED: CMakeFiles/clang_rt.builtins-riscv32.dir/enable_execute_stack.c.o 
 llvm-project-original/build/./bin/clang --target=riscv32-unknown-unknown-elf -DVISIBILITY_HIDDEN  -g -fno-lto -std=c11 -fPIC -fno-builtin -fvisibility=hidden -fomit-frame-pointer -DCOMPILER_RT_HAS_FLOAT16 -fforce-enable-int128 -MD -MT CMakeFiles/clang_rt.builtins-riscv32.dir/enable_execute_stack.c.o -MF CMakeFiles/clang_rt.builtins-riscv32.dir/enable_execute_stack.c.o.d -o CMakeFiles/clang_rt.builtins-riscv32.dir/enable_execute_stack.c.o -c  llvm-project-original/compiler-rt/lib/builtins/enable_execute_stack.c
 llvm-project-original/compiler-rt/lib/builtins/enable_execute_stack.c:12:10: fatal error: 'sys/mman.h' file not found
   12 | #include <sys/mman.h>
      |          ^~~~~~~~~~~~
1 error generated.
[115/159] Building C object CMakeFiles/clang_rt.builtins-riscv32.dir/eprintf.c.o
FAILED: CMakeFiles/clang_rt.builtins-riscv32.dir/eprintf.c.o 
 llvm-project-original/build/./bin/clang --target=riscv32-unknown-unknown-elf -DVISIBILITY_HIDDEN  -g -fno-lto -std=c11 -fPIC -fno-builtin -fvisibility=hidden -fomit-frame-pointer -DCOMPILER_RT_HAS_FLOAT16 -fforce-enable-int128 -MD -MT CMakeFiles/clang_rt.builtins-riscv32.dir/eprintf.c.o -MF CMakeFiles/clang_rt.builtins-riscv32.dir/eprintf.c.o.d -o CMakeFiles/clang_rt.builtins-riscv32.dir/eprintf.c.o -c  llvm-project-original/compiler-rt/lib/builtins/eprintf.c
 llvm-project-original/compiler-rt/lib/builtins/eprintf.c:10:10: fatal error: 'stdio.h' file not found
   10 | #include <stdio.h>
      |          ^~~~~~~~~
1 error generated.

And LLVM_DEFAULT_TARGET_TRIPLE=riscv32-unknown-linux-gnu gets the error message:

CMake Error at llvm-project-original/libunwind/src/CMakeLists.txt:102 (message):
  Compiler doesn't support generation of unwind tables if exception support
  is disabled.  Building libunwind DSO with runtime dependency on C++ ABI
  library is not supported.

I found a simple way to bypass clang. I directly call ld.lld to link the file, like build/bin/ld.lld example/lld_example.o -o example/lld_example. I don’t know if this is the right thing to do, but it works.