elf 记录

链接器对编译生成的目标文件进行链接时,A.
首先进行符号解析,找出外部符号在哪定义。如果外部符号在一个静态库中定义,则直接将对应的定义代码复制到最终生成的目标文件中。B.
接着链接器进行符号重定位。编译器在生成目标文件时,通常使用从零开始的相对地址,而在链接过程中,链接器从一个指定的地址开始,根据输入目标文件的顺
序,以段(segment)为单位将它们拼装起来。其中每个段可以包括很多个节(section)。除了目标文件的拼装,重定位过程中还完成了下面两个任
务:一是生成最终的符号表,二是对代码段(.text)中的某些位置进行修改,要修改的位置由编译器生成的重定位表指出

链接过程中还会生成两个表:got表和plt表。

 

got表中每一项都是本运行模块要引用的全局变量或函数的地址,可以用got表来间
接引用全局变量。函数也可以把got表的首地址作为一个基准,用相对该基准的偏移量来(直接)引用静态函数。由于动态链接器(ld-linux.so)不
会把运行模块(*.so)加载到固定地址,在不同进程的地址空间中各运行模块的绝对地址、相对地址都不同。这种不同反映到got表上,就是每个进程的每个
运行模块都有独立的got表,所以进程间不能共享got表(内容)。

 

plt表中每一项都是一小段汇编代码,对应于本运行模块要引用的每一个全局函数。当链接器发现某个符号引用是位于其它共享目标文件(动态连接库*.so)中的一个全局函数时,就在文件的plt表里创建一个项目,以便将来重定位

一个elf头,描绘了整个文件的组织结构,这个文件中会有多个段(segment),每个段都由相应的节(section)拼装而成。

 

对由链接器链接生成的可执行目标文件进行加载运行时,内核首先读取elf文件头。根
据头部数据指示分别读入各种数据结构,找出可加载的段并调用mmap()函数将其加载到内存。内核找到标记为PT_INTERP的段,这个段对应着动态链
接器的名称,然后加载动态链接器(linux中通常是/lib/ld-linux.so.2)。接着内核将控制权交给动态链接器。动态链接器检查程序对外
部文件(共享库)的依赖性,并在需要时对其进行加载。之后动态链接器开始对程序中的外部引用(即全局变量/函数)进行重定位,即定位出程序其引用的外部变
量/函数的真实内存地址。R_386_GLOB_DAT类型的重定位项目涉及到got表。R_386_JMP_SLOT类型的重定位项目涉及到plt表。
动态链接还有一个延迟(lazy)特性,即真正引用时才进行重定位(环境变量LD_BIND_NOW为空值NULL时)。接下来动态链接器执行elf文件
中标记为.init节的代码,进行程序运行的初始化。最后动态链接器把控制权交给程序,从elf文件头中定义的入口处开始执行程序。

 

 

03-08
### ELF 文件格式概述 ELF(Executable and Linking Format)是一种对象文件的格式,广泛应用于Unix及其衍生系统中,用于定义不同类型的对象文件的内容结构和布局方式[^1]。 #### ELF 文件的主要组成部分 一个典型的ELF文件主要由以下几个部分构成: - **ELF 头 (ELF Header)** 这是一个固定长度的数据结构,位于每一个ELF文件的最前端。它包含了描述整个文件属性的关键信息,比如目标架构、入口地址等[^2]。 - **程序头表 (Program Header Table, PHDR)** 如果存在,则紧跟在ELF头部之后。此表格记录了如何加载可执行映像到内存中的指令集,对于动态链接库尤其重要。 - **节区 (Sections)** 节区是数据的实际承载者,它们按照特定的方式被组织起来形成完整的功能模块。常见的有`.text`(代码段)、`.data`(已初始化全局变量)、`.bss`(未初始化静态变量)等等。 - **节头表 (Section Header Table, SHT)** 描述各个节的位置大小及其他特性;只有当需要访问具体某一部分内容时才会用到这部分元数据。 #### ELF 文件类型分类 依据用途的不同,可以将ELF文件分为如下几类[^4]: | 类型 | 定义名 | 含义 | |---------|------------|----------------------------------------------------------| | 可重定位 | `ET_REL` | 编译器产生的中间产物,通常指`.o`文件,在最终链接阶段会被合并成其他形式的输出 | | 可执行文件 | `ET_EXEC` | 直接运行的应用程序镜像 | | 动态共享对象 | `ET_DYN` | 即所谓的.so文件,供多个进程间共享使用的函数集合 | | Core Dump | `ET_CORE` | 当应用程序崩溃时生成的核心转储文件,有助于调试分析 | ```c // 示例:获取并打印 ELF 文件类型 #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> #include <elf.h> void print_elf_type(const char *filename){ int fd; Elf64_Ehdr ehdr; if ((fd = open(filename, O_RDONLY)) == -1) { perror("open"); exit(EXIT_FAILURE); } read(fd, &ehdr, sizeof(ehdr)); switch (ehdr.e_type) { case ET_NONE: printf("%s is an unknown type.\n", filename); break; case ET_REL : printf("%s is a relocatable object file (.o).\n", filename); break; case ET_EXEC: printf("%s is an executable file.\n", filename); break; case ET_DYN : printf("%s is a shared library or position-independent executable.\n", filename); break; case ET_CORE: printf("%s is a core dump file.\n", filename); break; default: printf("%s has an unrecognized type.\n", filename); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值