#![no_builtins] does not remove memcpy from pure Rust code

⚓ rust    📅 2025-06-16    👤 surdeus    👁️ 3      

surdeus

I want to write a shared library for Linux which does not depend on libc. Since it contains purely computational (and panic-free) functions it depends only on memset and memcpy symbols.

Let's use the following simplified example:

#![no_std]

#[unsafe(no_mangle)]
pub unsafe extern "C" fn my_cpy(buf_in: *const u8, buf_out: *mut u8, len: usize) {
    core::ptr::copy_nonoverlapping(buf_in, buf_out, len);
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn my_set(buf_ptr: *mut u8, buf_len: usize) {
    let s = core::slice::from_raw_parts_mut(buf_ptr, buf_len);
    s.fill(0);
}

As expected, readelf -Ws results in the following symbol table:

     5: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND memcpy
     6: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND memset
     7: 00000000000015f0    15 FUNC    GLOBAL DEFAULT   11 my_cpy
     8: 0000000000001600    17 FUNC    GLOBAL DEFAULT   11 my_set

Ideally, I would like to "inline" memcpy and memset into the library without exposing them as global symbols (I am fine with it being slightly less efficient than the system's implementation). I could use the compiler-builtins crate with enabled mem feature, but unfortunately it can be used only on Nightly.

But recently I encountered the #![no_builtins] attribute which looks exactly what I want. And indeed, adding it to the crate removes the memcpy symbol, but for some reason memset is still present:

     5: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND memcpy
     6: 00000000000015c0    15 FUNC    GLOBAL DEFAULT   11 my_cpy
     7: 00000000000015d0   156 FUNC    GLOBAL DEFAULT   11 my_set

Is this behavior expected?

2 posts - 2 participants

Read full topic

🏷️ rust_feed