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
rustc
include these calls in the compiled lib....a, even when I haven't used any core functions that rely on them (and am building with--profile release
)? - 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?
Thank you!