C启动例程需要什么?

时间:2011-01-04 16:26:27

标签: c exec startup main

引用其中一个unix编程书籍,

  

当C程序被执行时   kernelby,exec函数之一   调用特殊start-up routine。这个   函数在main之前调用   函数被调用。可执行文件   程序文件将此例程指定为   该计划的起始地址;   这是由链接编辑器设置的   它由C编译器调用。这个   启动例程从中获取值   内核命令行参数和   环境和设置如此   主函数被称为   如前所示。

为什么我们需要一个中间人start-up routine。 exec函数可以直接调用main函数,内核可以直接将命令行参数和环境传递给main函数。为什么我们需要中间的启动程序?

4 个答案:

答案 0 :(得分:9)

因为C没有“插件”的概念。因此,如果你想使用,malloc()有人必须初始化必要的数据结构。 C程序员很懒,不想一直写这样的代码:

main() {
    initialize_malloc();
    initialize_stdio();
    initialize_...();
    initialize_...();
    initialize_...();
    initialize_...();
    initialize_...();

    ... oh wow, can we start already? ...
}

因此,C编译器会确定需要完成的工作,生成必要的代码并设置所有内容,以便您可以立即开始使用 代码。

答案 1 :(得分:5)

启动例程初始化CRT(即创建CRT堆以使malloc / free工作,初始化标准I / O流等);在C ++的情况下,它还调用全局变量的构造函数。可能还有其他特定于系统的设置,您应该检查运行时库的源代码以获取更多详细信息。

答案 2 :(得分:5)

调用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!

答案 3 :(得分:0)

重要的是要知道应用程序是在用户模式下执行的,任何系统都会调出,设置特权位并进入内核模式。这有助于防止用户访问内核级系统调用以及无数其他复杂情况,从而提高操作系统的安全性。因此,对printf的调用将陷阱,设置内核模式位,执行代码,然后重置为用户模式并返回到您的应用程序。

CRT需要帮助您并允许您在Windows和Linux中使用所需的语言。它为操作系统提供了一些非常基础的引导,为您提供开发功能集。