fio supports a whole bunch of io engines - all supported engines are present here : https://github.com/axboe/fio/tree/master/engines
I have been trying to understand the internals of how fio works and got stuck on how fio loads all the io engines.
For example I see every engine has a method to register and unregister itself, for example sync.c registers and unregisters using the following methods
fio_syncio_register
: https://github.com/axboe/fio/blob/master/engines/sync.c#L448
and fio_syncio_unregister
:
https://github.com/axboe/fio/blob/master/engines/sync.c#L461
My question is who calls these methods ?
To find answer I tried running fio under gdb - placed a break point in fio_syncio_register and in the main function, fio_syncio_register gets called even before main which tells me it has something to do with __libc_csu_init
and backtrace confirmed that
(gdb) bt
#0 fio_syncio_register () at engines/sync.c:450
#1 0x000000000047fb9d in __libc_csu_init ()
#2 0x00007ffff6ee27bf in __libc_start_main (main=0x40cd90 <main>, argc=2, argv=0x7fffffffe608, init=0x47fb50 <__libc_csu_init>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe5f8)
at ../csu/libc-start.c:247
#3 0x000000000040ce79 in _start ()
I spent sometime reading about __libc_csu_init
and __libc_csu_fini
and every single description talks about methods being decorated with __attribute__((constructor))
will be called before main, but in the case of fio sync.c I dont see fio_syncio_register decorated with __attribute__
Can someone please help me out in understanding how this flow works ? Are there other materials I should be reading to understand this ?
Thanks
Interesting question. I couldn't figure out the answer looking at the source, so here are the steps I took:
This tells us that global initializers are present in this object. These are called at program startup. What are they?
Interesting. There is apparently a special
.text.startup
section. What's in it?Why, it's exactly the function we are looking for. But how did it end up in this special section? To answer that, we can look at preprocessed source (in retrospect, I should have started with that).
How could we get it? The command line to compile
sync.o
is hidden. Looking inMakefile
, we can unhide the command line withQUIET_CC=''
.Now we know the command line, and can produce preprocessed file:
Looking in
/tmp/sync.i
, we see:Hmm, it is
__attribute__((constructor))
after all. But how did it get there? Aha! I missed thefio_init
on this line:What does
fio_init
stand for? Again in/tmp/sync.i
:So that is how it works.