Change:
There is a policy that Rust's does not depend on the libc implementation for a given target. This has caused us quite a deal of heartache in the past, and it is about to cause us more, but I believe it is and has been the right choice. Rust code relying only on our core library should not really require participation from any other toolchain or library beyond our own code. We should be able to have "pure Rust" targets without being entangled with implementation details. We should be able to, in the long run, build and link our own code. And we should not close the door on that, certainly not at this stage where people are actually building pure Rust runtime libraries and operating systems. In I made a mistake that violated this policy. I was not familiar with how the function definitions would be resolved, and I thought they only depended on the linker somehow. It had not occurred to me, at the time, that it induced a dependency on glibc, and I was somehow not tipped off by the other bugs that started showing up. It has caused recurring issues even until relatively recently: I have personally also run into this in another project, even with very recent compilers. A lot of work has been done to make my mistake compile anyways, and it's still not enough. Obviously, this deeply hurts our ability to implement things like . Fortunately, it is easily corrected: simply remove the feature from the aarch64-unknown-linux-gnu target spec unless and until we arrive at an implementation that does not require participation from glibc. This will lead to a performance regression using atomic instructions in some cases, but that's an acceptable loss if the alternative is continually trashing everyone's ability to build Rust code. This may require retouching code in compiler-builtins as well.
to be clear, is not caused by this issue, but fixing it exposes a latent bug caused by this issue (compiler_builtins has a hard dependency on LLVM's compiler-rt on that target: ). thank you for writing this up! I hadn't even realized this was related to libc.
Yeah there's a lot of "the problems are so weird and arcane that issues are rarely about them but the problems get mentioned in passing comments" which is why I felt posting a separate issue was necessary.
Assigning a priority label to keep awareness high on this issue (bits of ). The relevant team will decide how to work on this -label:I-prioritize +label:P-high
Note re: this football: T-libs took a look at it. As Thom expresses, from the libcore perspective it's purely an optimization and we can disable it, and even though it has to do with how libcore functions, it has to do with how compiler targets work and how they are built. We enable it explicitly for certain targets, but LLVM also enables it implicitly. And as long as this remains an issue, this breaks a lot of ways to compile for a lot of (all?) tier 3 targets, making it much harder to use the compiler. So, T-libs thinks T-compiler should take a look at it!
T-compiler they need to that "core shall not depend on libc" is actually the policy. There seemed to be consensus that it's a good policy, but the title of this issue is the first time most of the team had heard it exists. an MCP for ripping out from . has graciously offered to write this up. I believe this will also include a proposal to codify 1.
Also somewhat related, some targets (notably, Android) use emulated TLS for which makes depend on pthreads from libc. This is a concern if we ever want to stabilize as a core language feature available in .
This sounds like a bug in llvm/compiler-rt where musl may want to check for HWCAP in a different way than glibc. The code in could be amended with something like this:
is supported in musl in all versions after 1.0.0: So the fix in llvm/compiler-rt should be to detect at build time whether is supported in the libc.
That assumes we want to have to depend on libc or indeed even compiler-rt to build for a target. The intent of compiler-builtins is pretty explicitly to not have to depend on compiler-rt.
Regardless of whether or not depends on the system C library (I'd prefer it did not, but it may be unavoidable), it is quite problematic for us to have a dependency on functionality provided only by the C code that don't have shims in , which is the current state of things on aarch64. This is bad because: don't always have those sources available when compiling . if we do have the compiler-rt sources, we might not be able to build them (note that it's much harder to cross-compile C code than pure Rust code) other targets, compiling these sources is entirely optional (for those reasons), and when unavailable the non-optional functionality comes from (sometimes with less efficient implementations). Concretely, this breaks a bunch of things that would/should otherwise work: -compiled [^andnostd] (and several other targets), unless the user has both: A configured C cross compilation toolchain (including the system headers, a C cross compiler, the target's ranlib/ar, and so on) And also has a checkout of the sources somewhere on their machine, and sets the path to that location (and even then there might be some other requirement needed). in many cases (probably way more of them than it likely needs to, honestly -- this is currently the main reason it doesn't happen to work most of the time IIUC). other stuff along the same lines too. Anyway, this is at best pretty annoying, and is something that (IMO) we'll need to address even if we decide "yep core can require libc". [^andnostd]: Note that this is broken even for code when using too. I think the most straightforward approach to fix those issues (without totally giving up ) is probably for us to implement versions of the outline-atomic functions in Rust inside the crate, for use as a fallback in cases where we don't have the C code, or don't have a cross compiler. This is straightforward in principal, but I don't know if it's practical for us to port the runtime feature detection aspect to Rust. Aesthetics aside, adding a dependency on -the-crate into seems... non-trivial to me to get working with the linker in all cases (maybe I'm mistaken, and it won't be an issue?). That said, -without- is already missing a bunch of other optimizations, so maybe not having support for runtime feature detection in the fallback code would be fine. If so, it's presumably straight-forward to port to Rust (the hard part is probably figuring out when to turn on the fallback without breaking anything...)
Following the ARM Architecture Reference Manual, the detection of the LSE atomic instructions can be done in assembly by reading the value of the "AArch64 Instruction Set Attribute Register 0" register, and checking that the value of bits [23:20] is equal to . Here's how golang does the CPU feature detection:
The above only works for Linux because Linux emulates these instructions from user-space starting in 4.11 which i believe is above the minimum supported Linux kernel version for Rust. Similarly, freebsd supports this emulation in 12+. That said, i really want to see outline-atomics not get dropped of the large performance delta it can bring.
It works only with relatively new versions of some OSes (, ). Also, AFAIK, it does not work on some environments regardless of OS versions. is a record of a test I did a while back. In any case, on Linux, HWCAPCPUID should be checked first . FWIW, (FEATLSE128) also means FEATLSE is implemented.
now that compiler-builtins supports outline-atomics natively, does it make sense to close this issue? I tested in that it fixed
Ah, thank you so much!

Discussion:
[[package]] name = "compiler_builtins" <del> version = "0.1.93" </del> <ins> version = "0.1.95" </ins> source = "registry+https://github.com/rust-lang/crates.io-index" <del> checksum = "76630810d973ecea3dbf611e1b7aecfb1012751ef1ff8de3998f89014a166781" </del> <ins> checksum = "6866e0f3638013234db3c89ead7a14d278354338e7237257407500009012b23f" </ins> dependencies = [ "cc", "rustc-std-workspace-core",

panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } libc = { version = "0.2.146", default-features = false, features = ['rustc-dep-of-std'], public = true } <del> # FIXME(Nilstrieb): https://github.com/rust-lang/compiler-builtins/pull/532/files#r1249354225 compiler_builtins = { version = "=0.1.93" } </del> <ins> compiler_builtins = { version = "0.1.95" } </ins> profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] }