详解链接下的ELF可重定位目标文件结构

一、什么是链接?

     gcc编译器读取源程序文件(.c文件)并把它翻译成一个可执行目标文件,翻译过程中就包括了链接。

    在现代系统中,链接是由叫做链接器的程序自动执行的。

      链接是将各种代码和数据片段收集并组合成为一个单一文件的过程,这个文件可被加载到内存并执行。也就是将所有的文件汇总为一个文件。

二、静态链接

     ·静态连接器以一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的,可以加载和运行的可执行目标文件作为输出。

     ·可重定位目标文件由各种不同的代码和数据节组成,每一节都是一个连续的字节序列

     ·为了构造可执行文件,链接器必须完成两个主要任务

          1、符号解析:目标文件定义和引用符号,每个符号对应于一个函数、一个全局变量或者一个静态变量。其目的是将每个符号引用正好和一个符号定义关联起来

          2、重定位:编译器和汇编器生成从地址 开始的代码和数据节,然偶修改所有对这些符号的引用,使他们指向这个内存位置。

     这里我们可以通俗的理解一下,所谓链接,就是在多个程序同时编译的情况下,我们需要将文件中的变量函数整合到一个文件中,分配内存,方便使用。

     现代x86-64Linux和Unix系统的目标文件使用可执行可链接格式(ELF)

三、可重定位目标文件

    我们来看一下一个典型的ELF可重定位目标文件的格式

ELF头 以一个16个字节的序列开始,这个序列描述了生成该文件的系统的字的大小和字节顺序。ELF头剩下的部分包含帮助链接器语法分析和解释目标文件的信息。其中包括ELF头的大小,目标文件的类型,及其类型,节头部表的文件偏移,节头部表中条目的大小和数量。
.text节 已编译程序的机器代码(比如一些函数)
.rodata 只读数据,比如printf语句中的格式串和开关语句跳转表
.data 已初始化的全局变量和静态C变量(局部C变量在运行时被保存在栈中,不出现在data和bss中)
.bss 未初始化的全局和静态C变量,以及所有被初始化为0的全局或静态变量
.symtab 一个符号表,它存放在程序中定义和应用的函数和全局变量的信息(不包含局部变量条目)
.rel.text .text节的重定位信息,用于重新修改代码段的指令中的地址信息
.rel.data .data节的重定位信息,用于对被模块使用或定义的全局变量进行重定位的信息
.debug 一个调试符号表(gcc -g)
.line 原始C源程序中的行号和.text节中机器指令之间的映射,通过-g调用
.strtab 一个字符串表。其中内容包括.symtab和.debug节中的符号表,以及头节部中的节名字。
节头表 每个节的节名,偏移和大小

      接下来,我们用一段简单的代码演示一下

int sum(int *a, int n);

int array[2] = {1, 2};

int main() 
{
    int val = sum(array, 2);
    return val;
}

①ELF头

先只链接,生成可重定位目标文件

调出ELF头的内容

②节头部表

 根据节头部表信息看可重定位文件。根据每个节的偏移量和大小画出整个可重定位文件。

eg: .text:000040~000040+00001f

③.text .data .bss

每个节放什么变量详细去看前面的表格,这里以一个程序举例

     ·.bss节中不放入初始值,只要说明将来执行是占用几个字节即可,因此,.bss实际上不占用磁盘空间,提高了磁盘空间利用率

     ·有时.common和.bss会交替出现,这里分辨一下

            .common   未初始化的全局变量

            .bss            未初始化的静态变量,以及初始化为0的全局或静态变量

④.symtab

发布了22 篇原创文章 · 获赞 2 · 访问量 5442

猜你喜欢

转载自blog.csdn.net/qq_43135849/article/details/101600674