dtolnay / linkme

Safe cross-platform linker shenanigans

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

"The encapsulation symbol needs to be retained under --gc-sections properly"

asomers opened this issue · comments

The current master branch fails to build on FreeBSD 14.0-CURRENT amd64, even though it still works on FreeBSD stable/13.

$ cargo test
...
  = note: ld: error: undefined symbol: __start_linkme_SHENANIGANS
          >>> referenced by x4z07wsgcl2z4i4
          >>>               /usr/home/somers/src/rust/linkme/target/debug/deps/distributed_slice-425b465e5440679a.x4z07wsgcl2z4i4.rcgu.o:(distributed_slice::SHENANIGANS::hca25c6519cd4df0f)
          >>> the encapsulation symbol needs to be retained under --gc-sections properly; consider -z nostart-stop-gc (see https://lld.llvm.org/ELF/start-stop-gc)
          
          ld: error: undefined symbol: __stop_linkme_SHENANIGANS
          >>> referenced by x4z07wsgcl2z4i4
          >>>               /usr/home/somers/src/rust/linkme/target/debug/deps/distributed_slice-425b465e5440679a.x4z07wsgcl2z4i4.rcgu.o:(distributed_slice::SHENANIGANS::hca25c6519cd4df0f)
          
          ld: error: undefined symbol: __start_linkme_EMPTY
          >>> referenced by x4z07wsgcl2z4i4
          >>>               /usr/home/somers/src/rust/linkme/target/debug/deps/distributed_slice-425b465e5440679a.x4z07wsgcl2z4i4.rcgu.o:(distributed_slice::test_empty::EMPTY::h31c7f9e37773eb8f)
          >>> the encapsulation symbol needs to be retained under --gc-sections properly; consider -z nostart-stop-gc (see https://lld.llvm.org/ELF/start-stop-gc)
          
          ld: error: undefined symbol: __stop_linkme_EMPTY
          >>> referenced by x4z07wsgcl2z4i4
          >>>               /usr/home/somers/src/rust/linkme/target/debug/deps/distributed_slice-425b465e5440679a.x4z07wsgcl2z4i4.rcgu.o:(distributed_slice::test_empty::EMPTY::h31c7f9e37773eb8f)
          
          ld: error: undefined symbol: __start_linkme_NONCOPY
          >>> referenced by x4z07wsgcl2z4i4
          >>>               /usr/home/somers/src/rust/linkme/target/debug/deps/distributed_slice-425b465e5440679a.x4z07wsgcl2z4i4.rcgu.o:(distributed_slice::test_non_copy::NONCOPY::h920eb5b4a050a94d)
          >>> the encapsulation symbol needs to be retained under --gc-sections properly; consider -z nostart-stop-gc (see https://lld.llvm.org/ELF/start-stop-gc)
          
          ld: error: undefined symbol: __stop_linkme_NONCOPY
          >>> referenced by x4z07wsgcl2z4i4
          >>>               /usr/home/somers/src/rust/linkme/target/debug/deps/distributed_slice-425b465e5440679a.x4z07wsgcl2z4i4.rcgu.o:(distributed_slice::test_non_copy::NONCOPY::h920eb5b4a050a94d)
          cc: error: linker command failed with exit code 1 (use -v to see invocation)
          

error: could not compile `linkme` due to previous error
error: could not compile `linkme` due to previous error
error: could not compile `linkme` due to previous error

LLVM's instructions on how to solve the problem in C are here, but I don't know the Rust compiler well enough to apply its advice:
https://lld.llvm.org/ELF/start-stop-gc

A workaround is to use RUSTFLAGS="-C link-dead-code".

Mentioning @knan-md @allanjude in case either of you know of a way to fix this. The FreeBSD implementation is from #42.

I see what looks like the same error on Linux (Fedora 36, using either Fedora's Rust or Rust 1.65.0 installed using rustup) if I link with clang/ld.lld (which I was doing by having

[target.'cfg(not(any(target_os = "windows", target_arch = "wasm32")))']
rustflags = ["-C", "linker=clang", "-C", "link-args=-fuse-ld=/usr/bin/ld.lld"]

in ~/.cargo/config.toml, which I'd copied from somewhere a while back to slightly speed up builds and forgot about...).

If I read https://lld.llvm.org/ELF/start-stop-gc right that's expected, ld.lld after 13.0.0 on any ELF platform probably triggers it (or GNU ld before October 2015, but using a linker that old that to link Rust is probably a less common combination).

(I don't know enough about linkers and how Rust interacts with them to help fix this, sorry...)

Putting #[used] on the static variable seems like it should resolve this, but it does not help.

I get this same error targeting Chromeos and Android:
https://ci.chromium.org/ui/p/chrome/builders/try/linux-chromeos-compile-chrome/249317/overview
https://ci.chromium.org/ui/p/chromium/builders/try/android-12-x64-rel/469563/overview

For some reason it's not appearing for Linux and MacOS, though they are using lld.

A workaround is to use RUSTFLAGS="-C link-dead-code".

This does not help us in Chromium, it seems. Applying that to the crate that has the static variable does not remove these errors when we try to link that crate into a .so.

These errors are resolved for me by enabling the used_linker feature. I did not need to add any extra #[used] attr on to the static slice variable itself.

Example successful link here: https://logs.chromium.org/logs/chromium/buildbucket/cr-buildbucket/8774385254500438081/+/u/compile__with_patch_/stdout#L41799_0

These errors are resolved for me by enabling the used_linker feature. I did not need to add any extra #[used] attr on to the static slice variable itself.

Example successful link here: https://logs.chromium.org/logs/chromium/buildbucket/cr-buildbucket/8774385254500438081/+/u/compile__with_patch_/stdout#L41799_0

This workaround also helped me with a very basic example I was building. It appears that lld is a common thread in the problematic configurations. It's also fairly unpleasant to have to pepper the code with #![feature(used_with_arg)] and depend on unstable features.

FWIW, I'm on Debian Linux, so it's not particularly immune to this issue either.