0% found this document useful (0 votes)
16 views

Exploring The Main Function

Uploaded by

PannPaadal
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views

Exploring The Main Function

Uploaded by

PannPaadal
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 10

Exploring Main()

Here is a glimpse on how a simple main function is translated in assembly.

#include<stdio.h>
int main()
{
return 0;
}

#include<stdio.h>
int main(int argc, char **argv)
{
return 0;
}

#include<stdio.h>
void main()
{
}

#include<stdio.h>
void main(int argc, char **argv)
{
}

By: Yashwanth Naidu Tikkisetty


Now let’s explore how main is called and where main comes from.

What is that one particular function that needs to be present for a c program to run.
Yes, It’s the main() function.

When you run the program, the start-up code gets executed and then the kernel will call the main
function where you define how it should work.

What does the kernel do when you press enter after the ./a.out ?

Well, below are the series of execution before main is called

From _start the main is called, this operation is seen below:

And these are the operations performed when the process begins and when it ends

By: Yashwanth Naidu Tikkisetty


(Guess what 0x8, %rsp is)

(Started another process hence address change from here, just keep in mind the function names seen
above as you will be seeing in depth about it)

From the readelf –headers ./sample , we see that the entry point is 0x1060

So what do I get after disassembling?


A hell lot of stuff.

In the above you can see the dump of the functions _init and __cxa_finalize@plt

By: Yashwanth Naidu Tikkisetty


Next comes the printf@plt, _start and deregister_tm_clones.

Then register_tm_clones and __do_global_dtors_aux

By: Yashwanth Naidu Tikkisetty


Then the frame_dummy, main and finally the _fini.

That’s a lot of info to check. No worries, we wont be checking everything, as we are going after main.

This is where you can find the answer for the question, what invokes main?
The (__libc_start_main)libc-start.c initializes and invokes the main. The libc-start.c is executed for
statically linked binaries, for dynamically linked, it would be in libc.so and this comes under startup
code. Before this the ELF startup code is run: https://codebrowser.dev/glibc/glibc/csu/init-
first.c.html#__libc_init_first

Invoke main from __libc_start_main :


https://codebrowser.dev/glibc/glibc/sysdeps/nptl/libc_start_call_main.h.html

Perform initialization and invoke main.: https://codebrowser.dev/glibc/glibc/csu/libc-start.c.html#101

By: Yashwanth Naidu Tikkisetty


In line 125 of the above ( Perform initialization and invoke main ), you can find that call_init is defined
where it is initialized for dynamic executables. It finds the main executable, link map and run its init
function.

In line 173, we can see that, for static executables, the mentioned code is run.

By: Yashwanth Naidu Tikkisetty


The function LIBC_START_MAIN

Below is the process of startup by GNU as mentioned in GNU HURD.

GNU HURD is a collection of microkernel servers that are written as a part of the GNU project.

Note: The startup process is different for statically linked programs and dynamically lined programs

Statically-linked program
• The ELF headers points program start at _start.
• _start (sysdeps/mach/hurd/i386/static-start.S) calls _hurd_stack_setup
• _hurd_stack_setup (sysdeps/mach/hurd/i386/init-first.c) calls first_init which
calls __mach_init to initialize enough to run RPCs, then runs
the _hurd_preinit_hook hooks, which initialize global variables of libc.
• _hurd_stack_setup (sysdeps/mach/hurd/i386/init-first.c) calls _hurd_startup.
• _hurd_startup (hurd/hurdstartup.c) gets hurdish information from servers and
calls its main parameter.
• the main parameter was actually doinit (in sysdeps/mach/hurd/i386/init-first.c),
which mangles the stack and calls doinit1 which calls init.
• init sets threadvars, tries to initialize threads (and perhaps switches to the
new stack) and gets to call init1.
• init1 gets the Hurd block, calls _hurd_init on it
• _hurd_init (hurd/hurdinit.c) initializes initial ports, starts the signal thread,
runs the _hurd_subinit hooks (init_dtable hurd/dtable.c notably initializes the FD
table and the _hurd_fd_subinit hooks, which notably checks std*).
• We are back to _start, which jumps to _start1 which is the normal libc startup
which calls __libc_start_main
• __libc_start_main (actually called LIBC_START_MAIN in csu/libc-start.c) initializes
libc, tls, libpthread, atexit
• __libc_start_main calls initialization function given as parameter __libc_csu_init,
• __libc_csu_init (csu/elf-init.c) calls preinit_array_start functions
• __libc_csu_init calls _init
• _init (sysdeps/i386/crti.S) calls PREINIT_FUNCTION, (actually libpthread on
Linux, __gmon_start__ on hurd)
• back to __libc_csu_init calls init_array_start functions
• back to __libc_start_main, it calls calls application's main, then exit.

By: Yashwanth Naidu Tikkisetty


dynamically-linked program
• dl.so ELF headers point its start at _start.
• _start (sysdeps/i386/dl-machine.h) calls _dl_start.
• _dl_start (elf/rtld.c) initializes bootstrap_map, calls _dl_start_final
• _dl_start_final calls _dl_sysdep_start.
• _dl_sysdep_start (sysdeps/mach/hurd/dl-sysdep.c) calls __mach_init to initialize
enough to run RPCs, then calls _hurd_startup.
• _hurd_startup (hurd/hurdstartup.c) gets hurdish information from servers and
calls its main parameter.
• the main parameter was actually go inside _dl_sysdep_start, which calls dl_main.
• dl_main (elf/rtld.c) interprets ld.so parameters, loads the binary and libraries,
calls _dl_allocate_tls_init.
• we are back to go, which branches to _dl_start_user.
• _dl_start_user (./sysdeps/i386/dl-machine.h)
runs RTLD_START_SPECIAL_INIT (sysdeps/mach/hurd/i386/dl-machine.h) which
calls _dl_init_first.
• _dl_init_first (sysdeps/mach/hurd/i386/init-first.c) calls first_init which
calls __mach_init to initialize enough to run RPCs, then runs
the _hurd_preinit_hook hooks, which initialize global variables of libc.
• _dl_init_first calls init.
• init sets threadvars, tries to initialize threads (and perhaps switches to the
new stack) and gets to call init1.
• init1 gets the Hurd block, calls _hurd_init on it
• _hurd_init (hurd/hurdinit.c) initializes initial ports, starts the signal thread,
runs the _hurd_subinit hooks (init_dtable hurd/dtable.c notably initializes the FD
table and the _hurd_fd_subinit hooks, which notably checks std*).
• we are back to _dl_start_user, which calls _dl_init (elf/dl-init.c) which calls
application initializers.
• _dl_start_user jumps to the application's entry point, _start
• _start (sysdeps/i386/start.S) calls __libc_start_main
• __libc_start_main (actually called LIBC_START_MAIN in csu/libc-start.c) initializes
libc, atexit,
• __libc_start_main calls initialization function given as parameter __libc_csu_init,
• __libc_csu_init (csu/elf-init.c) calls _init
• _init (sysdeps/i386/crti.S) calls PREINIT_FUNCTION, (actually libpthread on
Linux, __gmon_start__ on hurd)
• back to __libc_csu_init calls init_array_start functions
• back to __libc_start_main, it calls application's main, then exit

By: Yashwanth Naidu Tikkisetty


A Simple Flow:

By: Yashwanth Naidu Tikkisetty


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

An Article Written by: Yashwanth Naidu Tikkisetty

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

By: Yashwanth Naidu Tikkisetty

You might also like