Sta.li: Static Linux(sta.li) |
Sta.li: Static Linux(sta.li) |
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.
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.
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.
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.
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.
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.)
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.
If the OS has rigid dependency tracking (maybe source distros like Gentoo, or a cryptographically tracked binary distribution like freebsd-update), maybe you can live with that.
So there's some trade off of "dll hell" for binary hell, and perhaps some other security advantages to dynamic libs. IMHO shared libraries are pretty well understood now days and static linking should be avoided unless you have a very good reason.
Even in the unlikely case where binaries are statically linked against different versions of a library. You'd still have to check against which version each binary is compiled.
Of course, you also gain in security, since all kind of library preloading attacks are not possible anymore.
"Also a security issue with dynamically linked libraries are executables with the suid flag. A user can easily run dynamic library code using LD_PRELOAD in conjunction with some trivial program like ping. Using a static executable with the suid flag eliminates this problem completely."
Have the authors actually tried this? Using LD_PRELOAD with suid programs won't work.
> Linking a stripped hello world program with glibc results in 600kb. Linking it with uclibc in about 7kb.
That's nice for uclibc, but we're typically linking dynamically. The comparison should be between dynamically and statically linked binaries. A stripped and dynamically linked hello world results in a 6kb program on my machine (glibc).
There's also a lot of handwaving on memory usage in the FAQ.
I can build busybox (a multi-call all-in-one executable, use symlinks to refer to the binary with the name of a tool and it acts like that tool), with init and bourne shell and the minimal set of command-line tools (coreutils remakes and util-linux remakes) into a 600KiB executable statically linked with uclibc. Combined with a linux kernel, I can boot with it. Meanwhile, my glibc is 2MiB.
Modern computers are really amazing. And it's also amazing that the understandable trend of letting software get bigger and slower as long as it doesn't really cause problems on current hardware has resulted in such astounding (though mostly harmless) waste.
All that said, these stali project pages have existed for years, and there's nothing interesting to show for it. Not that many people really buy into this thing (including me).
As it stands, the FAQ entry is comparing apples and oranges. Comparing full-featured and dynamically linked programs to statically linked, but feature-limited ones is only interesting if you can get by with the feature-limited version. I suspect we're in agreement.
Is that the proportional size (binary size + glibc size / number of things using glibc), or just the size of the binary?
Not sure about "changing code during runtime", but one of the great benefits of dynamic-link libraries are for writing plugins. And I don't think it would take much time for an app to look up its own plugin folder.
As I see it suckless.org community prefers 'linking' in form of shell scripts or communication via pipes, ideally via system's VFS.
You will get lean and minimalistic base system. If something will not share same ideals it will not be in the base system (like glib[c]?, bash, Firefox). It is possible that dynamic linking will be allowed in /emul chroot as stated in 'Filesystem' page.
I see sta.li as rock solid minimalistic base system, which you can use on it's own (how I belive many suckless.org folks will use it) or as a base system, that you can build upon. Even more than that, you will be able to use sta.li components in generic distributions with ease, because of static linking.
Go-lang is in my opinion next step for Bell Labs folks in lean development for the masses. Don't take this too literally ;) Plan 9 [1] was first step, but people did not want whole new system. Inferno [2] was next one, but VM system was too much also. Go allows to use some of Plan 9 features in edible form for the masses. Without requirement to install specific system or VM to run your programs. That to some extent is what makes sta.li's ideals similar to go-lang's.
Development of sta.li is at slow pace, but many experiments are under development [3]. Probably some of them will be included in sta.li. Most probably sta.li will include X11, but we are seeing some developments with Wayland [4].
[1] - http://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs [2] - http://en.wikipedia.org/wiki/Inferno_%28operating_system%29 [3] - https://github.com/henrysher/sinit - http://galos.no-ip.org/sdhcp - http://git.suckless.org/dmc/ [4] - https://github.com/michaelforney/swc
http://www.youtube.com/watch?v=Zu9Qm9bNMUU
I'm not qualified to comment on Stali itself but, more generally, I can't recommend Suckless software highly enough.
Since I switched to Linux a few years back I've found myself using more and more of their programs--DWM, Dmenu, ST, Tabbed, Slock and Surf.
Before, I'd hop from one window manager, terminal or browser to another but, for me, Suckless programs just tend to stick because of the minimal philosophy.
This causes gcc to put each function in a separate section in the resulting object file, and the -gc-sections option makes ld strip the sections that are not reachable by calls from main (basically a tree-shaker).
"Because dwm is customized through editing its source code, it’s pointless to make binary packages of it. This keeps its userbase small and elitist. No novices asking stupid questions. There are some distributions that provide binary packages though."
Over the past 17 or so years I've been using linux full-time, I've experienced 3 or 4 of the "sweet spots", or times where using linux was superior to everything else on the market. GNOME 1.x with Enlightenment 0.15 (vs Win98) was the second one (the first, I'm told, was E DR0.13 with CmdrTaco's task managing app and Hand of God theme vs Win95). I believe we are currently at the end of another sweet spot with KDE 4.x being put out to pasture, as it completely destroys the UX of Windows 7/8 and Mountain Lion.
But don't knock the state of linux circa 1999. Sure, you had to ensure your sound cards had OSS drivers, and Winmodems sucked, but it was a superior experience to Win9x even back then.
Furthermore I suspect the scope of stali will be so narrow that I will never be able to run say a CL implementation on it. Pretty much the same as Plan9, I love the design but it's practically useless for me. :(
Was it worth the effort? Eh. But it was instructive and I'd like to attempt (when I get some time) to try a larger project.
This is a very big assumption.
Dynamic linkers are also clever enough to only mmap the required parts of dynamic library.
This is why I like to re-make my shell and associated tools static binaries — shell scripts run 10-20% faster. (lots of small programs running repeatedly)
True, but I'd expect that to be dwarfed by the I/O time required to load even a single 4k page from disk, vs. keeping one copy of a big dynamic library like glibc loaded for the whole system, with fixups done per-process.
Good points about ASLR and static-linking frequently-exec'd-and-exited processes like the shell; and certainly for embedded and HPC it makes sense. I guess the moral, as always, is to measure.
On one hand, you eliminate one attack vector since you take ldd out of the equation. On the other hand, you depend on packagers who distribute their programs to rebuild and relink them every time a security issue creeps up a library they link with. I'm not sure I like that, and I don't have the free time I had in high school when compiling everything by hand seemed really fucking cool.
as for static linking being leaner, i have been told an entire shared library needs to be loaded if so much as 1 program needs a part of it, but i doubt it. i don't see why shared libraries can't be demand loaded just like executables are. then again, demand loading a shared library would be a more complex task, and i have reservations about complexity just like the suckless community does.
If we add more functionality to the hello world program, the dynamically linked version should increase in size slower than the statically linked.
Totally. Reading the FAQ reminded me of https://xkcd.com/386/
I think the literature surrounding prelink pretty strongly contradicts this assertion. See:
http://people.redhat.com/jakub/prelink/prelink.pdf
When examining memory usage on Linux systems, one of the common measurement metrics is the Proportional Set Size (PSS), which essentially is what I was asking about (but for on-disk size, rather than just in-memory): http://lwn.net/Articles/230975/
There's a lot of work going on in link time optimization at the moment, both in LLVM and GCC. It's not quite ready for prime time, it still takes more than a small change in your Makefile to deploy it (e.g. dealing with linkers etc).
With LLVM toolchain you can compile C code (or other high level code) into LLVM IR, link the IR files together and run that through the optimizer.
You will notice that modern optimizers will want to inline everything if possible and a lot of functions will be missing from the resulting binary. Boundaries of object files are perhaps the biggest obstacle in optimization today.
With the automake-based build system you'd pass "--enable-final" and the buildsystem would cat all the source files together and compile the whole damn thing at once (and really stress-test the kernel and gcc).
With KDE 4 I believe it is -DKDE4_ENABLE_FINAL=TRUE passed to cmake.
It was never quite 100%... sometimes you'd run into things like different source files in a modules declaring the same class name, insufficiently-namespaced header include guards, etc. But it was definitely interesting.
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.
Sorry if I wasn't clear.
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.
Don't get me wrong, there are places I think that static linking is ideal. I wish more distributors of binary only software would statically link, or at least include standalone required dynamic libraries, rather than rely on system dynamic libraries.
I wish them luck in their experiment and hope they can improve static linking, but I suspect they will learn more about why dynamic loading "wastes" so many resources the more they come in contact with real world libraries.
It brings in used libraries, all at once. E.g. if you used sincos() from math.a, and math.a contained 47 other math functions, then you'd get all 48 math functions in your static binary just from using sincos().
Someone correct me if I'm wrong but I believe it's only with good whole program optimization at link time that it's possible to truly prove that a function is unneeded and exclude it (and then re-link if needed to re-resolve symbols to their new address in virtual memory).
You are probably talking about demand paging (which happens on statically linked binaries.