zilch-lang/nstar

Fetching the path to the linux dynamic loader

Closed this issue · 3 comments

Dynamically loading functions at runtime requires to have the dynamic loader path in the ELF file (at least on Linux).

In an ELF file, it is done by adding a .interp section which points to the path of the dynamic loader. While this can be hardcoded as /lib64/ld-linux-x86-64.so.2 for example, this does not work on all Linux distributions (like NixOS). On NixOS, there is a tool called patchelf which is in charge of updating hardcoded paths such as this one.
While this works, there may be better alternatives, like:

  • using a shell command to fetch the file (e.g. find / -path '*ld-linux*.so.? -type f
    This is very slow (it has to traverse the entire filesystem) and does not necessarily works great (you can have multiple entries, or not handle different versions, etc)
  • hardcoding the path unless a flag like --dynamic-loader=path/to/ld-linux.so.N is specified
    This should work, unless the path specified is invalid
  • automatically retrieving the path through for example an environment variable NSTAR_DYN_LOADER which would be set on installation (requiring some way to fetch the path anyway, at some point)

One of the downside of having the --dynamic-loader option is that if there are any breaking change between major versions of glibc, it won't really handle them properly.
A downside of having an environment variable for this is that the compiler depends entirely on the users' environment which may not be a great thing to depend on. You also have to fetch the path to the dynamic loader at some point, and there doesn't seem to really be one working for all distributions (or at least I haven't found one).

The (probably) best alternative would be to hardcode the path to the dynamic loader, and, on NixOS at least, use patchelf with the hook, or use the --dynamic-loader (automatically set to ${pkgs.glibc}/bin/ld-linux-<arch>.so.N) in a wrapper.

Seems like gcc follows the --dynamic-linker approach to the problem, with a default argument /lib64/ld-linux-x86-64.so.2 or /lib/ld-linux.so.2 (for either x86 or x64, I don't know for other architectures).
I believe this is the correct way to go, this way we can just wrap the executable on NixOS (the only problem would be how to fetch the dynamic linker consistently, depending on x86 or x64, we could set it to ${pkgs.glibc}/lib/ld-linux-x86-64.so.2 or ${pkgs.glibc}/lib/ld-linux.so.2 I believe -- maybe even replacing the .2 with the major version of ${pkgs.glibc}).

In fact, because we are only generating relocatable ELF object files, and linking them to the C-runtime, ld already does this for us, which saves us some time here.