加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

加载器和C运行时初始化的角色之间的区别

发布时间:2020-12-16 02:58:53 所属栏目:百科 来源:网络整理
导读:我正在阅读关于C运行时初始化的角色从这个链接: http://www.embecosm.com/appnotes/ean9/html/ch05s02.html 它表示运行时初始化执行任务,如设置堆栈,并在更详细的页面还说,它初始化bss段与零.在其他一些地方我也读到它初始化数据和其他一些细分. 这在我的脑
我正在阅读关于C运行时初始化的角色从这个链接: http://www.embecosm.com/appnotes/ean9/html/ch05s02.html

它表示运行时初始化执行任务,如设置堆栈,并在更详细的页面还说,它初始化bss段与零.在其他一些地方我也读到它初始化数据和其他一些细分.

这在我的脑海里怀疑装载机是什么呢?因为这些任务中的一些也是装载机的责任.

所以,我的问题:

>运行时初始化或c运行时实际执行什么?
>装载机实际上是做什么的?

编辑

好的,如果该链接具体描述了嵌入式系统的运行时初始化的角色,那么它对正常系统有什么作用.
据我所知,运行时初始化只会调用main,而没有其他工作.

解决方法

  1. 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程序的情况下,运行时库在引导程序之外几乎没有做任何事情.编译器调用C运行时引导各种环境的东西,然后基本上通过调用main来控制用户.

考虑到您的问题的评论中的回应,您可能已经知道程序针对其环境进行引导的过程随着目标环境的数量而异.鉴于现在和过去C支持的平台和操作系统的数量,没有可能的方法枚举C运行时工作或当前工作的所有方式.

每个C库都有自己的C运行时,并且支持C的每个环境可能会有不同的引导问题和要求.这些要求在很大程度上取决于操作系统或硬件的功能以及C实现的完整性.但是,我可以回答C运行时通常在可能熟悉的环境中做的一些事情.

>由于C运行时负责调用main,因此通过atexit(3)注册的调用函数将是C运行时的责任.
>解析并调用任何构造函数/析构函数接口(_init,_fini等)
>初始化并调用实时加载器(负责解析和加载在链接时注册并在运行时加载的动态共享对象).
>优雅地处理脱线的出口.
>将argc和argv初始化并传递给程序的主要内容.
>定义和初始化各种C库全局符号.例如,它为环境设置错误(现代系统将errno定义为线程安全,因此需要生活在TLS中). environ是在调用main之前需要初始化的另一个全局符号.
>对于这个问题,C运行时需要设置TLS.
>吨多

您可能有兴趣查看在“csu”(C启动)目录中找到的glibc implementation of the runtime. (这个目录以外有一些特定于机器的部分)

不同的系统将有不同的要求.如您所看到的,嵌入式系统可能会对运行时间有更多的工作,因为它们可能负责从寄存器初始化到程序加载和执行(任何内核都不提供)的任务.由于嵌入式目标的独立项目非常复杂,因此“C运行时”和“内核”之间的区别可能会变得模糊.

现在:

  1. What does [a] loader actually do?

有多种类型的装载器,也取决于运行时环境.对于具有EEPROM的小型嵌入式环境,加载程序可能是一些固件,可以开始执行地址0中找到的任何内容.您可能还将自己视为加载程序,手动将二进制文件写入EEPROM.

在现代操作系统中,有一些装载机.

>引导程序.历史上,这些操作的方式是BIOS选择引导设备,查看地址,将512字节的数据读入存储器,并从那里开始执行.我已经离开这个世界一段时间了,所以我不知道EFI / UEFI有什么区别,除了它们是足够完整(复杂)的引导环境.
>内核.当你执行一个程序时,大量的东西正在引导下进行.假设您在某些类Unix操作系统中从shell运行程序,加载过程可能会如下所示:

>您的shell尝试在环境配置的PATH中查找二进制文件.这可以通过向内核发出一些系统调用来解析不同路径序列下的文件名.
>假设找到文件,shell通常会fork(2)和execve(2). fork(2)调用使内核创建一个新进程; execve(2)调用用新的替换替换克隆的二进制文件.
>内核从其存储介质(磁盘,网络,内存,任何)读取文件的第一页,并尝试找出如何执行该文件.

>如果是ELF二进制文件,它可以从二进制文件的头文件中确定.然后,内核将基于ELF部分头部中指定的偏移量将二进制文件的部分加载到内存中,为堆栈设置映射区域,然后根据条目地址(也是ELF头部分)开始执行.这个入口点可能是_start,这是C运行时的一部分.
>如果它不是ELF二进制文件,它仍然可以通过解释器执行.内核将尝试从文件开始解析解释器(例如#!/ bin / bash),解析它并执行它.最终会发现一个ELF可执行文件,否则它将失败.

>内核开始执行二进制,大概在_start,如前所述.
Eli Bendersky对此作了更全面的评论,题目是“How statically linked programs run on linux”.

>运行时加载器/动态链接器/您想要的任何内容.有关这些工作的信息,请参阅“Anatomy of Linux dynamic libraries”文章.当然,dlopen(3)/ dlsym(3)/ dlclose(3)/ dlerror(3)函数集只是一个用于与动态加载器进行交互的API.我强烈建议您阅读这些界面的手册页,以了解Linux动态加载程序支持的功能集,以及加载程序的种类.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读