nit*_*ian 4 c program-entry-point startup exec
引用其中一个unix编程书籍,
当kernelby执行C程序时,其中一个exec函数调用special
start-up routine.在调用main函数之前调用此函数.可执行程序文件将此例程指定为程序的起始地址; 这是由C编译器调用时由链接编辑器设置的.这个启动例程从内核中获取命令行参数和环境的值,然后进行设置,以便调用main函数,如前所示.
为什么我们需要一个中间人start-up routine.exec函数可以直接调用main函数,内核可以直接将命令行参数和环境传递给main函数.为什么我们需要两者之间的启动程序?
Aar*_*lla 10
因为C没有"插件"的概念.因此,如果您想使用,那么,malloc()某人必须初始化必要的数据结构.C程序员很懒,不想一直写这样的代码:
main() {
initialize_malloc();
initialize_stdio();
initialize_...();
initialize_...();
initialize_...();
initialize_...();
initialize_...();
... oh wow, can we start already? ...
}
Run Code Online (Sandbox Code Playgroud)
所以,C编译器计算出需要的东西做的,生成所需的代码,并设置了一切,所以你可以开始你的代码的时候了.
启动例程初始化CRT(即创建CRT堆以便malloc/ free工作,初始化标准I/O流等); 在C++的情况下,它还调用全局变量的构造函数.可能还有其他特定于系统的设置,您应该检查运行时库的源代码以获取更多详细信息.
调用main()是C事物,而调用_start()是内核事物,由二进制格式头中的入口点指示。(为清楚起见:内核不希望或不需要知道我们称之为_start)
如果您使用非C二进制文件,则可能没有main()功能,甚至可能根本没有“功能”的概念。
所以实际的问题是:为什么编译器不给出main()起始地址?这是因为典型的libc实现要在真正启动程序之前进行一些初始化,请参见其他答案。
以编辑为例,您可以像这样更改入口点:
$ cat entrypoint.c
int blabla() { printf("Yes it works!\n"); exit(0); }
int main() { printf("not called\n"); }
$ gcc entrypoint.c -e blabla
$ ./a.out
Yes it works!
Run Code Online (Sandbox Code Playgroud)