"...huck the whole thing and rewrite it in assembly."
What are the functions in libc that you truly need and use?
How many of those routines are you incapable or unwilling to rewrite yourself?
I have asked myself these questions on many occasions.
The cruft laden operating system I use (which I imagine by many people's standards is "bare bones") is hopelessly dependent on "libc". But I find that the userland programs I truly need can be written using only a minimal subset of the many functions that are compiled into it.
Could I write any of these in assembly and create my own "libasm" to do the syscalls? This is a project I have contemplated many times.
To motivate myself to keep writing more assembly in the age of scripting language du jour madness, I write a small program in assembly language and then write the same program in C and then step through each compiled program (e.g., with ald). Seeing some of the overhead is an effective motivator.
It's sometimes startling how major foundational tools and systems ignore bloat.
For example, I wanted to use C++11's std::array to return fixed-lengths arrays by value on the stack. This was in a minimal API that originally included NO other headers. In MSVC, std::array included a tree of 100 other headers including gems such as istream, exception, new, malloc, and float.
Yes, I'm aware that none of this stuff gets compiled into the binary, but it shows a disregard for lean dependencies that is emblematic of a bigger problem.
From our (STL maintainer) perspective, <array> includes <algorithm> because it needs equal(), <iterator> because it needs reverse_iterator, and <tuple> because it needs to provide get(). Minimal!
But yeah, it drags in a whole tree of headers. Minimizing this is possible, and we've taken steps to do so in the past, but it's a lot of work for possibly minimal benefit - user translation units tend to drag in many STL headers, especially if they're using precompiled headers like they should. We think our time is better spent fixing correctness bugs and implementing features.
I understand. We definitely want C++14 features first :) But it seems like some of the problems would be easy to fix. Like - istream_iterator is defined in <iterator>, so <iterator> needs to include <istream>, which has a huge subtree. Iterators are a much more "leaf" idea than input streams. Why doesn't <istream> include <iterator> instead?
Or, <algorithm> gets most of its subtree via <memory>, which it needs for a few algorithms that use temporary buffers. That one is beyond your control... The standard should add an <algorithm_lightweight> header containing only algorithms that don't need extra memory. Or you could add your own such header to use internally.
Users must be able to include <iterator> by itself, and get istream_iterator.
We do break things up into internal headers, we just haven't done that as much as possible. Come to think of it, equal() is defined in one of our central headers, so we should probably take advantage of that in <array>.
Musl libc has every function in a separate file, so if you statically link you just get what you use, modulo a number of functions that use each other. So building it yourself is not going to be much better.
Just a remark: If you find it confusing to scatter your code over too many small files with only one function each, look up "-ffunction-sections" on the gcc manual.
Both you and tptacek understand what it is I want. Apparently the musl author is on the same page too. Very good.
But note my goal is not to achieve "better" than what someone else has written.
My goal is having more control over the result and to practice assembly language programming. And... to eliminate some of the "overhead" I see.
Big difference between my handwritten assembly and what gcc generates. Regardless of which is "better" one is more succinct.
Perhaps I drifted a bit from the original blog post; I think the author may have just been trying to find a speed increase, rather than chasing after some sort of minimalist aesthetic.
Comments
"...huck the whole thing and rewrite it in assembly."
What are the functions in libc that you truly need and use?
How many of those routines are you incapable or unwilling to rewrite yourself?
I have asked myself these questions on many occasions.
The cruft laden operating system I use (which I imagine by many people's standards is "bare bones") is hopelessly dependent on "libc". But I find that the userland programs I truly need can be written using only a minimal subset of the many functions that are compiled into it.
Could I write any of these in assembly and create my own "libasm" to do the syscalls? This is a project I have contemplated many times.
To motivate myself to keep writing more assembly in the age of scripting language du jour madness, I write a small program in assembly language and then write the same program in C and then step through each compiled program (e.g., with ald). Seeing some of the overhead is an effective motivator.
It's sometimes startling how major foundational tools and systems ignore bloat.
For example, I wanted to use C++11's std::array to return fixed-lengths arrays by value on the stack. This was in a minimal API that originally included NO other headers. In MSVC, std::array included a tree of 100 other headers including gems such as istream, exception, new, malloc, and float.
Yes, I'm aware that none of this stuff gets compiled into the binary, but it shows a disregard for lean dependencies that is emblematic of a bigger problem.
From our (STL maintainer) perspective, <array> includes <algorithm> because it needs equal(), <iterator> because it needs reverse_iterator, and <tuple> because it needs to provide get(). Minimal!
But yeah, it drags in a whole tree of headers. Minimizing this is possible, and we've taken steps to do so in the past, but it's a lot of work for possibly minimal benefit - user translation units tend to drag in many STL headers, especially if they're using precompiled headers like they should. We think our time is better spent fixing correctness bugs and implementing features.
I understand. We definitely want C++14 features first :) But it seems like some of the problems would be easy to fix. Like - istream_iterator is defined in <iterator>, so <iterator> needs to include <istream>, which has a huge subtree. Iterators are a much more "leaf" idea than input streams. Why doesn't <istream> include <iterator> instead?
Or, <algorithm> gets most of its subtree via <memory>, which it needs for a few algorithms that use temporary buffers. That one is beyond your control... The standard should add an <algorithm_lightweight> header containing only algorithms that don't need extra memory. Or you could add your own such header to use internally.
Users must be able to include <iterator> by itself, and get istream_iterator.
We do break things up into internal headers, we just haven't done that as much as possible. Come to think of it, equal() is defined in one of our central headers, so we should probably take advantage of that in <array>.
You for the most part don't need to rewrite anything. You can take the source code for most libc functions and compile them independently.
Musl libc has every function in a separate file, so if you statically link you just get what you use, modulo a number of functions that use each other. So building it yourself is not going to be much better.
Just a remark: If you find it confusing to scatter your code over too many small files with only one function each, look up "-ffunction-sections" on the gcc manual.
Both you and tptacek understand what it is I want. Apparently the musl author is on the same page too. Very good.
But note my goal is not to achieve "better" than what someone else has written.
My goal is having more control over the result and to practice assembly language programming. And... to eliminate some of the "overhead" I see.
Big difference between my handwritten assembly and what gcc generates. Regardless of which is "better" one is more succinct.
Perhaps I drifted a bit from the original blog post; I think the author may have just been trying to find a speed increase, rather than chasing after some sort of minimalist aesthetic.