我正在从以下链接阅读 C 运行时初始化的作用:http://www.embecosm.com/appnotes/ean9/html/ch05s02.html
它说运行时初始化执行诸如设置堆栈之类的任务,并且在更多页面中详细说明它还说它用零初始化 bss 段。在其他一些地方,我还读到它初始化数据和其他一些段。
这让我对加载程序做了什么产生了怀疑?因为其中一些任务也是 loader 的职责。
所以,我的问题:
编辑
好的,如果该链接具体描述了嵌入式系统的运行时初始化的作用,那么它在普通系统上的作用是什么。
就我而言,运行时初始化将只调用 main 并且没有其他工作要做。
最佳答案
- What does the runtime initialization or c runtime actually do?
维基百科定义了一个 runtime library作为:
a set of low-level routines used by a compiler to invoke some of the behaviors of a runtime environment, by inserting calls to the runtime library into compiled executable binary.
对于 C 程序,运行时库除了 bootstrap 之外几乎没有什么可做的。编译器调用 C 运行时来引导各种环境事物,然后基本上通过调用
main
将控制权交给用户。 .鉴于您的问题评论中的回答,您可能已经发现,针对其环境 bootstrap 的过程随目标环境的数量而变化。考虑到 C 现在和过去支持的平台和操作系统的数量,没有办法枚举 C 运行时已经工作或当前工作的所有方式。
每个 C 库都有自己的 C 运行时,每个支持 C 的环境都可能有不同的引导问题和要求。这些要求在很大程度上取决于操作系统或硬件的特性以及 C 实现的完整性。但是,我可以回答一些您可能熟悉的环境中 C 运行时通常会做的事情。
main
,因此调用通过 atexit(3)
注册的函数将是 C 运行时的责任。 _init
、 _fini
等)argc
的初始化和传递和 argv
进入程序的main
. errno
适合环境(现代系统将 errno
定义为线程安全的,因此它需要存在于 TLS 中)。 environ
是另一个需要在调用 main
之前初始化的全局符号. 您可能有兴趣浏览 glibc implementation of the runtime ,在“csu”(C 启动)目录中找到。 (此目录之外有一些特定于机器的部分。)
不同的系统会有不同的要求。正如您所读到的,嵌入式系统可能有更多的运行时工作,因为它们可能负责从寄存器初始化到程序加载和执行的任务(这不是由任何内核提供的)。考虑到嵌入式目标上足够复杂的独立项目,“C 运行时”和“内核”之间的区别可能会变得模糊。
现在:
- What does [a] loader actually do?
加载器有很多种,也取决于运行时环境。对于带有 EEPROM 的小型嵌入式环境,加载程序可能是一些固件,它开始执行它在地址 0 找到的任何内容。您也可以将自己视为加载程序,手动将二进制文件写入 EEPROM。
在现代操作系统中,有许多加载程序。
PATH
.这是通过向内核发出多个系统调用以解析不同路径序列下的文件名来完成的。 fork(2)
和 execve(2)
. fork(2)
调用使内核创建一个新进程; execve(2)
call 用新的二进制文件替换克隆的二进制文件。 _start
,C 运行时的一部分。 #!/bin/bash
)解析解释器,解析它并执行它。最终它会找到一个 ELF 可执行文件,否则它将失败。 _start
, 如前所述。 dlopen(3)
/dlsym(3)
/dlclose(3)
/dlerror(3)
一组函数只是一个用于与动态加载器交互的 API。我强烈建议阅读这些接口(interface)的手册页,以很好地了解 Linux 动态加载器支持的功能集,以及加载器的功能。 关于c - loader 和 C 运行时初始化的作用区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27596818/