Join the discussion

Write your take first — we'll ask for email only when you're ready to publish.

  • Hacker News
  • i'm not sure how much people realize that the modern "graphics driver" is actually just "the kernel multiplexes userspace messages to/from the GPU and we've taught mesa to understand each family of GPU you'd ever care to support."

    i helped somebody get Doom running on an old embedded system running some 4.x kernel. we just built everything, including mesa, statically and deployed that. imagine building everything static but loading the system's libgl.so instead (which was probably just a symlink or abstraction over mesa's own implementation). what's the benefit: we'd get older, less optimized graphics routines from 5 years ago?

    if you're statically linking, then just bring your own graphics "driver". the kernel interfaces are stable enough. it's not conceptually different than embedding `syscall`s directly into your application the same way you do when statically linking libc.

  • > i'm not sure how much people realize that the modern "graphics driver" is actually just "the kernel multiplexes userspace messages to/from the GPU and we've taught mesa to understand each family of GPU you'd ever care to support."

    In the case of OpenGL, it has a fairly sophisticated state tracker, which you can carry around with you. For example, I can statically compile ANGLE this way.

    But even OpenGL/Vulkan have a shader compiler that's unique to the hardware (it's expensive to carry it around with every piece of hardware in the universe).

    And I'm not even talking about libdrm, which is quite tightly tied to the kernel version.

    I know exactly what I'm talking about, because I can also statically compile Mesa into my application.

    by pg83
  • Do people say "so", "ess-oh" or "dot-ess-oh"? The title "a .so" is clunky to the "ess-oh" gang.
  • Well .so is short for shared object so I think "a .so" is correct.
  • I don’t think I’ve said it out loud more than a couple times in my life. But in general I think I spell out / pronounce the “dot” in file extensions unless it’s completely obvious from context.
  • If you dynamically sold an SO are you still static even if you did it "custom" ? At that point it's a dynamic loader in another name?
  • Technically, you're right, it's a dynamic loader. Technically, it's pure dynamic loading.

    If we look at the issue at its core, we're still a statically linked program in a hostile environment, forced to dynamically load device drivers from the system.

    It's similar to Golang; on MacOS, it has to use libSystem, even though otherwise, these are the statically linked Go binaries we're used to and love.

    Let me add a little more detail: if I use vdso with gettimeofday in a statically linked program on Linux, am I still a statically linked program, or not? :)

    by pg83
  • 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.
  • by pg83
  • Disclaimer: This is a user’s perspective rather than a programmer’s perspective.

    valid point. I am usually okay with LLM generated code since even if it might not be architecturally sound It is usually well commented and has tests and documentation for helping another agent/human debug any issues.

    But, just the painful experience of debugging any dlopen related crashes and/or intermittent bugs; and the sheer amount of tokens burnt by an LLM chasing tangents when shown a stack trace; I wouldn’t touch this at least as a packager/consumer of certain apps for personal usage on older distros. So far, AnyLinux-Appimages seem to be a mature solution with great support from the developers, in case anyone lands here for packaging applications to run on older distros.

  • 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?
    by pg83
  • I have faced a similar issue in the past, and I don't understand how static binaries from the host are supposed to solve this.

    From what I remember, GPU access on Linux 'works' by accessing specific FDs under /dev, which are vendor specific - this is what these libs do under the hood.

    The libraries don't have any magic powers - if the FD is inaccessible, you won't be able to do anything.

    So there's some vendor specific access needed in containers anyway (or a blanket allow, which is a BAD idea).

    Also not sure why dynamic linking isn't good enough for this - the issue lies with the permissions, not how you load/link libraries.

  • I've implemented the same thing for micron (more or less). One advice I'd give you is to _really_ take care regarding SysV/ELF ABI conventions, there's tons of undocumented stuff in there and it's really easy to mess something up or cause a security defect (see AT_SECURE). That being said the way you're doing is also tricky(ish) because if I understood your implementation correctly you're hooking this into an already running musl which could cause backwards compatibility issues if musl changes under you. Doing this is safer if you control the entire runtime.
  • > One advice I'd give you is to _really_ take care regarding SysV/ELF ABI conventions, there's tons of undocumented stuff in there and it's really easy to mess something up or cause a security defect (see AT_SECURE)

    Yes, it's not trivial, but I hope that over time everything will settle down.

    > if I understood your implementation correctly you're hooking this into an already running musl which could cause backwards compatibility issues if musl changes under you

    No, I hook this to musl, which is statically linked into my binary, and I have complete control over it.

    by pg83
  • How this differs (is better!) from prior art - https://github.com/pg83/solo#how-this-differs-from-prior-wor...
    by pg83
  • What are your plans around the maintenance of this project, how would you feel about solo being incorporated into the musl build for graphics.gd ?
  • Note: That md file is LLM spew (like most of rest of codebase).

    https://github.com/pg83/solo/commits/main/README.md

    https://github.com/pg83/solo/commits/main/

  • If you can figure out your own ELF loader, you can figure out how to build a partially static executable that doesn't need this. You can mix static and dynamic linking. Build tooling around that is just shit.
  • Can you really mix it? When I break or remove a shared lib, some binaries no longer work. With static libs or even better, e. g. statically compiled busybox, I don't have that issue, so I disagree on the claim that mixing solves everything as such. I keep the basic toolchain I use as statically compiled variant. The whole system works better if I can break it less easily.
  • In this scenario, I'll have to choose which libc I want to run. These won't be portable Linux binaries in the true sense of the word; I'll have to leave Alpine out, and possibly Android, which I don't want.
    by pg83
  • Every couple of years, I revisit my PL dev hobby and this time I decided to create a language/runtime with pre-emptive scheduling using instruction fuel. While I always do freestanding builds, this time I decided that I also wanted to support native FFI.

    That is when I realized the true horror of (g)libc. It wants to inject itself at the root of the library/program and everything from threading to dlopen/dlsym is impacted. I tried a lot of workarounds including trying to implement a loader myself, but the complexity (and fragility) grew so much that I felt it was not worth it.

    Finally, I retreated into the safe world of a freestanding runtime + syscalls. FFI, if it has to happen, will occur via IPC of some kind. A second process linked against glibc that will manage calls on behalf of the clean first one.

  • 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?

  • musl does not perfectly emulate all aspects of glibc, so trying to use libraries that assume glibc can sometimes lead to problems.
  • 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.

  • Because many folks don't understand UNIX systems introduced dynamic linking for several reasons, and they actually only had static linking for almost 20 years, since UNIX was known outside Bell Labs.

    Additionally many other OSes have had both approaches since their early days, Xerox PARC ones.

    For some strange reason they assume to know better than all those researchers.

  • > Why? Have people managed to break the ancient concept of shared libraries

    If you break or remove a shared lib here, you may no longer be able to compile something from source. I had that happen in the past before I started to use more statically compiled programs (and busybox too).

    Assuming everything works as-is via shared libraries at all times, makes little sense for ALL linux systems. For instance, some people upgrade glibc manually. Then you need a working base system to resume compilation. I do that for my customized gobolinux system, so I can use any program version as well as any glibc version (assuming I can still compile the program; many older programs no longer compile).

  • 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.

  • So we are re-inventing patched a.out files, back when UNIX systems started to introduce dynamic loading, before ELF was invented?

    Advocates of static linking keep forgetting once upon a time UNIX only had static linking, then we had overlays, and eventually dynamic linking came to be.

  • Of course, I remember those times very well.

    And I also remember very well that dynamic linking appeared ONLY because we were catastrophically short on memory; everything else was added much later.

    Now we have plenty of memory, and we can very well return to our blessed roots!

    by pg83
  • This is a big forwards-compatibility risk. Suppose glibc adds a new symbol, and then a GPU driver adds a dependency on that symbol. The user wants to run an old executable with the updated GPU driver (maybe the old GPU driver doesn’t support their GPU). Normally, this would work fine: the user has to use a new copy of glibc, which will be compatible with both the new GPU driver and the old executable. But with your approach, the GPU driver is forced to use the glibc reimplementation which has been statically linked into the executable. Which, since the executable is old, can’t possibly implement the new symbol.

    The same issue would occur if glibc adds a new version of an existing symbol and then the GPU driver is recompiled. (Or, for that matter, if a GPU driver adds a dependency on a symbol which glibc has always supported but which isn’t in the subset that you reimplemented, though in theory that could be solved if you reimplemented 100% of the symbols.)