Why does this binary executable give "cannot execute: required file not found"?

I want to run rust-analyzer in nvim, installed via mason.
Mason downloads the required binaries to ~/.local/share/nvim/mason/packages/rust-analyzer/rust-analyzer-x86_64-unknown-linux-gnu. As we all know, arbitrary binaries and NixOS don’t play well. Still I’m curious to understand the issue in this case.

I’m use to the linking issues which gives “No such file or directory”, but here I get another issue

$ ~/.local/share/nvim/mason/packages/rust-analyzer/rust-analyzer-x86_64-unknown-linux-gnu  --help
bash: /home/gdforj/.local/share/nvim/mason/packages/rust-analyzer/rust-analyzer-x86_64-unknown-linux-gnu: cannot execute: required file not found

I’ve never seen that before, so I investigate

$ file ~/.local/share/nvim/mason/packages/rust-analyzer/rust-analyzer-x86_64-unknown-linux-gnu
/home/gdforj/.local/share/nvim/mason/packages/rust-analyzer/rust-analyzer-x86_64-unknown-linux-gnu: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=ae6a547566c4e303e37f2a814255a46107a9519a, with debug_info, not stripped

I’m not sure I understand all of it, but at least it’s a 64-bit ELF binary executable for my platform, which should be fine.

$ ldd ~/.local/share/nvim/mason/packages/rust-analyzer/rust-analyzer-x86_64-unknown-linux-gnu
	linux-vdso.so.1 (0x00007ffcb4dc5000)
	libgcc_s.so.1 => /nix/store/kni8lkj9hnyfvrnag648f35misbi5gja-xgcc-12.2.0-libgcc/lib/libgcc_s.so.1 (0x00007f6c39e6a000)
	librt.so.1 => /nix/store/1nyg1fvhpz8bx3vn3r9f18zhra2rpbx9-glibc-2.37-8/lib/librt.so.1 (0x00007f6c39e65000)
	libpthread.so.0 => /nix/store/1nyg1fvhpz8bx3vn3r9f18zhra2rpbx9-glibc-2.37-8/lib/libpthread.so.0 (0x00007f6c39e60000)
	libm.so.6 => /nix/store/1nyg1fvhpz8bx3vn3r9f18zhra2rpbx9-glibc-2.37-8/lib/libm.so.6 (0x00007f6c39d80000)
	libdl.so.2 => /nix/store/1nyg1fvhpz8bx3vn3r9f18zhra2rpbx9-glibc-2.37-8/lib/libdl.so.2 (0x00007f6c39d7b000)
	libc.so.6 => /nix/store/1nyg1fvhpz8bx3vn3r9f18zhra2rpbx9-glibc-2.37-8/lib/libc.so.6 (0x00007f6c37c1a000)
	/lib64/ld-linux-x86-64.so.2 => /nix/store/1nyg1fvhpz8bx3vn3r9f18zhra2rpbx9-glibc-2.37-8/lib64/ld-linux-x86-64.so.2 (0x00007f6c39e8d000)

There does not seem to be any issue with linking either, it finds what it needs.
In fact, LD_DEBUG is useless because it seems to fail before it even reaches that step.

And stracegives me that

$ strace ~/.local/share/nvim/mason/packages/rust-analyzer/rust-analyzer-x86_64-unknown-linux-gnu 
execve("/home/gdforj/.local/share/nvim/mason/packages/rust-analyzer/rust-analyzer-x86_64-unknown-linux-gnu", ["/home/gdforj/.local/share/nvim/m"...], 0x7ffc8e0f99b0 /* 93 vars */) = -1 ENOENT (No such file or directory)
strace: exec: No such file or directory
+++ exited with 1 +++

What kind of linuxery makes this executable not run?

1 Like

I assume the culprit is that the dynamic loader is not present in this location which causes this error to occur. It’s a confusing error and I know it well from when trying to run 32-Bit binaries on a 64-Bit Linux that did not yet have any 32-Bit compatibility installed. A not found dynamic loader causes this error message that is not at all helpful.

Try running this with something like steam-run where the environment makes sure that the dynamic loader is accessible from the default location and you will not get this error anymore.

2 Likes

This is, I’d argue, a fairly common failure when using prebuilt binaries on nixos. So common I expected this wiki page:

To mention this error. Since that has techniques for resolving this. Nothing sufficient for search I think. I’ll add some.

2 Likes

Well, now that you point it out, I realize the interpreter path is indeed wrong :man_facepalming:

Thanks for the help :pray:

For reference, it can be fixed using patchelf by changing the ELF interpreter

$ nix run nixpkgs#patchelf -- --set-interpreter "$(nix eval nixpkgs#stdenv.cc.bintools.dynamicLinker --raw)"  /path/to/your/file

in my case /path/to/your/file was ~/.local/share/nvim/mason/packages/rust-analyzer/rust-analyzer-x86_64-unknown-linux-gnu.

1 Like

QQ, I have run into this issue with a program that I used student.mkDerivation to install.

I have tested it, and it works if I run something like steam-run app --help.

Is it possible to use patchelf in something like the patchPhase? Just looking to avoid a rabbit hole looking for code samples if it is not possible.

Thank you.

EDIT, looks like this wiki page covers it. But… that makes my head hurt.

Use autoPatchelfHook

1 Like

Yeah, I had tried that, but kept running into errors. But now knowing it is the “right” way, I will go back and continue to tshoot it.

I’ve never tried setting up autoPatchelfHook, but in this guide from nix.dev they suggest using nix-ld as an alternative. I just set it up to resolve an issue I was hitting with the lua-language-server, and it worked pretty easily. The one thing that tripped me up was not reading that I needed to log out and back in again for the initial fix to go into place.

https://nix.dev/guides/faq.html#how-to-run-non-nix-executables

To note, nix-ld is the absolute last resort, and of course won’t work on machines that don’t have it set up, nor (as the page notes) does it appear to work for 32-bit executables.

There’s also the one option they neglected to mention of wrapping the executable, but that comes with its own caveats.

1 Like