【问题标题】:What is the need for C startup routine?C启动例程需要什么?
【发布时间】:2011-06-03 12:19:09
【问题描述】:

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

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

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

【问题讨论】:

  • 当然你不需要它,它只是为了方便。
  • 您能告诉我它提供了什么便利吗?

标签: c exec startup main


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      调用main() 是C 事物,而调用_start() 是内核事物,由二进制格式头中的入口点指示。 (为了清楚起见:内核不想或不需要知道我们称之为_start

      如果你有一个非 C 二进制文件,你可能没有 main() 函数,你甚至可能根本没有“函数”的概念。

      所以实际的问题是:为什么编译器不将main() 的地址作为起点?这是因为典型的 libc 实现希望在真正启动程序之前进行一些初始化,请参阅其他答案。

      edit 为例,你可以像这样改变入口点:

      $ 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!
      

      【讨论】:

      • 优秀。我越来越有见识了。非常感谢:)
      • @LinuxPenseur:还可以查看并试用我刚刚添加的示例!如果没有exit(0),它会 SIGSEGV,你能解释一下为什么会发生这种情况吗?
      【解决方案4】:

      同样重要的是,应用程序在用户模式下执行,任何系统调用,设置特权位并进入内核模式。这有助于通过防止用户访问内核级系统调用和无数其他复杂情况来提高操作系统的安全性。因此,对 printf 的调用将捕获、设置内核模式位、执行代码,然后重置为用户模式并返回到您的应用程序。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-09
        • 2011-04-25
        • 1970-01-01
        • 2011-08-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多