c++ - Linux ELF 32位加载

标签 c++ linux compiler-construction interpreter elf

我正在写一个x86二进制解释器。

目前,我正在处理加载可执行文件和共享对象。但是我仍然有些疑问:

1)动态链接程序/装载程序是否将主要可执行文件和共享库的.ini节串联在一起,从而仅为过程镜像生成一个.ini节?对于.fini部分?

2)它是否将多个符号和字符串表连接在一起?

3)我对搬迁一无所知。它们是在加载二进制文件时还是在调用过程时发生的?我想我不了解动态链接器/加载器如何管理重定位。

4)为什么存在.hash和.gnu.hash节?为什么我需要“哈希”符号?

欢迎链接,评论和先前的答案。

最佳答案

就装载程序而言,各节无关紧要-它们将被忽略。加载程序仅查看段,并且可执行文件的每个可加载段都在指定的地址加载。然后,加载程序将触发动态链接器(如果在可执行文件中要求)以处理共享库。通常,符号表和字符串表不在可装入的段中,因此装入程序将忽略它们。

因此,依次回答您的问题:

1)加载程序忽略.init和.fini节。它们通常是某些可装入段的一部分,而exectuable中的初始代码将运行.init节中的代码。动态链接器将加载共享对象的段,并调用每个入口点,这将类似地调用某些已加载段中的.init代码。

2)字符串/符号表仅对链接有意义,而不对加载有意义。因此,动态链接器将查看它们以解决任何重定位并构建跳转表

3)重定位主要用于(静态)链接-可执行文件永远不要包含重定位文件,并且它们在共享库中应该很少见(共享库通常与位置无关,因此不需要)。一些动态链接器根本无法处理重定位(不确定正常的Linux动态链接器),因此它们无法加载仍具有重定位的共享对象

4).hash节只是加快符号查找的一种优化方法-而不是通过符号表线性搜索特定符号,.hash节将直接带您进入它。您可以放心地忽略它们,并根据需要缓慢进行符号查找。

编辑

关于ELF加载程序的简短描述:

  • 读取ELF文件
  • 的程序头
  • 将文件的所有LOAD段加载到内存中。
  • 如果程序头中有一个INTERP条目,则以递归方式加载该二进制
  • 调用程序的入口点。

  • 差不多就够了(设置堆栈还有一些麻烦,但这显然不是加载程序的一部分,而是加载程序甚至没有运行之前的过程设置的一部分)。

    对于静态链接的可执行文件,没有INTERP条目,仅此而已。对于动态链接的可执行文件,INTERP节将类似于“/lib/ld-linux.so.2”(字符串),因此对加载程序的递归调用将读取该二进制文件,加载所有LOAD节,注意没有INTERP节(因此没有进一步的递归调用),调用入口点,然后返回(在此点,基本可执行文件的加载器将调用基本可执行文件的入口点)。

    现在,动态链接器是已加载的第二个可执行文件(/lib/ld-linux.so.2)。它要做的是去阅读原始二进制文件的.dynamic部分。这将告诉它要加载的共享库的列表,以及要在这些共享库中填充特定符号地址的表(.plt节-程序加载表)。因此它将加载这些共享库,在其中查找符号,并将其地址粘贴到该表中。每个共享库将有其自己的.dynamic节,该节将由动态链接器递归处理。符号查找会查看到目前为止已加载的所有对象中的所有符号,因此主程序中的符号可能会“覆盖”其他共享对象中的符号,并将其地址停留在共享对象的.plt中。加载每个共享库及其所有依赖项之后,将调用共享库的入口点。如果两个共享对象相互依赖(合法),则两个对象都将被加载并解析其.plts,然后将调用两个入口点,但不会以任何特别定义的顺序进行。

    请注意,在以上所有内容中,重定位从未出现。当无法在共享对象中指定的(虚拟)地址处加载共享对象时(因为该地址已经加载了其他内容),可能会发生重定位。发生这种情况时,需要将共享库重定位以加载到其他地址,这涉及查看对象中的所有重定位条目以查找需要修补以处理重定位地址的事物。

    最后,符号引用在包含引用的对象的符号表中仅具有偏移量-链接器需要在已加载的所有其他对象的符号表中查找符号名(字符串),以找出哪些内容它指的是。每个对象都有其自己的符号表,并且这些表除了逻辑上没有组合。符号查找将遍历到目前为止已加载的所有对象,然后依次在每个符号表中查找该符号,以查找定义该符号的条目。

    关于c++ - Linux ELF 32位加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12135503/

    相关文章:

    c++ - strncpy 需要很长时间

    linux - 无法安装git

    assembly - 扩展编译器以获得自己的汇编输出

    ios - 为什么我不能在 Swift 中重新分配实例方法?

    linux - 如何在linux shell中获取内存地址的值

    c++ - 以自定义类为键的 Unordered_map

    c++ - 线程安全的简单 C++ 容器类

    c++ - 初始化类 - 未解析的外部符号

    c++ - vector 析构函数导致程序在 C++ 中崩溃

    linux内核头文件