装载机的角色和C运行时初始化之间的差异 [英] Difference between the roles of loader and C runtime initialization

查看:127
本文介绍了装载机的角色和C运行时初始化之间的差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在读关于此链接中的C运行时初始化的角色:<一href=\"http://www.embecosm.com/appnotes/ean9/html/ch05s02.html\">http://www.embecosm.com/appnotes/ean9/html/ch05s02.html

它说,运行intialization确实喜欢设置栈的任务,并进一步详细页面也说,它初始化用零BSS段。在其他一些地方我也看了,它初始化数据和一些其他部分。

这在我的脑海中创建一个疑问什么加载程序呢?由于其中一些任务也是装载机的责任。

所以,我的问题:


  1. 什么是运行时初始化或C运行时真正做到?

  2. 什么是装载机实际上做?

修改

好了,所以如果该链接描述运行时初始化为专门的嵌入式系统它有正常的系统是什么角色的角色,然后。
至于我在想,那么运行时初始化将只需要调用主并没有其他的工作留给它。


解决方案

  

      
  1. 什么是运行时初始化或C运行时真正做到?

  2.   

维基百科定义了一个运行时库为:


  

一组用于由编译器调用某些运行时环境的行为,通过插入调用运行时库编译成可执行的二进制低级别的例程。


在C程序的情况下,运行时库已经很少自举程序之外的事情。编译器调用C运行时来引导各种环境的东西,然后基本上是通过调用

控制手拿开到用户

鉴于你的问题的意见的答复,你可能已经想通了,通过该程序自举其环境的过程有针对性的环境的数量而变化。鉴于现在和过去用C支持的平台和操作系统的数量,有是枚举,其中C运行时已工作或当前工作的所有方式没有可能的方式。

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


  • 由于C运行时负责调用,它遵循​​通过的atexit(3)将是C运行时的责任。


  • 决心和调用任何构造函数/析构函数接口( _init _fini 等)


  • 初始化并调用实时加载器(它负责解决,并在加载链接时登记,并在运行时加载动态共享对象)。


  • 独立的线程处理出优雅。


  • 初始化和传球 ARGC 的argv 进入该程序的


  • 定义和初始化各种C库的全局符号。例如,它设置错误号正确的环境(现代系统定义错误号来是线程安全的,因此它需要住在TLS)。 ENVIRON 是调用之前,需要在初始化另一次全球性的象征


  • 对于这个问题,C运行时需要设置TLS。


  • 吨以上。


您可能感兴趣的通过的运行,在中南大学发现的glibc的实现(C启动)目录。 (有一些机器特定的部分这个目录之外。)

不同的系统会有不同的要求。当你读过,嵌入式系统可能对运行时显著更多的工作,因为他们可能是负责任务,从寄存器初始化程序加载和执行(其中,这是不以任何内核提供)。 C运行时与仁之间的区别,可以在嵌入式目标变得模糊给予足够复杂的独立项目。

现在


  <醇开始=2>
  
  • 什么是[A]装载机实际上做?

  •   

    有许多类型的装载机,还根据不同的运行时环境。对于使用EEPROM一个小型的嵌入式环境中,装载机可能有些固件启动的不管它找到地址0执行你也认为自己是装载机,手工编写二进制到EEPROM中。

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


    1. 引导程序。从历史上看,这些都在BIOS中挑选一个引导设备,着眼于一个地址,读取512字节的数据到内存中一个方式操作,并开始从那里执行。我已经离开这个世界,现在一段时间,所以我不知道有什么区别与EFI / UEFI以外,他们有足够的更完整的(复杂)引导环境。


    2. 内核。当你执行一个程序,吨的东西是怎么回事引擎盖下得到它去。假设你在某些类Unix操作系统外壳运行程序,加载过程可能会遵循这样的事情:


      • 您的外壳尝试寻找二进制某处在您的环境配置 PATH 。这通过发出一个数字系统调用内核来解决不同的路径顺序下一个文件名进行。

      • 假设找到该文件,外壳通常叉(2)的execve(2)。在叉(2)调用导致内核创建一个新进程;在的execve(2)调用替换为新克隆的二进制文件。

      • 内核从存储介质(磁盘,网络,内存等等)并试图读取文件的第一页找出如何执行它。

        • 如果它是一个ELF二进制文件,则可以确定从二进制的头。然后,内核加载的二进制文件的部分到内存中的某个地方,基于ELF节头指定偏移,设置用于堆栈和诸如此类的东西映射区域,然后开始执行基于入口地址(也ELF头的一部分)。此入口点可能是 _start ,C运行时的一部分。

        • 如果它不是一个ELF程序,它仍然可以通过跨preTER可执行文件。内核将试图解析从文件开始的相互preTER(例如#!/斌/庆典),解决它,并执行它。它最终会发现一个ELF可执行文件或将失败。


      • 内核开始执行二进制文件,可能是在 _start ,如前所述。

      • 利Bendersky具有此,题为如何静态链接程序在Linux上运行


    3. 运行时加载程序/动态链接程序会/无论你想打电话给他们。我将把你的Linux的动态库 解剖文章以获取有关如何将这些工作。当然,的dlopen(3) / 则dlsym(3) / dlclose(3) / dlerror获得(3)一套功能只是用于动态加载程序交互的API。我会强烈建议阅读这些接口的手册页来获得被Linux动态加载程序所支持的功能集的一个好主意,什么样的东西加载程序。


    I was reading about the roles of the C runtime initialization from this link: http://www.embecosm.com/appnotes/ean9/html/ch05s02.html

    It says that the runtime intialization does tasks like setting up the stack and in further pages in detail it also says that it initializes the bss segment with zeroes. At some other places I also read that it initializes data and some other segments.

    This created a doubt in my mind about what the loader does then? Because some of these tasks are also the responsibility of the loader.

    So, my questions:

    1. What does the runtime initialization or c runtime actually do?
    2. What does loader actually do?

    EDIT

    Ok so if that link describes the role of runtime initialization for embedded systems specifically, then what role does it have on normal systems. As far as I think, then the runtime initialization will just call main and no other work is left for it.

    解决方案

    1. What does the runtime initialization or c runtime actually do?

    Wikipedia defines a runtime library as:

    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.

    In the case of C programs, the runtime library has very little to do outside of bootstrapping the program. The compiler invokes the C runtime to bootstrap various environmental things and then basically hands off control to the user by calling main.

    Given the responses in the comments of your question, you may have already figured out that the process by which a program is bootstrapped for its environment varies with the number of targeted environments. Given the number of platforms and operating systems supported by C now and in the past, there is no possible way to enumerate all the ways in which the C runtime has worked or currently works.

    Every C library has its own C runtime and every environment supporting C will likely have different bootstrap problems and requirements. These requirements depend largely on features of the operating system or hardware combined with the completeness of the C implementation. However, I can answer some things that C runtimes typically do in environments with which you may be familiar.

    • Since the C runtime is responsible for calling main, it follows that calling functions registered through atexit(3) would be the responsibility of the C runtime.

    • Resolve and call any constructor / destructor interfaces (_init, _fini, etc.)

    • Initialize and call the real-time loader (which is responsible for resolving and loading dynamic shared objects registered at link-time and loaded at runtime).

    • Handling exit of detached threads gracefully.

    • Initialization and passing of argc and argv into the program's main.

    • Define and initialize various C library global symbols. For example, it sets errno properly for the environment (modern systems define errno to be thread-safe, so it needs to live in TLS). environ is another global symbol that needs initialization prior to calling main.

    • For that matter, the C runtime needs to set up TLS.

    • Tons more.

    You may be interested in looking through the glibc implementation of the runtime, found in the "csu" (C start-up) directory. (There are some machine-specific portions outside of this directory.)

    Different systems will have different requirements. As you've read, an embedded system may have significantly more work for the runtime because they may be responsible for tasks ranging from register initialization to program loading and execution (where this is not provided by any kernel). The distinction between "C runtime" and "kernel" can become blurry given sufficiently complex standalone projects on embedded targets.

    Now:

    1. What does [a] loader actually do?

    There are many types of loaders, also depending on the runtime environment. For a small embedded environment with an EEPROM, the loader may be some firmware that starts execution of whatever it finds at address 0. You might also think of yourself as the loader, manually writing your binary out to the EEPROM.

    In modern operating systems, there are a number of loaders.

    1. Bootloaders. Historically, these have operated in a fashion where the BIOS picks a boot device, looks at an address, reads 512 bytes of data into memory, and starts executing from there. I've been out of this world for a while now, so I'm not sure what the difference is with EFI/UEFI other than that they are sufficiently more complete (and complicated) bootstrap environments.

    2. Kernels. When you execute a program, tons of stuff is going on under the hood to get it going. Assuming you're running your program from a shell in some Unix-like OS, the loading process may follow something like this:

      • Your shell attempts to look for the binary somewhere in your environment-configured PATH. This is done by issuing a number of syscalls to the kernel to resolve a filename under a different path sequence.
      • Assuming the file is found, the shell will usually fork(2) and execve(2). The fork(2) call causes the kernel to create a new process; the execve(2) call replaces the cloned binary with the new one.
      • The kernel reads the first page of the file from its storage medium (disk, network, memory, whatever) and attempts to figure out how to execute it.
        • If it's an ELF binary, it can determine that from the binary's header. The kernel then loads the sections of the binary into memory somewhere, based on offsets specified in the ELF section headers, sets up mapped regions for stacks and whatnot, then begins executing based on the entry address (also part of the ELF header). This entry point is probably _start, part of the C runtime.
        • If it's not an ELF binary, it could still be executable through an interpreter. The kernel will attempt to parse the interpreter from the start of the file (e.g. #!/bin/bash), resolve it, and execute it. Eventually it will find an ELF executable or it will fail.
      • The kernel begins executing the binary, probably at _start, as mentioned.
      • Eli Bendersky has a more thorough write-up on this, entitled "How statically linked programs run on linux".
    3. Run-time loaders / dynamic linkers / whatever you want to call them. I'll refer you to the "Anatomy of Linux dynamic libraries" article for information about how these work. Of course, the dlopen(3) / dlsym(3) / dlclose(3) / dlerror(3) set of functions are simply an API for interacting with the dynamic loader. I would highly recommend reading the manual pages of these interfaces to get a good idea of the featureset supported by the Linux dynamic loader, and what kinds of things the loader does.

    这篇关于装载机的角色和C运行时初始化之间的差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆