首页 > 其他分享 >ELF链接以及结构

ELF链接以及结构

时间:2023-02-19 11:45:58浏览次数:50  
标签:初始化 符号表 文件 symtab ELF 链接 结构

ELF文件结构

环境: 运行Linux的x86-64系统

一、编译与链接

假设存在两个cpp文件

使用gcc -c test.cpp add.cpp生成两个可重定位目标文件.o,此时还未进行链接,单独.o文件无法执行

使用ld -e main -o out add.o test.o链接并且-e main指定入口,此时依旧是无法运行,提示段错误,这是因为系统并不知道改在什么时候退出(我们并没有链接其他库帮我们进行退出),尝试在main下断点,gdb调试到ret即为返回时进行下一步

下一步可见直接跳到0x1的地址执行代码,显然这个地址是不正确的,所以导致段错误,下图中rip值确为0x1

解决方案:
加入自解决exit代码,然后在return之前调用exit即可,代码实际是实现了一个系统调用sys_exit

void exit() {
  asm("movq $14,%rdi \n\t"
      "movq $60,%rax \n\t"
      "syscall \n\t");
}

使用objdump分别dump链接前的test.o链接后输出的out, 链接前test.o中无add的汇编实现,而且地址从0开始,链接后有add汇编实现,并且地址空间从0x401000开始

二、ELF文件格式

典型的可重定位目标文件的格式如下图所示,注意是可重定位目标文件,而非可执行文件

.text:已编译程序的机器代码。

.rodata:只读数据,比如printf语句中的格式串和开关语句的跳转表。

.data:已初始化的全局和静态C变量。局部C变量在运行时被保存在栈中,既不出现在.data节中,也不出现在.bss节中。

.bss:未初始化的全局和静态C变量,以及所有被初始化为0的全局或静态变量。在目标文件中这个节不占据实际的空间,它仅仅是一个占位符。目标文件格式区分已初始化和未初始化变量是为了空间效率:在目标文件中,未初始化变量不需要占据任何实际的磁盘空间。运行时,在内存中分配这些变量,初始值为0。

.symtab:一个符号表,它存放在程序中定义和引用的函数和全局变量的信息。一些程序员错误地认为必须通过-g选项来编译一个程序,才能得到符号表信息。实际上,每个可重定位目标文件在.symtab中都有一张符号表(除非程序员特意用STRIP命令去掉它)。然而,和编译器中的符号表不同,.symtab符号表不包含局部变量的条目。

.rel.text:一个.text节中位置的列表,当链接器把这个目标文件和其他文件组合时,需要修改这些位置。一般而言,任何调用外部函数或者引用全局变量的指令都需要修改。另一方面,调用本地函数的指令则不需要修改。注意,可执行目标文件中并不需要重定位信息,因此通常省略,除非用户显式地指示链接器包含这些信息。

.rel.data:被模块引用或定义的所有全局变量的重定位信息。一般而言”任何已初始化的全局变量,如果它的初始值是一个全局变量地址或者外部定义函数的地址,都需要被修改。

.debug:一个调试符号表,其条目是程序中定义的局部变量和类型定义,程序中定义和引用的全局变量,以及原始的C源文件。只有以-g选项调用编译器驱动程序时,才会得到这张表。

.line:原始C源程序中的行号和.text节中机器指令之间的映射。只有以-g选项调用编译器驱动程序时,才会得到这张表。

.strtab:一个字符串表,其内容包括.symtab和.debug节中的符号表,以及节头部中的节名字。字符串表就是以null结尾的字符串的序列。

这里着重说明.symtab .shstrtab .strtab的不同
.strtabstring table保存普通的字符串,比如符号的名字,如下图有test.cpp _ZL13global_static 以及 main _Z4exitv Z3addii等等

.shstrtab即为section header table 保存节的名字,如.data .text等

用readelf -s读.symtab可以看到输出的都是strtab中的一些符合和其他数据。
实际上.symtab确定符号的名称与其值之间的关联,其中名称不是直接以字符串形式出现的,而是表示为某一字符串数组.strtab的索引

下为symtable的结构体定义,st_name实际存储的是偏移,到strtab中寻找对应符号,value实际也是地址,在.data中寻找值

根据下面的elf对比图可见,可执行文件比可重定位目标文件多一个program_header_table (describes the sections of the program that contain executable program code which will be mapped into the program address space as it is loaded)
并且section_header_table内结构不一样,可重定位目标文件多两个rela节和一个note.gnu_stack堆栈提示节

如下图,左边是ELF的链接视图,可以理解为是目标代码文件的内容布局。右边是ELF的执行视图,可以理解为可执行文件的内容布局。

Section称为节,是指在汇编源码中经由关键字section或segment修饰、逻辑划分的指令或数据区域,汇编器会将这两个关键字修饰的区域在目标文件中编译成节,也就是说"节"最初诞生于目标文件中。

Segment称为段,是链接器根据目标文件中属性相同的多个Section合并后的Section集合,这个集合称为Segment,也就是段,链接器把目标文件链接成可执行文件,因此段最终诞生于可执行文件中。我们平时所说的可执行程序内存空间中的代码段和数据段就是指的Segment。

从概念上来说,段和节的区别在于它们所代表的内存区域的不同。段代表的是可执行代码和数据等内存区域,而节则更加抽象,它代表的是文件中的一组相关数据。在ELF文件中,节是按照功能和目的来划分的,比如代码节、数据节、符号表节等等,而段则是按照内存区域来划分的,比如代码段、数据段、BSS段等等。总的来说,段和节在ELF文件中都是重要的概念,它们分别代表了可执行代码和数据在内存中的组织方式和文件中的逻辑组织方式。

使用readelf -S 分别读取test.o和out的节Section

关于标志位,说明如下(部分),例如flag为WA,那这节在执行过程中可写并且需要分配内存,例如在.o中rela.text就不需要分配内存,因为他与可执行文件的执行无关,只在链接阶段有用

使用readelf -l 分别读取test.o和out的段Segment,显然可重定位目标文件.o并没有Segment的概念,而可执行文件有
这里的标志位,比如R E就是可读可执行,但是不可写

三、数据的存储位置

第二节中提到了不同数据存放的节,这里进行验证,这里并未验证const数据,但是const数据是只读数据,存放在.rodata

.bss段存放未初始化的全局和静态C变量,以及所有被初始化为0的全局或静态变量

.data段存放已初始化的全局和静态C变量。局部C变量在运行时被保存在栈中,既不出现在.data节中,也不出现在.bss节中。

参考

标签:初始化,符号表,文件,symtab,ELF,链接,结构
From: https://www.cnblogs.com/LLeaves/p/17128680.html

相关文章

  • c++学习9 结构体
    一结构体赋值结构体赋值的方法有三种,逐个成员赋值,整体赋值和拷贝赋值。设一个结构体有struckstudent{intage;charch[32];};逐个成员赋值:studenttony={16,"tony"};......
  • xshell链接virtualbox 虚拟机 CentOs7
    安装虚拟机​​点击下载​​安装xshell​​点击下载​​(填写邮箱,邮箱里下载)下载CentOs​​点击下载CentOs7​​创建虚拟机,安装刚刚下载的镜像如图设置:xshell设置:如果失败,......
  • 01 数据结构概念简述
     一、数据结构就是数据的存储方式如何存储、以体现数据之间的逻辑关系,为以后更好的利用数据做准备数据关系一般分为:"一对一"、"一对多"、"多对多""一对一"关系:使......
  • 软件体系结构课堂测试
    (1)什么是架构答:架构是把一个整体划分成不同的部分,不同的角色根据自己的特长分工协作,沟通完成自己相应的部分,再将这些部分有机结合为一个整体,完成项目整体所需要完成的任务......
  • self-attention自注意力机制 2
    https://blog.csdn.net/Michale_L/article/details/126549946 三、Self-Attention详解针对输入是一组向量,输出也是一组向量,输入长度为N(N可变化)的向量,输出同样为长度为N......
  • 【系统架构设计师】计算机组成与体系结构 ② ( 冯诺依曼结构 | 哈佛结构 | 常见的芯片
    文章目录​​一、冯诺依曼结构​​​​二、哈佛结构​​​​三、常见的芯片​​一、冯诺依曼结构冯诺依曼结构:指令存储器与数据存储器应用场景:PC机,使用i3,i......
  • 【系统架构设计师】计算机组成与体系结构 ① ( 计算机组成 | CPU | 存储器 | 总线 | I
    文章目录​​一、计算机组成与体系结构​​​​二、计算机组成结构​​​​三、CPU组成​​​​1、运算器​​​​2、控制器​​一、计算机组成与体系结构计算机组成与体......
  • Xshell链接远程服务器报错
     报错内容: 1、首先:在Linux服务器上输入ps-e|grepssh 判断是否有ssh服务  以上只有客户端。2、进行ssh配置,  3、如果出现报错,无法配置,在Linux服务器......
  • Python学习之线性数据结构(二)
    print(end='')end=表示语句结束后加入的东西print(sep='')sep表示间隔符1223这个间隔的空格就是间隔符print(1,2,sep='',end='')#打印数字1和2间隔符为空格......
  • List集合-数据结构
    List集合-数据结构数据结构是计算机存储,组织数据的方式.是指相互之间存在一种或多种特定关系的数据元素的集合.通常情况下,精心选择的数据结构可以带来更高的运行或者......