Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

smalloc-sys - Allow libatomic to be statically linked #187

Open
polarathene opened this issue Oct 10, 2024 · 3 comments
Open

smalloc-sys - Allow libatomic to be statically linked #187

polarathene opened this issue Oct 10, 2024 · 3 comments

Comments

@polarathene
Copy link

Problem

libatomic is forced to link dynamically, preventing static builds. Is there a reason for this?

Reproduction

#[global_allocator]
static ALLOCATOR: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc;

fn main() {
    println!("Hello, world!");
}
docker run --rm -it --workdir /example alpine 
apk add rustup gcc g++ cmake make nano
rustup-init -y --profile minimal && source "$HOME/.cargo/env"
cargo init && cargo add snmalloc-rs

# Add the two allocator lines above to `src/main.rs` then compile a static build:
nano src/main.rs
RUSTFLAGS="-C relocation-model=static -C target-feature=+crt-static" cargo build \
  --release \
  --target x86_64-unknown-linux-musl

Failure linking libatomic.so:

  = note: /usr/lib/gcc/x86_64-alpine-linux-musl/13.2.1/../../../../x86_64-alpine-linux-musl/bin/ld: attempted static link of dynamic object `/usr/lib/gcc/x86_64-alpine-linux-musl/13.2.1/../../../../lib/libatomic.so'
          collect2: error: ld returned 1 exit status

libatomic.a is available:

$ ls -l /usr/lib | grep atomic

-rw-r--r--    1 root     root        111956 Mar 12  2024 libatomic.a
lrwxrwxrwx    1 root     root            18 Oct 10 00:29 libatomic.so -> libatomic.so.1.2.0
lrwxrwxrwx    1 root     root            18 Oct 10 00:28 libatomic.so.1 -> libatomic.so.1.2.0
-rwxr-xr-x    1 root     root         26248 Mar 12  2024 libatomic.so.1.2.0

Adding to the RUSTFLAGS ENV value with -C link-arg=/usr/lib/libatomic.a, -L /usr/lib -l static=atomic, or -C prefer-dynamic=no all fail to get this library linked statically.


Cause

microsoft/mimalloc#634

Few older platforms require libatomic for atomic operations but many of them don't (ARMv7 and higher, i686 and higher).
mimalloc however uses it irrespective of target platform when libatomic is installed

This is also the case with snmalloc?

cc:

if target_os == "windows" && target_env == "gnu" {
println!("cargo:rustc-link-lib=dylib=atomic");
}
if target_os == "linux" {
println!("cargo:rustc-link-lib=dylib=atomic");
};

cmake:

println!("cargo:rustc-link-lib=dylib=atomic");

// linux: using PTHREAD_DESTRUCTORS
if cfg!(target_os = "linux") {
println!("cargo:rustc-link-lib=dylib=atomic");
}


Reference - mimalloc-sys

For the mimalloc-sys rust crate this was resolved with an additional conditional (related report, associated issue/PR was resolved in May 2024):

let target_arch = env::var("CARGO_CFG_TARGET_ARCH").expect("target_arch not defined!");

// on armv6 we need to link with libatomic
if target_os == "linux" && target_arch == "arm" {
    println!("cargo:rustc-link-lib=dylib=atomic");
}

However the use of dylib forced dynamically linking the library breaking support for static builds. That was fixed in June 2024.

@SchrodingerZhu
Copy link
Owner

SchrodingerZhu commented Oct 11, 2024

I remember snmalloc emits references to certain __atomic* symbols. Many platforms does not ship a static version of libatomic due to its nature (there is some datum inside libatomic that ought to be shared by processes). Tweaking architectural feature flags can eliminate such symbol references but I need to check with @mjp41 and test it on my side.

@ryancinsight
Copy link
Contributor

ryancinsight commented Dec 3, 2024

@SchrodingerZhu I'm not actually sure designation is required. Currently I can remove dylib for everything I can test and the build work fine with new version. maybe we can make more liberal

@SchrodingerZhu
Copy link
Owner

SchrodingerZhu commented Dec 3, 2024

Revisiting the problem, I think it is correct NOT to enforce dynlib. If the platform ships static library, I don't see the reason not to use it. Our code should be corrected!

The "potential non-static" requirement was actually something I was told years ago by a linux packager when I trying to make full static linkage, which made me give up my attempt. Indeed, archlinux distro only ships the shared library by default:

❯  find /usr/lib* -name libatomic*
/usr/lib/libatomic_ops_gpl.so.1.2.1
/usr/lib/libatomic_ops.so.1
/usr/lib/libatomic_ops.so.1.2.0
/usr/lib/libatomic_ops_gpl.so
/usr/lib/libatomic.so.1.2.0
/usr/lib/libatomic.so.1
/usr/lib/libatomic_ops.so
/usr/lib/libatomic_ops_gpl.so.1
/usr/lib/libatomic.so
/usr/lib/julia/libatomic.so.1
/usr/lib/gcc/x86_64-pc-linux-gnu/12.3.0/libatomic.so
/usr/lib/gcc/x86_64-pc-linux-gnu/13.3.1/libatomic.so
/usr/lib32/libatomic.so.1
/usr/lib32/libatomic.so
/usr/lib32/libatomic.so.1.2.0

Ideally, I don't think we should even link against it if users know that their program is to run only on modern enough hardware.

libatomic is a portability support library. The compiler emits function call to symbols inside libatomic instead of raw atomic instruction to make sure that the produced binary can be run with different hardware capabilities.

00000000000032b0 T __atomic_add_fetch_1@@LIBATOMIC_1.0
0000000000003c10 i __atomic_add_fetch_16@@LIBATOMIC_1.0
0000000000003450 T __atomic_add_fetch_2@@LIBATOMIC_1.0
00000000000035f0 T __atomic_add_fetch_4@@LIBATOMIC_1.0
0000000000003790 T __atomic_add_fetch_8@@LIBATOMIC_1.0
0000000000003300 T __atomic_and_fetch_1@@LIBATOMIC_1.0
0000000000003e80 i __atomic_and_fetch_16@@LIBATOMIC_1.0
00000000000034a0 T __atomic_and_fetch_2@@LIBATOMIC_1.0
0000000000003640 T __atomic_and_fetch_4@@LIBATOMIC_1.0
00000000000037f0 T __atomic_and_fetch_8@@LIBATOMIC_1.0
00000000000025c0 T __atomic_compare_exchange@@LIBATOMIC_1.0
0000000000003270 T __atomic_compare_exchange_1@@LIBATOMIC_1.0
0000000000003a40 i __atomic_compare_exchange_16@@LIBATOMIC_1.0
0000000000003410 T __atomic_compare_exchange_2@@LIBATOMIC_1.0
00000000000035b0 T __atomic_compare_exchange_4@@LIBATOMIC_1.0
0000000000003750 T __atomic_compare_exchange_8@@LIBATOMIC_1.0
0000000000002c00 T __atomic_exchange@@LIBATOMIC_1.0
0000000000003290 T __atomic_exchange_1@@LIBATOMIC_1.0
0000000000003ae0 i __atomic_exchange_16@@LIBATOMIC_1.0
0000000000003430 T __atomic_exchange_2@@LIBATOMIC_1.0
00000000000035d0 T __atomic_exchange_4@@LIBATOMIC_1.0
0000000000003770 T __atomic_exchange_8@@LIBATOMIC_1.0
0000000000003140 T __atomic_feraiseexcept@@LIBATOMIC_1.1
00000000000032a0 T __atomic_fetch_add_1@@LIBATOMIC_1.0
0000000000003bc0 i __atomic_fetch_add_16@@LIBATOMIC_1.0
0000000000003440 T __atomic_fetch_add_2@@LIBATOMIC_1.0
00000000000035e0 T __atomic_fetch_add_4@@LIBATOMIC_1.0
0000000000003780 T __atomic_fetch_add_8@@LIBATOMIC_1.0
00000000000032e0 T __atomic_fetch_and_1@@LIBATOMIC_1.0
0000000000003e30 i __atomic_fetch_and_16@@LIBATOMIC_1.0
0000000000003480 T __atomic_fetch_and_2@@LIBATOMIC_1.0
0000000000003620 T __atomic_fetch_and_4@@LIBATOMIC_1.0
00000000000037d0 T __atomic_fetch_and_8@@LIBATOMIC_1.0
00000000000033a0 T __atomic_fetch_nand_1@@LIBATOMIC_1.0
00000000000041c0 i __atomic_fetch_nand_16@@LIBATOMIC_1.0
0000000000003540 T __atomic_fetch_nand_2@@LIBATOMIC_1.0
00000000000036e0 T __atomic_fetch_nand_4@@LIBATOMIC_1.0
0000000000003890 T __atomic_fetch_nand_8@@LIBATOMIC_1.0
0000000000003320 T __atomic_fetch_or_1@@LIBATOMIC_1.0
0000000000003f60 i __atomic_fetch_or_16@@LIBATOMIC_1.0
00000000000034c0 T __atomic_fetch_or_2@@LIBATOMIC_1.0
0000000000003660 T __atomic_fetch_or_4@@LIBATOMIC_1.0
0000000000003810 T __atomic_fetch_or_8@@LIBATOMIC_1.0
00000000000032c0 T __atomic_fetch_sub_1@@LIBATOMIC_1.0
0000000000003d00 i __atomic_fetch_sub_16@@LIBATOMIC_1.0
0000000000003460 T __atomic_fetch_sub_2@@LIBATOMIC_1.0
0000000000003600 T __atomic_fetch_sub_4@@LIBATOMIC_1.0
00000000000037a0 T __atomic_fetch_sub_8@@LIBATOMIC_1.0
0000000000003360 T __atomic_fetch_xor_1@@LIBATOMIC_1.0
0000000000004090 i __atomic_fetch_xor_16@@LIBATOMIC_1.0
0000000000003500 T __atomic_fetch_xor_2@@LIBATOMIC_1.0
00000000000036a0 T __atomic_fetch_xor_4@@LIBATOMIC_1.0
0000000000003850 T __atomic_fetch_xor_8@@LIBATOMIC_1.0
0000000000003230 T atomic_flag_clear@@LIBATOMIC_1.2
0000000000003240 T atomic_flag_clear_explicit@@LIBATOMIC_1.2
0000000000003210 T atomic_flag_test_and_set@@LIBATOMIC_1.2
0000000000003220 T atomic_flag_test_and_set_explicit@@LIBATOMIC_1.2
0000000000002f30 T __atomic_is_lock_free@@LIBATOMIC_1.0
0000000000002120 T __atomic_load@@LIBATOMIC_1.0
0000000000003250 T __atomic_load_1@@LIBATOMIC_1.0
0000000000003910 i __atomic_load_16@@LIBATOMIC_1.0
00000000000033f0 T __atomic_load_2@@LIBATOMIC_1.0
0000000000003590 T __atomic_load_4@@LIBATOMIC_1.0
0000000000003730 T __atomic_load_8@@LIBATOMIC_1.0
00000000000033c0 T __atomic_nand_fetch_1@@LIBATOMIC_1.0
0000000000004210 i __atomic_nand_fetch_16@@LIBATOMIC_1.0
0000000000003560 T __atomic_nand_fetch_2@@LIBATOMIC_1.0
0000000000003700 T __atomic_nand_fetch_4@@LIBATOMIC_1.0
00000000000038b0 T __atomic_nand_fetch_8@@LIBATOMIC_1.0
0000000000003340 T __atomic_or_fetch_1@@LIBATOMIC_1.0
0000000000003fb0 i __atomic_or_fetch_16@@LIBATOMIC_1.0
00000000000034e0 T __atomic_or_fetch_2@@LIBATOMIC_1.0
0000000000003680 T __atomic_or_fetch_4@@LIBATOMIC_1.0
0000000000003830 T __atomic_or_fetch_8@@LIBATOMIC_1.0
0000000000003200 T atomic_signal_fence@@LIBATOMIC_1.2
00000000000022f0 T __atomic_store@@LIBATOMIC_1.0
0000000000003260 T __atomic_store_1@@LIBATOMIC_1.0
0000000000003990 i __atomic_store_16@@LIBATOMIC_1.0
0000000000003400 T __atomic_store_2@@LIBATOMIC_1.0
00000000000035a0 T __atomic_store_4@@LIBATOMIC_1.0
0000000000003740 T __atomic_store_8@@LIBATOMIC_1.0
00000000000032d0 T __atomic_sub_fetch_1@@LIBATOMIC_1.0
0000000000003d50 i __atomic_sub_fetch_16@@LIBATOMIC_1.0
0000000000003470 T __atomic_sub_fetch_2@@LIBATOMIC_1.0
0000000000003610 T __atomic_sub_fetch_4@@LIBATOMIC_1.0
00000000000037b0 T __atomic_sub_fetch_8@@LIBATOMIC_1.0
00000000000033e0 T __atomic_test_and_set_1@@LIBATOMIC_1.0
0000000000004270 i __atomic_test_and_set_16@@LIBATOMIC_1.0
0000000000003580 T __atomic_test_and_set_2@@LIBATOMIC_1.0
0000000000003720 T __atomic_test_and_set_4@@LIBATOMIC_1.0
00000000000038d0 T __atomic_test_and_set_8@@LIBATOMIC_1.0
00000000000031f0 T atomic_thread_fence@@LIBATOMIC_1.2
0000000000003380 T __atomic_xor_fetch_1@@LIBATOMIC_1.0
00000000000040e0 i __atomic_xor_fetch_16@@LIBATOMIC_1.0
0000000000003520 T __atomic_xor_fetch_2@@LIBATOMIC_1.0
00000000000036c0 T __atomic_xor_fetch_4@@LIBATOMIC_1.0
0000000000003870 T __atomic_xor_fetch_8@@LIBATOMIC_1.0
                 w __cxa_finalize@GLIBC_2.2.5
                 w __gmon_start__
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000000000 A LIBATOMIC_1.0
0000000000000000 A LIBATOMIC_1.1
0000000000000000 A LIBATOMIC_1.2
                 U memcmp@GLIBC_2.2.5
                 U memcpy@GLIBC_2.14
                 U __memcpy_chk@GLIBC_2.3.4
                 U pthread_mutex_lock@GLIBC_2.2.5
                 U pthread_mutex_unlock@GLIBC_2.2.5
                 U __stack_chk_fail@GLIBC_2.4

I don't think any of the symbol is really needed for x86-64-v2 and above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants