4 ms·
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
by cryptonector 6y ago
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.
- cryptonector 6y agoIn a containerized world, static linking will generally be faster, unless the OS does page de-duping for text/rodata. So doing the work to make static linking semantics not suck seems likely to be important.
- mforney 6y agoYou bring up some good points here. Here are some of my experiences with these problems when working on oasis (my static linux distro). > 1. symbol collisions -> accidental interposition (and crashes); I've encountered symbol collisions only twice, but both resulted in linker errors due to multiple function definitions. I'm not sure how this could happen accidentally. Maybe you are referring to variables in the common section getting merged into a single symbol? Recent gcc enables -fno-common by default, so those will be caught by the linker as well. > 2. you have to flatten the dependency tree into a topological sort at the final link-edit. Yes, this is pretty annoying. pkg-config can solve this to some degree with its --static option, but that only works if your libraries supply a .pc file (this is often the case, though). I think libtool also can handle transitive dependencies of static libraries, but it tries hard to intercept the -static option before it reaches the compiler so it links everything but libc statically. You can trick it by passing `-static --static`. For oasis, I use a separate approach to linking involving RSP files (i.e. linking with @libfoo.rsp), which really are just lists of other libraries they depend on. > Besides fixing these issues, the C dynamic linking universe also enables things like: > - run-time code injection via LD_PRELOAD and intended interposition Yes, this can be a problem. I wanted to do this recently to test out the new malloc being developed for musl libc, but ended up having to manually integrate it into the musl sources instead of just using LD_PRELOAD. > - run-time code loading/injection via dlopen(3) In particular, this is a big problem for scripting languages that want to use modules written in compiled languages, as well as OpenGL which uses dlopen to load a vendor-specific driver. > 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. But doesn't the dynamic linker still have to do extra work to resolve the relocations in the executable, even when the dependency libraries are already loaded?
- cryptonector 6y ago