Solo – a .so loader for static Linux binaries

(github.com)

27 points | by zX41ZdbW 1 hour ago

6 comments

  • simonask 19 minutes ago
    It is a testament to the complete failure of the GNU/Linux userland that something like this seems at all attractive to spend time on (or, it seems, LLM tokens).

    Actually, scratch that, because Windows and macOS have historically struggled with ABI compatibility as well (macOS less so, due to not caring about backward compatibility in the first place).

    How did we get to the point where people feel they need to go to the length of embedding an ELF loader in their binary (!!) rather than just linking with glibc?

    • pg83 16 minutes ago
      Glibc has a terrible history of binary incompatibility. If that's so hard to believe, try running binaries built on one distribution on other distributions. Linux has two stable ABIs: the kernel ABI for static programs, and, ironically, WINE.
  • pg83 7 minutes ago
    How this differs (is better!) from prior art - https://github.com/pg83/solo#how-this-differs-from-prior-wor...
  • nomel 36 minutes ago
    I don't know much about musl.

    > GPU: Vulkan and OpenGL drivers are supplied by the host as shared objects, usually built against glibc, and a fully static musl binary cannot normally dlopen() them.

    Why? Have people managed to break the ancient concept of shared libraries, and this is a fix for that?

    • okanat 27 minutes ago
      Because glibc and GNU set a terrible precedent. On GNU/Linux systems the shared binary interpreter / loader, GCC compiler, the C library and the system C/C++ ABI all depend into each other. You cannot change any of them independently. All shared libraries depend on the specific glibc version to load them into memory to be able to use that specific glibc version as their C library and make calls like dlopen.

      Shared libraries have always been broken in Linux. Unfortunately many things like GPU drivers, graphics libraries and NSS need shared libraries to dynamically load certain runtimes (because you don't want to load all possible GPU drivers in existence to your RAM). So an ecosystem has been developed on top of terrible ABI and architecture GNU/glibc provided.

      • b5n 7 minutes ago
        While I don't disagree with some of the pain you describe, you conveniently gloss over the fact that gnu developed a system that worked, and then made it free to everyone to consult and use.
        • okanat 6 minutes ago
          BSD also did it. They did it better. Maybe more modern but AOSP also did it but at a different level of binary: instead of ELF, using compiled Java bytecode archives.
      • asveikau 9 minutes ago
        > system C/C++ ABI

        C++ abi should not be included in this. It is independent from the other pieces and historically a source of incompatibility on its own.

        Saying "C/C++ abi" as if they are the same is looney tunes, the former is very simple and stable and the latter is very complex.

      • uecker 18 minutes ago
        In what sense do binary interpreter / loader, GCC compiler, C library and system C/C++ ABI dependent on each other? I have certainly mixed different versions of all these components without problems so far.
        • pg83 3 minutes ago
          For example, the itanium unwind ABI implementation lies between these three entities.
        • okanat 9 minutes ago
          When you compile GCC you need to provide a full glibc installation as your target. It is also a dependency of libstdc++.

          C++ global/static variable initialization depends on the specific version of glibc (they don't usually break compat, but they can and they did in the past) which also provides ld-linux.so that loads those global variable placeholders in the correct manner such that glibc and libstdc++ can initialize them correctly.

          This is just one example. Thread local variables and behavior of things like pthreads with signal, fork etc all depend on glibc.

        • duped 3 minutes ago
          The interpreter/loader is glibc and a key part of bootstrapping an executable built against glibc is loading libc itself before continuing on to load the program. Versioning is a problem when distributing binaries linked against a newer glibc to distros that ship an older one. The C compiler doesn't really care as much.
      • duped 6 minutes ago
        > all shared libraries depend on the specific glibc version to load them

        Not really, though. glibc uses symbol versions that are forward but not backward compatible. If you got an error that said "this program was built for a newer version of <distro>" would you say the same thing?

        Note this is the same (if not worse) on MacOS, and on windows you used to distribute the CRT with your application just to deal with the same problem.

    • akerl_ 18 minutes ago
      musl has no problem building and using shared libraries.

      What you can't do is build something statically with musl and then reliably dlopen shared libraries built with glibc.

      • pg83 15 minutes ago
        Well, now it's possible! Furthermore, SoLo binaries can run, without modification, on glibc-based distros, alpine, and soon on android/bionic (not committed yet).
    • ranger_danger 31 minutes ago
      musl does not perfectly emulate all aspects of glibc, so trying to use libraries that assume glibc can sometimes lead to problems.
      • pg83 19 minutes ago
        On the one hand, this is technically true, but on the other, what serious issues do you know that will cause problems in practice? I run tests on 1,000 of the most popular Debian packages.
  • j16sdiz 43 minutes ago
    > backed by its own ELF loader (x86-64 and aarch64) and a glibc ABI bridge

    Yacks

    • mananaysiempre 11 minutes ago
      If you want to load the OpenGL/Vulkan vendor driver then unfortunately you don’t have much of a choice: those are linked against glibc, and I believe generally also against libwayland (I might be wrong about the latter). If you instead want to load plugins or whatnot into your statically linked executable, then personally I’d argue that you shouldn’t be emulating Linux dynamic linking semantics at all, because the whole late-bound global namespace thing is silly and wrong. (Solaris, which is where Glibc took this model from, moved away from it[1] as much as compatibility allowed, and so did Darwin[2], and Windows never had the issue to begin with, but Glibc persisted and Musl copied it.)

      [1] https://www.linker-aliens.org/blogs/rie/entry/direct_binding...

      [2] https://web.archive.org/web/20011004090044/http://developer....

    • fabiensanglard 37 minutes ago
      Please elaborate and explain to people with less knowledge why this is bad.
      • arjvik 26 minutes ago
        Mapping parts of files into executable memory, and then executing them, had better be bulletproof! Exploiting this seems like a direct path to RCE, and it's likely that this sort of library is used by privileged code.

        Purely academically, this is a very cool piece of code! Just hoping that it gets a thorough vetting before used by privileged/security-critical software :)

    • lunixbochs 36 minutes ago
      • pg83 20 minutes ago
        Oh, cool, another prior art I didn't know :)
  • catlifeonmars 38 minutes ago
    So not completely static, since it must link against a libc :P
    • pg83 21 minutes ago
      The binary itself is completely static; the link even provides commands on how to check this!
  • jeffbee 35 minutes ago
    How are we supposed to take this stuff seriously if the author (sic) isn't even willing to write the readme? Claude exists! If I want some slop I can push the button myself.
    • pg83 6 minutes ago
      Tell me, are there any substantive comments on the text, on what has been done, and on the technical implementation, and not on the form?
    • pg83 22 minutes ago
      • WD-42 19 minutes ago
        Parents point is the readme was written by Claude. Signals low effort.
        • pg83 11 minutes ago
          README.md was written by me, and I, of course, used claude/codex for it. In general, I do everything through claude/codex, the reasons are described in https://github.com/pg83/solo/blob/main/CONTRIBUTING.md . And no, it's not low effort, and no, I don't see the point in wasting time de-claude-ifying the text just to avoid it looking like I didn't spend enough time on it.
      • jlebar 18 minutes ago
        Implicit assumption of gp is that the README is llm authored. (Which, I agree is how it reads to me.)