Live data from Hacker News

Dynamic linking

drewdevault.com

21–30 of 249 posts

Re: Dynamic linking

#21
I think a more interesting analysis of "security vulnerability costs for static linking" would look not at just "how many bytes does the end user download" but "what are the overall costs to the distro to support a fully statically linked setup", looking at eg CPU costs of doing the rebuild or how much total-elapsed-time it would take to do a full rebuild of every affected package.

Re: Dynamic linking

#22

Earlier quoted context omitted.

Run htop or similar, sort by "shared memory" column and see how much more memory you'd need per process if shared linking did not exist. I think the author's using a wrong method to make a point. Dynamic linking feels out of place for most long-running server-side apps (typical SaaS workload). One can argue that in a mostly CLI-environment there's also not much benefit. But even an empty Ubuntu desktop runs ~400 proc…

Go executables are statically linked. It makes deployment a breeze. I think you overestimate how much saving you get from dynamically linking libc. Each executable uses only a small portion of libc, so the average savings is going to be in the handful of kilobytes per executable.

True, but a couple github imports and 10 lines of code generates a 100mb binary. But, to be fair, I guess we're okay with shipping huge binaries now a days because we're literally shipping whole environments with docker anyway.

Re: Dynamic linking

#23
By far the most important reason for dynamic linking for C is semantics: static linking semantics are stuck in 1978 and suck (more on that below), while dynamic linking semantics make C a much better language.

In particular, static linking for C has two serious problems:

1. symbol collisions -> accidental interposition (and crashes);

2. you have to flatten the dependency tree into a topological sort at the final link-edit.

Both of these are related, and they are disastrous. They are also related to the lack of namespaces in C.

Besides fixing these issues, the C dynamic linking universe also enables things like:

- run-time code injection via LD_PRELOAD and intended interposition

- run-time code loading/injection via dlopen(3)

- audit (sotruss)

- reflection

- filters (which allow one to move parts of libraries contents to other libraries without forcing re-links and without forcing built systems to change to add new -lfoo arguments to link-edits)

- use of dladdr(3) to find an object's install location, and then that to find related assets' install locations relative to the first, which then yields code that can be relocated at deploy time (sure, "don't do that" is a great answer, but if you statically-link then you think you can, and now you just can't have assets to load at run-time)

- use of weak symbols to detect whether a process has some library loaded

and others.

C with those features is a far superior language -- a different language, really -- to C without them.

(EDIT: A lot of the semantics of ELF could be brought to static linking. Static link archives could have a .o that has metadata like depedencies, "rpaths", exported/protected symbols, interposer symbols, etc. The link-editor would write and consume that metadata. However, it's 2020, and the static link ecosystem is stuck in 1980 because no one has bothered, and no one has bothered because dynamic linking is pretty awesome. Still, it could be done, and once in a while I think I ought to do it to help save people from themselves who want static linking.)

> Do your installed programs share dynamic libraries?

> Findings: not really

> Over half of your libraries are used by fewer than 0.1% of your executables.

The C library most certainly gets shared, as well as libm and such. The rest, it's true, not so much, but it does depend on what you're measuring. Are you measuring C++ apps? Yeah, C++ monomorphization leads to essentially static linking. Are you measuring Java apps with no significant JNI usage? You won't find much outside the libraries the JVM uses.

> Is loading dynamically linked programs faster?

> Findings: definitely not

Dynamically-linked programs will load faster when their dependencies are already loaded in memory, and slower otherwise. The biggest win here is the C library.

> Will security vulnerabilities in libraries that have been statically linked cause large or unmanagable updates?

> Findings: not really

Correct. But, being able to update libc or some such and not have to worry about updating consumers you might not even know about is a very nice feature.

Re: Dynamic linking

#24
I believe the original reasoning for Dynamic Linking wasn't performance gains, but security gains -- someone described the driving story to me as essentially a found vulnerability in a very common library required updating and re-compiling everything on every system, scarring sysadmins globally and permanently; the space saving and performance aspects came up as later "bonuses".

I have little memory of the details of the story, and I'm not 100% sure it's true, but it's a much more satisfying and reasonable argument for dynamic linking than performance/space.

Of course, the more modern solution would probably be a good package manager -- if its trivial to recompile things, and track what needs to be recompiled, then dynamic linking seems to gain little, but bring in a lot of its own headaches (as we know today)

Re: Dynamic linking

#25

Earlier quoted context omitted.

Run htop or similar, sort by "shared memory" column and see how much more memory you'd need per process if shared linking did not exist. I think the author's using a wrong method to make a point. Dynamic linking feels out of place for most long-running server-side apps (typical SaaS workload). One can argue that in a mostly CLI-environment there's also not much benefit. But even an empty Ubuntu desktop runs ~400 proc…

That is an extremely misleading figure. Shared memory is page-aligned entire libraries dropped into RAM. Statically linking would, as the article shows, only use on average about 4% of the symbols available from the libraries, and the majority of this would not end up in RAM with your statically linked binary. And if you used a more selective approach, dynamically linking to no more than perhaps a dozen high-impact l…

> Put the cold hard numbers right in front of someone's face and still the cargo cult wins out.

Come on.

You did not actually measure the figure GP mentioned and which you are disputing. Your methodology and assumption — that 4% external symbol use translates into 4% size used — is a plausible guess, but you haven't supported it with data.

Even if you had measured the figure you're accusing GP of ignoring, the tone of your remark is just aggressively condescending and inappropriate. Tone it down.

To address your other claims:

> Shared memory is page-aligned entire libraries dropped into RAM.

There is a good reason to page- or superpage-align code generally; it burns some virtual memory but reduces TLB overhead and therefore misses / invalidations, which are very costly. You would want to do the same with executable code in a static-linked binary.

> the majority of [the small fraction of static linked library used] would not end up in RAM with your statically linked binary.

Huh? Why do you claim that?

> And if you used a more selective approach, dynamically linking to no more than perhaps a dozen high-impact libraries and statically linking the rest, you'd get a lot of the benefits and few of the drawbacks.

I think that claim is plausible! But it wasn't an option presented on your blog post, nor was it discussed by GP. Prior to that comment, discussion was only around 100% vs 0% dynamic linking.

Re: Dynamic linking

#26

Earlier quoted context omitted.

Run htop or similar, sort by "shared memory" column and see how much more memory you'd need per process if shared linking did not exist. I think the author's using a wrong method to make a point. Dynamic linking feels out of place for most long-running server-side apps (typical SaaS workload). One can argue that in a mostly CLI-environment there's also not much benefit. But even an empty Ubuntu desktop runs ~400 proc…

Go executables are statically linked. It makes deployment a breeze. I think you overestimate how much saving you get from dynamically linking libc. Each executable uses only a small portion of libc, so the average savings is going to be in the handful of kilobytes per executable.

In theory yes. However, in practice static linking with glibc pulls in a lot of dead weight, musl comes to the rescue though:

test.c:

  int main(int argc, char **argv) {
    printf("hello world\n");
    return 0;
  }
Dynamic linking (glibc):

  $ gcc -O2 -Wl,--strip-all test.c
  $ ls -sh a.out
  8.0K a.out
Static linking (glibc):

  $ gcc -O2 --static -Wl,--strip-all test.c
  $ ls -l a.out
  760K a.out
Static linking (musl):

  $ musl-gcc --static -O2 -Wl,--strip-all test.c
  $ ls -sh a.out
  8.0K a.out

Re: Dynamic linking

#27
post #20
post #5

Suckless has a project to get a fully static compiled Linux environment. Unfortunately I don't know how far that have come

I don't think stali has seen any activity in several years. As far as I know, the only completely statically linked Linux distribution that is actively developed is my own project (inspired by stali), oasis: https://github.com/oasislinux/oasis

Do you static-link Linux? :-)

Re: Dynamic linking

#28
Not convinced.

First, this analysis was done on Arch Linux, a source-based distribution. Since you know at compile time what your environment is, I would expect the benefits to be smaller. And of course, this means you're willing to do a lot of recompiles. I'd like to see analysis done on more traditional (& common) binary distros.

Second, the arguments seem a little cherry-picked. "Over half of your libraries are used by fewer than 0.1% of your executables." is cute. But modern systems have a lot of executables, so 0.1% > 1, so that still matters, and what about the other half.

Finally, we're already having serious problems getting containers to upgrade when a security vulnerability is found. Requiring recompilation of all transitive users is not likely to win any update speed contests. If it's completely automated then it would work, but any rocks in the process will leave people endlessly vulnerable. See the Android ecosystem, etc.

Re: Dynamic linking

#29
To get these stats, Drew used 5 different scripts in 5 different languages. Awk, sh, C, go & python. Well, the C program isn't a script it's a test artifact. Drew must subscribe to the "best tool for the job" philosophy rather than the "use what you know" philosophy.

Re: Dynamic linking

#30
post #8

A better way to do this analysis would be to build a Linux distribution with everything statically linked and compare to the normal version with dynamic linking, looking at disk space used, startup time, memory used, and time to launch specific applications both cold and hot.

When during Solaris 10 development the "unified process model" was introduced, and static link archives for all system libraries removed, boot times improved dramatically because all the programs that run at boot time were then dynamically-linked and started faster than their previous statically-linked selves because the C library and such were already loaded. Later of course we had even more dramatic boot time improvements via SMF (the Solaris/Illumos predecessor to Linux's systemd).

That was an apples-to-apples comparison of pre- and post-process model unification performance, and it was a win.

Now, this was back in... I want to say 2003 or 2004 -- before S10 shipped. And it's possible that the same experiment today would not have the same result.

I'm not sure how easy it would be to construct a distro with only dynamically-linked executables (at least for core libraries, like the C library) and then the same distro with only statically-linked executables. The S10 work was done by Roger Faulkner (RIP) and it was a huge change.

Post reply on HN