You are on page 1of 21

Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.

html

1 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

2 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

3 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

$uname -a
Linux localhost.localdomain 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 20
17 x86_64 x86_64 x86_64 GNU/Linux

$gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ldd --version
ldd (GNU libc) 2.17
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

4 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

#include <stdio.h>

printf(control, arg1, arg2, ...); # K&R (1st ed.)

int printf(const char *format, ...); # ANSI C (1989)

5 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

int printf(const char * restrict format, ...); # Latest ISO C (2011)

$ cat printf0.c $ cat printf1.c


#include <stdio.h> #include <stdio.h>

int main(int argc, char **argv) int main(int argc, char **argv)
{ {
printf("Hello World\n"); printf("Hello World %d\n",1);
return 0; return 0;
} }

6 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

$ gcc printf0.c -c -o printf0.o $ gcc printf1.c -c -o printf1.o


$ nm printf0.o $ nm printf1.o
0000000000000000 T main 0000000000000000 T main
U puts U printf

$ gcc printf0.c -o printf0 # Trivial printf dynamic linking


$ gcc printf1.c -o printf1 # Better printf dynamic linking
$ gcc printf0.c -o printf0_s -static # Trivial printf static linking
$ gcc printf1.c -o printf1_s -static # Better printf static linking

7 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

$ ls -l printf1*
total 1696
-rwxrwxr-x. 1 maiz maiz 8520 Mar 31 13:38 printf1 # Dynamic
-rw-rw-r--. 1 maiz maiz 101 Mar 31 12:57 printf1.c
-rw-rw-r--. 1 maiz maiz 1520 Mar 31 13:37 printf1.o
-rwxrwxr-x. 1 maiz maiz 844000 Mar 31 13:40 printf1_s # Static

$ nm printf1.o | wc -l
2 # Object file symbol count (main, printf)
$ nm printf1 | wc -l
34 # Dynamic-linked binary symbol count
$ nm printf1_s | wc -l
1873 # Static-linked binary symbol count

strace

8 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

$ strace ./printf1
execve("./printf1", ["./printf1"], [/* 47 vars */]) = 0
brk(NULL) = 0x1dde000
mmap(NULL, 4096, ..., -1, 0) = 0x7f59bce82000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=83694, ...}) = 0
mmap(NULL, 83694, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f59bce6d000
close(3) = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2127336, ...}) = 0
mmap(NULL, 3940800, ..., 3, 0) = 0x7f59bc89f000
mprotect(0x7f59bca57000, 2097152, PROT_NONE) = 0
mmap(0x7f59bcc57000, 24576, ..., 3, 0x1b8000) = 0x7f59bcc57000
mmap(0x7f59bcc5d000, 16832, ..., -1, 0) = 0x7f59bcc5d000
close(3) = 0
mmap(NULL, 4096, ..., -1, 0) = 0x7f59bce6c000
mmap(NULL, 8192, ..., -1, 0) = 0x7f59bce6a000
arch_prctl(ARCH_SET_FS, 0x7f59bce6a740) = 0
mprotect(0x7f59bcc57000, 16384, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ) = 0
mprotect(0x7f59bce83000, 4096, PROT_READ) = 0
munmap(0x7f59bce6d000, 83694) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, ..., -1, 0) = 0x7f59bce81000
write(1, "Hello World 1\n", 14Hello World 1) = 14
exit_group(0) = ?
+++ exited with 0 +++

brk fstat

9 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

$ cat /proc/3177/maps
00400000-00401000 r-xp 00000000 ./printf1
00600000-00601000 r--p 00000000 ./printf1
00601000-00602000 rw-p 00001000 ./printf1
7f59bc89f000-7f59bca57000 r-xp 00000000 /usr/lib64/libc-2.17.so
7f59bca57000-7f59bcc57000 ---p 001b8000 /usr/lib64/libc-2.17.so
7f59bcc57000-7f59bcc5b000 r--p 001b8000 /usr/lib64/libc-2.17.so
7f59bcc5b000-7f59bcc5d000 rw-p 001bc000 /usr/lib64/libc-2.17.so
7f59bcc5d000-7f59bcc62000 rw-p 00000000
7f59bcc62000-7f59bcc83000 r-xp 00000000 /usr/lib64/ld-2.17.so
7f59bce6a000-7f59bce6d000 rw-p 00000000
7f59bce81000-7f59bce83000 rw-p 00000000
7f59bce83000-7f59bce84000 r--p 00021000 /usr/lib64/ld-2.17.so
7f59bce84000-7f59bce85000 rw-p 00022000 /usr/lib64/ld-2.17.so
7f59bce85000-7f59bce86000 rw-p 00000000
7fff89031000-7fff89052000 rw-p 00000000 [stack]
7fff8914e000-7fff89150000 r-xp 00000000 [vdso]
ffffffffff600000-ffffffffff601000 r-xp [vsyscall]

$ strace ./printf1_s
execve("./printf1_s", ["./printf1_s"],[/*47 vars*/]) = 0
uname({sysname="Linux", nodename="...", ...}) = 0
brk(NULL) = 0x1d4a000
brk(0x1d4b1c0) = 0x1d4b1c0
arch_prctl(ARCH_SET_FS, 0x1d4a880) = 0
brk(0x1d6c1c0) = 0x1d6c1c0
brk(0x1d6d000) = 0x1d6d000
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, ..., -1, 0) = 0x7faad3151000
write(1, "Hello World 1\n", 14Hello World 1) = 14
exit_group(0) = ?
+++ exited with 0 +++

fstat mmap write

10 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

$ cat /proc/3237/printf1_s
00400000-004b8000 r-xp 00000000 ./printf1_s
006b7000-006ba000 rw-p 000b7000 ./printf1_s
006ba000-006df000 rw-p 00000000 [heap]
7ffff7ffc000-7ffff7ffd000 rw-p 00000000
7ffff7ffd000-7ffff7fff000 r-xp 00000000 [vdso]
7ffffffde000-7ffffffff000 rw-p 00000000 [stack]
ffffffffff600000-ffffffffff601000 r-xp [vsyscall]

11 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

printf() execution sequence ...printf execution continued

$ gdb ./printf1_s 0x423d02 in _IO_new_file_xsputn ()


... 0x41475e in vfprintf ()
main at printf1.c:5 0x414360 in _itoa_word ()
5 printf("Hello World %d\n", 1); 0x4152bb in vfprintf ()
0x400e02 5 printf("Hello World %d\n", 1);0x423c10 in _IO_new_file_xsputn ()
0x401d30 in printf () 0x40b840 in mempcpy ()
0x414600 in vfprintf () 0x423c6d in _IO_new_file_xsputn ()
0x40c110 in strchrnul () 0x41501f in vfprintf ()
0x414692 in vfprintf () 0x40c110 in strchrnul ()
0x423c10 in _IO_new_file_xsputn () 0x414d1e in vfprintf ()
0x424ba0 in _IO_new_file_overflow () 0x423c10 in _IO_new_file_xsputn ()
0x425ce0 in _IO_doallocbuf () 0x40b840 in mempcpy ()
0x4614f0 in _IO_file_doallocate () 0x423c6d in _IO_new_file_xsputn ()
0x4235d0 in _IO_file_stat () 0x424ba0 in _IO_new_file_overflow ()
0x40f8b0 in _fxstat () 0x4243c0 in _IO_new_do_write ()
### fstat syscall 0x4235e0 in _IO_new_file_write ()
0x461515 in _IO_file_doallocate () 0x40f9c7 in write ()
0x410690 in mmap64 () 0x40f9c9 in __write_nocancel ()
### mmap syscall ### write syscall happens here
0x46155e in _IO_file_doallocate () 0x423623 in _IO_new_file_write ()
0x425c70 in _IO_setb () 0x42443c in _IO_new_do_write ()
0x461578 in _IO_file_doallocate () 0x423cc1 in _IO_new_file_xsputn ()
0x425d15 in _IO_doallocbuf () 0x414d3b in vfprintf ()
0x424d38 in _IO_new_file_overflow () 0x408450 in free ()
0x4243c0 in _IO_new_do_write () 0x41478b in vfprintf ()
0x423cc1 in _IO_new_file_xsputn () 0x408450 in free ()
0x425dc0 in _IO_default_xsputn () 0x414793 in vfprintf ()
...cut 11 repeats of last 2 functions... 0x401dc6 in printf ()
0x425e7c in _IO_default_xsputn () main at printf1.c:6

12 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

_IO_*

_fxstat

Hello World %d\n

'Hello World '


%d
\n

13 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

0x400e02 5 printf("Hello World %d\n", 1);


0x401d30 in printf ()
0x414600 in vfprintf ()
0x40c110 in strchrnul () # string scanning
0x414692 in vfprintf ()
0x423c10 in _IO_new_file_xsputn () # buffering 'Hello World '
...
0x41475e in vfprintf ()
0x414360 in _itoa_word () # converting integer
0x4152bb in vfprintf ()
0x423c10 in _IO_new_file_xsputn () # buffering '1'
...
0x41501f in vfprintf ()
0x40c110 in strchrnul () # string scanning
0x414d1e in vfprintf ()
0x423c10 in _IO_new_file_xsputn () # buffering '\n'
...

from glibc/stdio-common/printf-parse.h:

/* Find the next spec in FORMAT, or the end of the string. Returns
a pointer into FORMAT, to a '%' or a '\0'. */
__extern_always_inline const unsigned char *
__find_specmb (const unsigned char *format)
{
return (const unsigned char *) __strchrnul ((const char *) format, '%');
}

in vfprintf:
0x414668 <+104>: mov esi,0x25 # Setting ESI to the '%' symbol
0x41466d <+109>: mov rdi,r12 # Pointing RDI to the format string
...saving arguments...
0x41468d <+141>: call 0x40c110 <strchrnul> # Search for next % or end

in strchrnul:
0x40c110 <+0>: movd xmm1,esi # Loading up an SSE register with '%'
0x40c114 <+4>: mov rcx,rdi # Moving the format string pointer
0x40c117 <+7>: punpcklbw xmm1,xmm1 # Vector-izing '%' for a fast compare
...eventual return of a pointer to the next token...

14 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

ssize_t write(int fildes, const void *buf, size_t nbyte);

0x4235e0 in _IO_new_file_write () # libio/fileops.c


0x40f9c7 in write () # sysdeps/unix/sysv/linux/write.c
0x40f9c9 in __write_nocancel () # various macros in libc and linux
### write syscall happens here

15 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

$ nm printf1_s | grep write


6b8b20 D _dl_load_write_lock
41f070 W fwrite
400575 t _i18n_number_rewrite
40077f t _i18n_number_rewrite
427020 T _IO_default_write
4243c0 W _IO_do_write
4235e0 W _IO_file_write
41f070 T _IO_fwrite
4243c0 T _IO_new_do_write
4235e0 T _IO_new_file_write
421c30 T _IO_wdo_write
40f9c0 T __libc_write ## Real write in symbol table
43b220 T __libc_writev
40f9c0 W write ## Same address -- weak symbol
40f9c0 W __write ## Same address -- weak symbol
40f9c9 T __write_nocancel
43b220 W writev
43b220 T __writev

000000000040f9c0 <__libc_write>:
40f9c0: 83 3d c5 bb 2a 00 00 cmpl $0x0,0x2abbc5(%rip) # 6bb58c <__libc_mult
iple_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
...cut...

16 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

#!/bin/sh
echo function_graph > /sys/kernel/debug/tracing/current_tracer
echo 1 > /sys/kernel/debug/tracing/tracing_on
./printf1_s
echo 0 > /sys/kernel/debug/tracing/tracing_on
cat /sys/kernel/debug/tracing/trace > output

7) | SyS_write() {
7) | vfs_write() {
7) | tty_write() {
7) 0.053 us | tty_paranoia_check();
7) | n_tty_write() {
7) 0.091 us | process_echoes();
7) | add_wait_queue()
7) 0.026 us | tty_hung_up_p();
7) | tty_write_room()
7) | pty_write() {
7) | tty_insert_flip_string_fixed_flag()
7) | tty_flip_buffer_push() {
7) | queue_work_on()
7)+10.288 us | } /* tty_flip_buffer_push */
7) | tty_wakeup()
7)+14.687 us | } /* pty_write */
7)+57.252 us | } /* n_tty_write */
7)+61.647 us | } /* tty_write */
7)+64.106 us | } /* vfs_write */
7)+64.611 us | } /* SyS_write */

17 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

$ ./printf1_s
Hello World 1
^Z
[1]+ Stopped ./printf1_s
$ top -o TTY

$ ls -l /dev/pts/0
crw--w----. 1 maizure tty 136, 0 Apr 1 09:55 /dev/pts/0

include/uapi/linux/major.h

...
#define UNIX98_PTY_MASTER_MAJOR 128
#define UNIX98_PTY_MAJOR_COUNT 8
#define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT)
...

18 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

...cut from earlier


7) | pty_write() {
7) | tty_insert_flip_string_fixed_flag()
7) | tty_flip_buffer_push() {
7) | queue_work_on()
7)+10.288 us | }
7) | tty_wakeup()
7)+14.687 us | } /* pty_write */
...

struct tty_struct *tty

tty_insert_flip_string_fixed_flag()
(https://elixir.bootlin.com/linux/v3.10/source/drivers/tty/tty_buffer.c#L256)

memcpy(tb->char_buf_ptr + tb->used, chars, space);


memset(tb->flag_buf_ptr + tb->used, flag, space);
tb->used += space;
copied += space;
chars += space;

if (port->low_latency)
flush_to_ldisc(&buf->work);
else
schedule_work(&buf->work);

19 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

tty_wakeup()

$ ./printf1_s
Hello World 1

20 de 21 06/04/2021 0:05
Tearing apart printf() – MaiZure's Projects http://www.maizure.org/projects/printf/index.html

$cat gdbcmds
start
stepi
stepi
stepi
stepi
...about 1000 more stepi...

$gdb printf1_s -x gdbcmds > printf1_s_dump

21 de 21 06/04/2021 0:05

You might also like