I am looking to understand the printf() statement at the assembly level. However most of the assembly programs do something like call an external print function whose dependency is met by some other object file that the linker adds on. I would like to know what is inside that print function in terms of system calls and very basic assembly code. I want a piece of assembly code where the only external calls are the system calls, for printf. I'm thinking of something like a de assembled object file. Where can I get something like that??
I would suggest instead to stay first at the C level, and study the source code of some existing C standard library free software implementation on Linux. Look into the source code of musl-libc or of GNU libc (a.k.a. glibc
). You'll understand that several intermediate (usually internal) functions are useful between printf
and the basic system calls (listed in syscalls(2) ...). Use also strace(1) on a sample C program doing printf
(e.g. the usual hello-world example).
In particular, musl-libc
has a very readable stdio/printf.c implementation, but you'll need to follow several other C functions there before reaching the write(2) syscall. Notice that some buffering is involved. See also setvbuf(3) & fflush(3). Several answers (e.g. this and that one) explain the chain between functions like printf
and system calls (up to kernel code).
I want a piece of assembly code where the only external calls are the system calls, for
printf
If you want exactly that, you might start from musl-libc's stdio/printf.c, add any additional source file from musl-libc till you have no more external undefined symbols, and compile all of them with gcc -flto -O2
and perhaps also -S
, you probably will finish with a significant part of musl-libc in object (or assembly) form (because printf
may call malloc
and many other functions!)... I'm not sure it is worth the pain.
You could also statically link your libc
(e.g. libc.a
). Then the linker will link only the static library members needed by printf
(and any other function you are calling).
To be picky, system calls are not actually external calls (your libc write
function is actually a tiny wrapper around the raw system call). You could make them using SYSENTER
machine instructions (but using vdso(7) is preferable: more portable, and perhaps quicker), and you don't even need a valid stack pointer (on x86_64) to make a system call.
You can write Linux user-level programs without even using the libc
; the bones implementation of Scheme is such a program (and you'll find others).