Does _start call my program's main function and other essential setup functions?

Viewed 438

I'm reading a textbook which describes how loader works:

When the loader runs, it copies chunks of the executable object file into the code and data segments. Next, the loader jumps to the program’s entry point, which is always the address of the _start function. The _start function calls the system startup function, __libc_start_main

From the answer of this question What is __libc_start_main and _start? we have the below pseudo-code about the execution flow:

_start:
   call __setup_for_c       ; set up C environment
   call __libc_start_main   ; set up standard library
   call _main               ; call your main
   call __libc_stop_main    ; tear down standard library
   call __teardown_for_c    ; tear down C environment
   jmp  __exit              ; return to OS

My questions are:

  1. I used objdump to check the assembly code of the program and I found _start only call __libc_start_main as picture below shows: enter image description here

What about the rest of functions like call __setup_for_c ,_main etc? especially my program's main function, I can't see how it get called. so is the pseudo-code about the execution flow correct?

  1. What does __libc_start_main setup standard library mean? Why the standard library needs to be setup? Isn't that the standard library just need to be linked by the dynamic linker when the program is loaded?
3 Answers
  1. The other function calls described in the linked answer give a synopsis of what needs to happen; the actual implementation details in the GNU C library are different, either using “constructors” (_dl_start_user), or explicitly in __libc_start_main. __libc_start_main also takes care of calling the user’s main, which is why you don’t see it called in your disassembly — but its address is passed along (see the lea just the callq). __libc_start_main also takes care of the program exit, and never returns; that’s the reason for the hlt just after the callq, which will crash the program if the function returns.

  2. The library needs quite a lot of setup nowadays:

    • some of its own relocation
    • thread-local storage setup
    • pthread setup
    • destructor registration
    • vDSO setup (on Linux)
    • ctype initialisation
    • copying the program name, arguments and environment to various library variables

    etc. See the x86-64-specific sysdeps/x86_64/start.S and the generic csu/libc-start.c, csu/init-first.c, and misc/init-misc.c among others.

Pseudo-code isn't code ;) _libc_start_main() can call the application's main() because the address of main() will have been fixed up by the linker. The order in which the code generated by the compiler does initialization might be interesting, but you shouldn't assume it will be the same from one compiler to another, or even one release to another. It's probably best not to rely on things being done in a particular way if you can avoid it.

As to what needs to be initialized -- standard C libraries like glibc are hugely complex, and a lot of stuff needs to be initialized. To take one example, the memory allocator's block table has to be set up, so that malloc() doesn't start with a random pattern of memory allocation.

what about the rest of functions like call __setup_for_c ,_main etc?

Those are just fancy made-up readable names used in the linked answer to transfer the meaning of that answer better.

how it get called

Your standard library implementation doesn't provide a function named __setup_for_c nor _main, so they don't exists so they don't get called. Every implementation may choose different names for the functions.

is the pseudo-code about the executation flow correct?

Yes - and the word "psuedo-code" you used infers that you are aware that it's not real code.

what does __libc_start_main setup standard library mean?

It means a symbol with the name __libc_start_main. __libc_start_main is a function that initializes all standard library things and runs main in glibc. It initializes libc, pthreads, atexit and finally runs main. glibc is open source, so just look at it.

why standard library needs to be setup?

Because it was written in the way that it depends on it. The simplest is, when you write:

 int var = 42; // variable with static storage duration
 int main() {
     return var == 42;
 }

(Assuming the optimizer doesn't kick in) then the value 42 has to be written into the memory held for var before main is executed. So something has to execute before main and actually write the 42 into the memory of var. This is the simplest case why something has to execute before main. Global variables are used in many places and all of them need to be setup, for example a variable named program_invocation_name in glibc holds the name of the program - so some code needs to actually query the environment or kernel about what is the name of the program and actually store the value (and potentially parse) a string into a global variable (and also remember about free() that string if dynamically allocated on exit). Some code "has to do it" - and that code is in standard library initialization.

There are many more cases - in C++ and other languages there are constructors, there is gcc GNU extension __attribute__((__constructor__)) and .init/.preinit sections - all of them executed before main. And destructors have to execute on exit, but not on _exit - thus atexit stuff is initialized before main and all destructors may be registered with it, depending on implementation.

Environment need to be initialized, potentially stack and some more stuff. And thread local variables need to be allocated only for current thread so that when you pthread_create another thread they don't get copied with non-thread-local variables.

isn't that standard library just need to be linked by the dynamic linker when the program is loaded?

It is - when the program is loaded, the standard library is just linked. The compiler, when generating the program, uses crt code to include some startup code into the program - for example a call to __libc_start_main.

Related