NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
17.72k stars 13.85k forks source link

ld.so: $LIB dynamic linking tokens expand to lib instead of lib32 on 32bit #101597

Open Atemu opened 3 years ago

Atemu commented 3 years ago

Describe the bug A clear and concise description of what the bug is.

Dynamic linking tokens can be put in the library path and ld.so is supposed to fill it in according to the executable's arch.

From to the manpage:

       $LIB (or equivalently ${LIB})
              This expands to lib or lib64 depending on the architecture
              (e.g., on x86-64, it expands to lib64 and on x86-32, it
              expands to lib).

To Reproduce Steps to reproduce the behavior:

  1. Run a 32bit executable with $LIB in place of lib or lib32 in the library path
  2. Run the executable
  3. It loads from lib, not lib32

This can be observed by looking at the paths in the log of LD_DEBUG=libs or infering it from LD_PRELOAD error messages:

mkdir /tmp/lib{,32}
touch /tmp/lib/64 /tmp/lib32/32
LD_PRELOAD=/tmp/\$LIB/32 ${pkgs.pkgsi386Linux.coreutils}/bin/ls
ERROR: ld.so: object '/tmp/$LIB/32' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
LD_PRELOAD=/tmp/\$LIB/64 ${pkgs.pkgsi386Linux.coreutils}/bin/ls
ERROR: ld.so: object '/tmp/$LIB/64' from LD_PRELOAD cannot be preloaded (file too short): ignored.

(I'm sure there are better methods.)

Expected behavior A clear and concise description of what you expected to happen.

This would be expected behaviour with 64bit executables but with 32bit ones, it should be the other way around:

ERROR: ld.so: object '/tmp/$LIB/32' from LD_PRELOAD cannot be preloaded (file too short): ignored.
ERROR: ld.so: object '/tmp/$LIB/64' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.

Screenshots If applicable, add screenshots to help explain your problem.

Additional context Add any other context about the problem here.

This popped up in https://github.com/NixOS/nixpkgs/issues/84686 while trying to update to 0.5.1 where Mangohud switched to a loading mechanism which relies on dynamic linking tokens.

Notify maintainers

@vcunat @jtojnar @edolstra @Ma27

Metadata Please run nix-shell -p nix-info --run "nix-info -m" and paste the result.

Maintainer information:

# a list of nixpkgs attributes affected by the problem
attribute:
# a list of nixos modules affected by the problem
module:
stale[bot] commented 3 years ago

I marked this as stale due to inactivity. → More info

Atemu commented 3 years ago

Still important to me.

vcunat commented 3 years ago

But for our i686-linux stdenv the default installation path is $out/lib and no lib32 directory exists in there. That sounds consistent to me; am I missing something?

EDIT: I mean, I can imagine it all changed, but I'd expect that to have quite non-trivial consequences and thus need substantial motivation.

kira-bruneau commented 3 years ago

Yeah, I don't think it would be a good idea to change this globally, especially if we only do this for i686-linux and not other platforms. To emulate what other distros do, I think we would have to build a separate ld specifically for running 32bit applications on a 64bit system, that's different from the ld used on a native 32bit system. Although, I don't think that's a good solution either, since we would have to rebuild everything for both variants. I think we should just keep the current behaviour and workaround this in the projects where this is a problem.

Luckily, for vkBasalt & MangoHud, vulkan-loader now allows defining multiple layer files with the same name, but different architectures: https://github.com/KhronosGroup/Vulkan-Loader/pull/525. The vkBasalt package already assumes this works, but vulkan-loader (and every other vulkan library) still needs to be updated in nixpkgs. I'm actually testing this out the upgrade right now, and I'll be submitting a PR shortly.

vcunat commented 3 years ago

There is some "multi-lib stdenv" but I don't know the status:

{
  # A stdenv capable of building 32-bit binaries.  On x86_64-linux,
  # it uses GCC compiled with multilib support; on i686-linux, it's
  # just the plain stdenv.
  stdenv_32bit = lowPrio (if stdenv.hostPlatform.is32bit then stdenv else multiStdenv);
}
kira-bruneau commented 3 years ago

@vcunat Hmm, I think the 32bit ld in "multi-lib stdenv" might still expand $LIB to lib, since it looks like it just creates a wrapper that combines the two builds: https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/libraries/glibc/multi.nix, but I will try it out.

stale[bot] commented 2 years ago

I marked this as stale due to inactivity. → More info