I have fond memories of using ELF interpreter settings so that .NET apps would just directly invoke Mono. I’m pretty sure I did the same for Java at some point. It’s a bit of a trip seeing that Alpine gets along without basic dynamic linking, though.
That leveraged binfmt_misc, I think? Java in a Debian still set that up to this day. My little Java app (wadc) has a /usr/bin/wadc that is literally a JAR file.
It is incredibly annoying that running an executable whose dynamic dependency is missing can emit just “file not found” with no extra useful information. I’ve ended up scratching my head over this a few times before I learned the pattern. Why doesn’t the dynamic linker just print out the name of the missing library?!
If it is just a missing library, that’s exactly what happens (libfoo.so.3: cannot open shared object file: No such file or directory).
The case discussed here, though, is where the missing piece is the dynamic linker itself (ld.so), which is a trickier problem, because what’s going to do the printing? The execve call itself fails (whereas with a missing library execve succeeds but the newly-running program then fails), so it’s up to whatever program called execve to detect that and report the error. The failure mode in question is in fact due a missing file, so ENOENT is what the kernel returns, and hence what the caller will probably print. I suppose you could try to get a specialized EBADINTERP errno code or something for this particular case of a missing or otherwise unusable interpreter added to the kernel/libc/POSIX, but with what currently exists I don’t see an easy solution.
I managed to discover the circumstances under which I had the problem: attempting to run a 32-bit executable on a 64-bit system when some libraries are missing, e.g.:
% ./cabal
zsh: no such file or directory: ./cabal
% ldd ./cabal
linux-gate.so.1 (0xf7fa4000)
libz.so.1 => /lib/i386-linux-gnu/libz.so.1 (0xf7f61000)
libgmp.so.10 => not found
libc.musl-x86.so.1 => not found
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d78000)
/lib/ld-musl-i386.so.1 => /lib/ld-linux.so.2 (0xf7fa6000)
You can get a significant amount of information out of the linux dynamic linker using some of the available debug environment variables. See: https://linux.die.net/man/8/ld-linux
For example:
export LD_DEBUG=all
ls
Will give you more information than you know what to do with :)
That being said, the case being discussed here could certainly use some better error reporting!
I love seeing these posts about things that are just second-nature to me, and yet some new individual has just learned what is going on under the covers!
I think that CGO is implicitly enabled when using networking stuff in Go programs, but I might be misremembering something.
You need it for non-sucking getaddrinfo() on Linux, it enables NSS modules.
I have fond memories of using ELF interpreter settings so that .NET apps would just directly invoke Mono. I’m pretty sure I did the same for Java at some point. It’s a bit of a trip seeing that Alpine gets along without basic dynamic linking, though.
That leveraged binfmt_misc, I think? Java in a Debian still set that up to this day. My little Java app (wadc) has a /usr/bin/wadc that is literally a JAR file.
It is incredibly annoying that running an executable whose dynamic dependency is missing can emit just “file not found” with no extra useful information. I’ve ended up scratching my head over this a few times before I learned the pattern. Why doesn’t the dynamic linker just print out the name of the missing library?!
If it is just a missing library, that’s exactly what happens (
libfoo.so.3: cannot open shared object file: No such file or directory
).The case discussed here, though, is where the missing piece is the dynamic linker itself (ld.so), which is a trickier problem, because what’s going to do the printing? The
execve
call itself fails (whereas with a missing libraryexecve
succeeds but the newly-running program then fails), so it’s up to whatever program calledexecve
to detect that and report the error. The failure mode in question is in fact due a missing file, so ENOENT is what the kernel returns, and hence what the caller will probably print. I suppose you could try to get a specializedEBADINTERP
errno code or something for this particular case of a missing or otherwise unusable interpreter added to the kernel/libc/POSIX, but with what currently exists I don’t see an easy solution.I managed to discover the circumstances under which I had the problem: attempting to run a 32-bit executable on a 64-bit system when some libraries are missing, e.g.:
You can get a significant amount of information out of the linux dynamic linker using some of the available debug environment variables. See: https://linux.die.net/man/8/ld-linux
For example:
Will give you more information than you know what to do with :)
That being said, the case being discussed here could certainly use some better error reporting!
Doesn’t help in this case unfortunately:
I love seeing these posts about things that are just second-nature to me, and yet some new individual has just learned what is going on under the covers!