I'm trying to run some rust code on qemu's RISCV virt machine. I started by creating a
#![no_std] rust library with
crate-type = ["staticlib"], and a basic assembly file that sets up a stack and jumps to an entry point in the rust lib. So far, so good. However, when I attempt to link the two I receive errors like
undefined reference to `memset'
I examined the rust artifact for occurrences of the name
memset, and sure enough:
$ nm target/riscv64gc-unknown-linux-gnu/debug/librust_obj.a | rg memset U memset <- seems like the important one 0000000000000000 T _ZN17compiler_builtins3mem40__llvm_memset_element_unordered_atomic_117h88840ce51f6dc317E 0000000000000000 T ...more 0000000000000000 T __llvm_memset_element_unordered_atomic_4 ...more
So it looks like LLVM is generating calls to an undefined symbol
memset (if I'm interpreting the U correctly). On a whim, I created stub functions with all of the names mentioned in the linker errors, and linking proceeds without a hitch! The resulting executable runs as expected in qemu as well.
This got me reading about compiler intrinsics, but I still haven't made full sense of this situation. In particular:
- Why does LLVM generate calls to these functions/symbols in the first place? Is there some advantage to leaving these up to the user/lib to define?
- Why does
rustcinclude these calls in the compiled lib....a, even when I haven't used any core functions that rely on them (and am building with
- What's the best way to proceed?
I can see that my stub functions are being called if I include certain code. For instance, if I compare two slices, then my stub
memcmp is called. Should I just write a version of
memcmp (and the others) and link it?