1. 67

  2. 17

    FWIW, this blog post is not saying “Rust does not have a stable ABI”, it’s more of a response to it.

    1. 6

      This is where I think sometimes the post headline should be amended…

      Very interesting post.

    2. 5

      Is shared libraries really needed those days? Same space? My laptop has 2Tb of it.

      1. 2

        I’d love for them to go away and us keep everything separate.

        While the ‘disk’ space issue is probably not a problem in many cases (I know I’d rather sacrifice space for duplicate code than have to deal with dependency hell) there are likely more issues to consider.

        I was going to say that it’s a pain to have to update an identical library in multiple packages when there’s a (security) fix, but it’s common that a fix breaks some packages and not others, so you’re left with the choice of some broken packages or a security fix you may or may not feel causes a vulnerability for you.

        Being able to update some packages (where a ‘fix’ doesn’t break them) and leave others until later, accepting the lack of fix, seems like a potentially desirable option.

        Are there other reasons for shared libraries to continue existing?

        1. 14

          Sharing library pages between applications? Preloads (mixed bag)? Less shaking the tree at link-time? Ecosystem stability beyond the syscall level?

          FWIW, Linux is an aberration in how much it makes static. Most systems have a hard requirement on dynamically linking system libraries, and unlike Linux, they either have extreme ABI stability (Windows, Solaris, etc.) or change the syscall ABI and require a rebuild anyways (OpenBSD).

          1. 9

            FWIW, Linux is an aberration in how much it makes static. Most systems have a hard requirement on dynamically linking system libraries, and unlike Linux, they either have extreme ABI stability (Windows, Solaris, etc.) or change the syscall ABI and require a rebuild anyways (OpenBSD).

            Or both. Solaris and Windows change(d) the syscall interface regularly – the stable boundary is in the system libraries.

            1. 5

              This would be a blog post I would love to read!

              1. 1

                I’d love to know how much shared library code is actually shared in RAM in desktop systems, servers, containers, etc. It would seem intuitive that a desktop would have plenty of shared code in some large libraries (e.g. those from Qt and KDE) but I suspect there may be less sharing than we might hope.

                LD_PRELOAD? Is it used for something important? I can imagine it might be but I just haven’t noticed it being used.

                Are you referring to compile time or runtime linking? I seem to remember runtime linking being extremely slow for ‘large’ code under Linux and that meaning we had to put hacks in place to make KDE apps appear to launch faster. It was something that only affected C++ code - not C - and I didn’t know how it could be improved. Would static linking make this worse?

                1. 4

                  It’s pretty easy on a Linux system—just read /proc/<pid>/maps, extract the libraries and count. I just did that on my virtual server (that handles email, web, gopher, etc.). The most commonly used libraries are /lib/ld.so and /lib/tls/libc.so (every process). Out of 118 libraries used, 44 are shared 8 times or less, one 10 times, 3 11 times, and then the rest at 21 reuses or more.

                  Also, I use LD_PRELOAD to intercept certain C functions, but generally only on a development system.

                2. 1

                  Well, talking about windows, it sure has tons of DLLs… but bundled for each program, so there’s almost no deduplication involved. I’d rather directly get static binaries that don’t break so easily (looking at you pacman, you should be fully static).

                3. 3

                  Application launch time, memory overhead, etc are the big ones.

                  But when you say “no shared libraries” where does that end? Every application should have its own complete copy of the windowing and UI libraries? If every application has its own copy of a library that has a security bug, then every application has to be updated.

                  Put aside that means improvements to the OS have no benefits to applications that have already been compiled, and OS UI changes won’t be reflected in your app, the code bloat of essentially having a complete copy of the OS for every app obviously becomes insane.

                  1. 1

                    The occurrence of security fixes in libraries with many consumers is much more frequent than ABI breakages.

                    This says nothing as well as to how difficult it can be to track packages which statically link said libraries (there is no way to easily examine the binaries for linkage - you have to look at the build recipe or do some heuristic check for the presence of a symbol).

                  2. 1

                    First up, disk space isn’t the important bit for shared libraries these days. It’s in memory cost and application launch time.

                    The second issue is common to OS’s - If I have a library with a stable API, and two other libraries communicate with each other with that library, but they each link in their own copy of a library, I need the memory layout of both libraries to match, at which point you’re ABI locked, and may as well just have shared libraries.

                  3. 5

                    The problems with a lack of stable ABI was a big driver in Swift’s ABI stability work - you can’t make system libraries in a safe language if that language’s ABI is unstable. You can’t have multiple system libraries having copies of essentially the same code (e.g. compilation must be separable).

                    If the answer is “make an unsafe wrapper layer” then you’re immediately losing a lot of the benefit of a safe language.

                    1. 3

                      Have there been any notable attempts to create a new language-agnostic ABI? I’m guessing most people reach for a message-passing or RPC library when C gets too limiting but it would be an interesting project.

                      1. 5

                        WebAssembly WASI is kinda that if you squint a bit: https://hacks.mozilla.org/2019/11/announcing-the-bytecode-alliance/

                        1. 2

                          VMS has always had a language-agnostic ABI.

                        2. 2

                          That was really interesting. In all the various arguments I’ve seen for and against C, nobody ever brought up the stable and controllable ABI before.

                          1. 8

                            It’s like the one key benefit over basically everything else.

                            1. 4

                              This is mostly because on Unix, C is the lowest common denominator. Many other platforms define cross-language ABIs or define runtime low-level late binding like COM.

                              1. 2

                                I would be really interested in the slightly-higher/newer abstraction that was alluded to in the blog article.

                                I’m contributing to a new language, and I’m less than motivated to work on some full-blown C FFI to be honest.

                              2. 3

                                Many languages have stable ABIs, it’s an artifact of not-large-scale-system languages that results in unstable ABI - pascal, C, objective-c, C++, Swift, etc have stable ABIs because all of them are expected to be useable for core system libraries.

                                C++ is the only really problematic child as the language makes it super easy to accidentally bollocks up an API exposed binary detail (accidentally reordering vtables) - but if you know to be careful around virtual methods in the same way you are with struct fields then your guaranteed that the same definition will always compile to the same binary interface, across all compilers targeting a given platform.

                                Languages like rust make no such guarantee, so their use as a system language is severely limited.

                                1. 3

                                  I partially agree, but I think that holding up ABI compatibility as such a strong requirement is a severely outdated stance.

                                  I don’t see anything wrong with building software for a specific library/version configuration on-demand, either by package archives, or on users’ machines.

                                  The only reason why this wasn’t possible done in the past is because building C software is a huge mess.

                                  This is a reasonable option with Rust (and other languages), but I think it’s more reasonable to migrate to a slightly higher-level interface description format (as mentioned already) than “whatever fell out of a C compiler 30 years ago”.

                                  1. 1

                                    For an OS - which is where a lot of the critical frameworks that are attacked live - ABI stability is critical.

                                    You can’t mandate that a user updates all their software concurrently with the OS, or N-boot for every version of the OS that each piece of software they use is compiled for.

                                    That’s why Swift being ABI stable was so critical - Apple couldn’t use Swift for system frameworks unless it was stable, and so all the system frameworks are still C, Objective-C, and unfortunately IOKit which is C++ (C++ is deterministically and by spec ABI stable, but it’s super easy to change ABI without realising)