main函数是C程序执行的入口吗?

/ 0评 / 0

       当然不是,我们知道,在C中,我们的可执行程序最后是通过链接后来生成的,而链接过程实际上有大量的汇编好的C库二进制文件参与进来,如ctr1.o、crt2.o等。因此最终的可执行程序中,除了我们编写的C代码以外,还有大量的C库文件参与了最终链接,并包含在最终的可执行文件中。

这个“组装”的过程如何做,是由链接器ld的链接脚本决定的。

链接脚本定义一些基本信息,例如最终生成文件的类型、目标机器类型、一些其他重要信息、以及我们关注的真正的入口_start

我们来看看_start都干了什么

需要明确的是,_start这个函数主要是为程序的运行创建好运行环境,并没要做太多别的事情,在这个函数中__lib_csu_fini__lib_csu_init的函数地址都作为参数传递给了__lib_start_main函数。从这两个入参函数的名字可以推测出其作用分别是处理退出阶段和初始化阶段的函数。main函数之前的所有事情主要便是在__lib_cus_init中做的,那么__lib_cus_init什么时候被调用呢?事实上,在__lib_csu_init__lib_csu_fini传入__lib_start_main之后,接下来会执行generic_start_main,这个函数会做一些初始化C库所需要的环境,例如环境变量、函数栈、多线程环境等,在这些事情结束后,以下代码保证了__lib_csu_init在main函数前调用。

这里的init就是__lib_cus_init,在此之后才会执行用户的main函数


 

关于__lib_csu_init函数的具体执行流:__lib_csu_init--->_init--->__lib_global_ctors

在__libc_global_ctors中会去调一些用户自定义的使用编译器特性的函数,这些函数都会先于main函数之前被执行。这些函数的地址在稍微老一点的gcc版本下是放在.ctors section这个数组中,现在的gcc是将这些函数的地址放在.init_array section中,具体不再深究。

       假如我们想在main函数之前做一些自定义的事情,事实上也就是让编译器把这些指令放在.ctors section(当然新版本是.init_array section)中了,其具体过程再此也不展开了,举个例子

    gcc编译后,其输出结果如下

       

发表评论

电子邮件地址不会被公开。 必填项已用*标注