Hacker News new | ask | show | jobs
by ChuckMcM 4502 days ago
Ah kids, they crack me up!

Lot of fun reading that, I looked around briefly but couldn't find my email archive from Sun, but I was in the kernel group when folks got the idea that "Gee if you shared the text segment of libraries, that would give you more memory for your buffer cache or user pages!" One of the guys in my group re-wrote the linker to scan through and realign text segments so that the maximum number of read-only pages (and thus shareable) could be allocated. And of course code that had static buffers and what not (go look at the 4.1BSD code, they were everywhere). It made my Sun 3/75 which had, wait for it 32 Megabytes of RAM (yes, less than the L2 cache in some machines these days) run quite a bit faster. Took a long time to get right too.

Shared libraries gave you three distinct advantages, one you cut down on the working set size, two you cut down on file load time, and three it became possible to "interpose" on the library and run two versions of the library at the same time for backwards compatibility.

Building a static system might be fun but for a 64 bit system, building one where libraries were fixed in the address space in flash or something might actually be even better.

4 comments

I remember, but these days the parallel to working set size (depending on the app) is fitting things in cache, or at least cache-awareness -- which some people aim for, but is largely an ignored issue. Page thrashing versus cache thrashing.

An issue both back then and today is potentially that dynamic linkage often ends up using an indirection table, unlike static linkage with simple fixups, which then adds at least the cost of an indirection to each function call.

Sometimes that overhead is swamped by other factors, sometimes it's not, but that would be one reason why static linkage can be faster at times.

Dlopen() is certainly a lifesaver sometimes.

Plus you can inline stuff with static linking.
Whole program optimization is really the killer feature for static linking today. It's possible with dynamic linking, but a static compiler can really go to town shedding weight since lots of libraries have common code structures (see every sufficiently complex C library and its own implementations of various data structures).
that one paragraph... if i were you i'd be wishing i could edit that comment! you most certainly do not "cut down on file load time." the linking process is a complex task, especially if it's to be performed with any efficiency. i remember when starting a large dynamically linked executable was a glacial process on linux, far slower than the time necessary to read the entire executable from disk. no sensible system loads the entire executable when it's statically linked.

your claim of running two library versions at the same time is downright hilarious! this is far harder with dynamic linking, where you need to be sure of loading the right library on every launch of the affected programs than it is with static, where the libraries are just built in to the executables.

To be clear, loading data from disk takes milliseconds and re-computing addresses takes nanoseconds. Yes, in less than one tenth the time it takes to read the part of the libraries you have linked into your binary from disk, you can locate and fixup any link references.

This part I don't get "no sensible system loads the entire executable when it's statically linked." If you're a statically linked executable, by definition the entire file is headed into memory, if there was something in the library you didn't use it got edited out in the link step. Now you may mmap the file and fault it in as you go along, but you are going to have the whole thing read.

> To be clear, loading data from disk takes milliseconds and re-computing addresses takes nanoseconds.

I think the literature surrounding prelink pretty strongly contradicts this assertion. See:

http://people.redhat.com/jakub/prelink/prelink.pdf

http://lwn.net/Articles/341305/

http://lwn.net/Articles/341309/

> you most certainly do not "cut down on file load time."

Surely you must be joking eekee.

I know SSDs have made us all forget, but Disks (you know, those spinning piles of rust that most of us still have in computers to permanently store our bits on) are incredibly, painfully slow. Average times for any action on a disk are in milliseconds. That's millions of computational cycles.

I'm sure someone could invent a system where the dynamic linking process is slower than loading a static executable from a disk, but I've yet to find it. I'm also certain that our assumption that dynamic linking is always the way to go will be more and more challenged by the speed of SSDs, which are becoming much closer to RAM in speeds every day. But for today... no way.

>>the linking process is a complex task, especially if it's to be performed with any efficiency.

I'm no kernel hacker, but doesn't that make the GP argument better?

It would be almost like static linking?

If code is compiled against a shared lib which always will be at the same address in virtual memory, a linking setup could be cached. (And redone if there is a new version of the library, of course.)

(I realize that caching this symbol table won't be a totally trivial change.)

>> I'm no kernel hacker, but doesn't that make the GP argument better?

Nope. Dynamic linking is done each time the program is loaded - the kernel calls out to the dynamic linker to open shared libraries, resolve symbols, create jump tables & the like. Static linking is done once (at compile/link time). When you execute a statically compiled library, the kernel just loads the text, data & bss into memory and more or less starts executing main(). Much, much simpler, although you lose the ability to do things like ASLR.

BugBrother however correctly interpreted my suggestion, which is that given a large address space, one could define an address where shared libraries would always appear. Thus your linking information can be fixed in in the executable and the only dynamic part is a check to see if the library is loaded or not. Thus all the link speed benefits of static linking, the load speed benefits of dynamic linking.
My point was that with dynamic libraries at fixed memory addresses, dynamic linking information can be cached (as long as no binaries are updated). That would imply similar efficiency as for static libraries.

Sorry if I wasn't clear.

Isn't that what prelinking[1] does?

[1]: http://en.wikipedia.org/wiki/Prelink

Thanks. He, a bit after I stopped doing "real" work and went scripting. :-) :-(

Sometimes I regret that, but then I think of the repeated reading of the Effective C++ books. Not to mention the writing of C for a week which I could throw together in hours in Lisp or Perl.

furthermore the most dramatic issues arise with C++ vtables, although even that has been addressed with prelinking and a large address space helps a lot.
I think the real advantage to static linking is that it forces developers to fully acknowledge the resources they are using.

Programs using shared libraries allow a degree of avoiding blame. It's difficult to judge the real impact of things, it rests upon assumptions about how much the library is shared, while putting pressure on the library to be serve more masters and to become more generalized increasing overall size.

It's not a simple equation. It would be at least interesting to get data on all-static systems as well as compare static linked memory usage vs shared library on an individual basis.

You still have the same issues about blame with libraries, static linking them won't solve it.
Yeah, but the dev will know at compile time what those problems are.
Plan 9 is statically linked. Suckless has a lot of plan9 fans, which is probably where this project comes from.