Linker error 'undefined reference to memcpy' when not linking libc

I'm trying to compile this repo GitHub - MarcusGrass/nostd-alloc-repr (cargo run --profile lto) and it seems that even though I have no dependencies on libc, memcpy is emitted.

The code that causes it is this:

    let mut v: Vec<u8> = Vec::with_capacity(256);
    for i in 0..16 {
        v.push(i);
        unix_println!("{}", envp.add(i as usize).read());
        env_sz += 1;
    }

When it's changed to this, it works:

    let mut env_sz = 0;
    let mut v: Vec<u8> = Vec::with_capacity(256);
    for i in 0..8 { // <--- from 16 to 8
        v.push(i);
        unix_println!("{}", envp.add(i as usize).read());
        env_sz += 1;
    }

This is the error:

error: linking with `cc` failed: exit status: 1
  |
  = note: "cc" "-m64" "/tmp/rustcaufks9/symbols.o" "/home/gramar/code/rust/nostd-alloc-failure/target/lto/deps/no_std-0e11b6c1ff6df839.no_std.b533f128-cgu.0.rcgu.o" "-Wl,--as-needed" "-L" "/home/gramar/code/rust/nostd-alloc-failure/target/lto/deps" "-L" "/home/gramar/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "/home/gramar/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-b7c79d85cf21a511.rlib" "-Wl,-Bdynamic" "-Wl,--eh-frame-hdr" "-Wl,-znoexecstack" "-L" "/home/gramar/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/home/gramar/code/rust/nostd-alloc-failure/target/lto/deps/no_std-0e11b6c1ff6df839" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro,-znow" "-Wl,-O1" "-Wl,--strip-all" "-nodefaultlibs" "-fuse-ld=lld" "-nostartfiles"
  = note: ld.lld: error: undefined symbol: memcpy
          >>> referenced by no_std.b533f128-cgu.0
          >>>               /home/gramar/code/rust/nostd-alloc-failure/target/lto/deps/no_std-0e11b6c1ff6df839.no_std.b533f128-cgu.0.rcgu.o:(alloc::raw_vec::finish_grow::h7174e8dc65700b0a)
          collect2: error: ld returned 1 exit status

Since it comes from alloc::raw_vec::finish_grow and only when iterating over something larger than 8 my wild guess is that the compiler can determined that the vec will never grow if less than 8 and doesn't emit the code with the bad symbol, but I don't know much about compilers so I might be way off.

Using rustc version: rustc 1.66.0-nightly (7fcf850d7 2022-10-23)

I'm grateful for any help!

I'm 99% sure it's the same story as with C/C++: LLVM can replace large copies with calls to memcpy.

In case of C/C++ that's easily preventable, just tell the compiler that memcoy doesn't exits, but I'm not sure how analogous option looks like for rustc.

This error occurs because rust assumes the existence of a handful of different symbols. They're primarily software floating-point functions and 128-bit integer arithmetic operations, but a few memory-related ones, including memcpy, need to exist as well.

You have two options:

  1. The recommended way, link in the compiler-builtins crate, or
  2. Define your own version, and make sure to do it with assembly so it doesn't get optimized into a recursive call to itself.
5 Likes

Thank you, I'll try this, currently the compiler-builtins build script segfaults, I'll try to figure it out!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.