Excellent stuff. My couple of notes..<p>1. printf may malloc so don't use it in an out of memory situation. Though I think this problem is vanishingly unlikely these days.<p>2. printf of floats used to require linking to the math library on some platforms (-lm)<p>3. I am pathetically grateful for nice diagnostics you get when you use the wrong % formatter in more recent C compilers. This used to be a <i>rich</i> source of errors and non-portability.
The registers rdi, rsi and rdx are acknowledged in the article but they don't appear in the disassembly:<p><pre><code> 000000000040f9c0 <__libc_write>:
40f9c0: 83 3d c5 bb 2a 00 00 cmpl $0x0,0x2abbc5(%rip) # 6bb58c <__libc_multiple_threads>
40f9c7: 75 14 jne 40f9dd <__write_nocancel+0x14>
000000000040f9c9 <__write_nocancel>:
40f9c9: b8 01 00 00 00 mov $0x1,%eax
40f9ce: 0f 05 syscall
</code></pre>
This is because they are set when the write function is called. The System V AMD64 ABI specifies that rdi, rsi and rdx are used for the 1st, 2nd and 3rd arguments of a function, perfectly matching the Linux system call ABI. The 5th and 6th also match: r8 and r9, respectively. However, the 4th argument doesn't match: system calls use r10 while System V uses rcx. I wish I knew why.
I wish there was a book length guide with this kind of tutorial style writing but haven’t found much. Everything I’ve found on Linux is more like a reference resource
This is a good overview of how it all works. On some systems like AmigaOS, there is no libc at all, for example standard input / output is handled by the dos.library in ROM. compiler-specific implementation is delivered as libc.a, which means that only static linking with libc is possible. UNIX®️ software cannot be compiled at all without modification and without having the 3rd party ixemul.library downloaded from "AmiNet" and installed in the LIBS: assign (which usually resolves to SYS:LIBS, which in turn usually resolves to either DF0:LIBS or DH0:LIBS).
“Linux/GNU” is a new one. Not sure if it’s a typo or a troll, but if the latter, it’s a pretty decent troll if such a thing exists? If it’s a typo, geez dude. You’re going to give RMS an aneurysm.
As far as the formatting part is concerned, if you just want to look at an implementation, FreeBSD's is extremely nice and readable:<p><a href="https://github.com/lattera/freebsd/blob/master/lib/libc/stdio/vfprintf.c" rel="nofollow">https://github.com/lattera/freebsd/blob/master/lib/libc/stdi...</a><p>For FRRouting, we decided we want to use Linux kernel style extensions (like "%pI4"), so to get this in a portable way we imported FreeBSD's printf into our code. Since printf() isn't exactly "hot" code getting changed a lot, we considered the maintenance / duplication cost acceptable.<p>You can see the result here:<p><a href="https://github.com/FRRouting/frr/tree/master/lib/printf" rel="nofollow">https://github.com/FRRouting/frr/tree/master/lib/printf</a><p><a href="http://docs.frrouting.org/projects/dev-guide/en/latest/logging.html" rel="nofollow">http://docs.frrouting.org/projects/dev-guide/en/latest/loggi...</a><p>stdio support is completely gone in our copy, WCHAR_SUPPORT is disabled at compile time, locale support is stubbed out/hardcoded to C locale. None of these matter to us. As a result, we can use this printf even in the SEGV handler. (That's only a bonus though, the main reason was extensibility on the format specifiers.)
Discussed at the time: <a href="https://news.ycombinator.com/item?id=17114919" rel="nofollow">https://news.ycombinator.com/item?id=17114919</a>