《程序员的自我修养》--笔记02

本文详细探讨了ELF文件的四种类型,包括可重定位文件、可执行文件、共享目标文件和核心转储文件,重点剖析了段表、重定位表和字符串表的作用。讲解了如何通过file命令识别文件类型,以及链接过程中的符号表和符号类型。
摘要由CSDN通过智能技术生成

目标文件的内容

ELF文件

linux下,使用file命令可以看到一个文件的类型,对于elf文件来说,一共有四个类型,分别是:

  • 可重定位文件:linux下的.o文件和windows下面的.obj文件,包含代码和数据,可以被链接成共享目标文件;(静态链接库也属于这一类,即.so文件)
  • 可执行文件:可以直接执行,例如/bin/bash,windows的exe;
  • 共享目标文件:linux下的so文件,windows下的dll文件;包含数据和代码,(1)可以作为其他可重定位文件或共享目标文件,一起链接生成目标文件;(2)动态链接器可以将几个这种文件与可执行文件结合,作为进程映像的一部分来运行;
  • 核心转储文件:进程意外终止时,转存相关信息的文件。

ELF文件中的段类别

下图是一个标准的elf文件结构示意图,主要包括图中几个部分:


  1. ELF Header:使用readelf -h xxx.o来查看目标文件的elf header信息;  此外,从elf的头信息中,我们可以得到elf文件基本属性,类型,目标机器号,程序入口地址等。具体信息如下:
  2. 几个重要的段的解释,可以使用objcopy命令自定义段,并插入内容;详情可以百度gcc的扩展运用;
  3. 整体来说,程序经过编译后,通过段实现了抽象。将源代码分为两部分:程序指令以及程序数据,优点主要是:(1)读写数据分离,防止程序被修改;(2)程序和数据的缓存区域单独设计,在cache里面,实现指令缓存和数据缓存分离,提高了指令缓存命中率;(3) 多个程序或者进程时候,实现指令共享。
  4. 分析指令: 用gcc -c将cc文件编译成.o文件,然后用下列命令查看;(linux下有很多实用的小命令,参考:GNU binutils 里的九种武器 - Linux中国的文章 - 知乎 https://zhuanlan.zhihu.com/p/85913402)

ELF中的三剑客

ELF文件中,除了一些基本段,有三个比较重要的部分,分别是段表,重定位表,字符串表。

段表

该表描叙了elf文件包含的所有段的信息,例如每个段的段名,长度,在文件中的偏移,读写权限以及其他权限等。段表是一个数组(每个元素是一个结构体,该结构体定义在 /usr/include/elf.h文件中,需要根据不同的硬件参数,找到对应的宏定义),数组的长度等于ELF文件中段的长度加一,第一个是保留的null结构体。所以,知道了段表数组中,每个结构体的信息,就知道了所有段的信息。但是描述段的信息的结构体,比较复杂。例如ELF32_Shdr段描述符结构:

  • sh_type可以告诉我们一个段是无效段,符号表,或者程序段/代码段/数据段;
  • sh_flags告诉我们该段在进程虚拟地址空间的属性,是否可写,可执行;
  • sh_link和sh_info:如果段的类型和链接相关(重定位表,符号表)的,这两个成员则表明需要使用的数据的地址;

重定位表

在段表中.rel.text是针对.text段的重定位表,所谓重定位,是对代码段中某些函数或者变量的地址进行重新分配(例如对当前代码文件引用别的代码文件的函数或者变量等)。对于重定位表,sh_type的数值为宏定义的”重定位表“类型。sh_link表示符号表的下标,sh_info表示需要重定位的段(地址偏移)。

字符串表

ELF文件中用到了很多的字符串,便于存储, 专门开辟段来存在字符串,在引用字符串的地方,直接用字符串表的偏移即可。字符串表分为两种:

  • 字符串表(.strtab):保存普通的字符串。例如符号的名字
  • 段表字符串表(shstrtab):保存段表中用到的字符串,例如段名;在elf_header的结构体中,e_shrtrndx。

链接的接口——符号

符号:将代码文件中的函数和变量地址,根据编译器的规则,表示为符号(一定格式的字母名称);链接——跨文件,模块,将这些符号,替代成实际的地址。每个目标文件都有一个符号表,该表记录文件的所有符号,每个定义的符号有个value,表示该符号的地址。函数和变量名最重要,以及:全局符号(函数名,全局变量),外部符号(引用外部文件的函数名,变量名),段名,局部符号,符号信息;前两者对于链接需要关心(nm xxx.o,命令查看)。


ELF符号表结构:符号有一个名为.symtab的段表示;定义可在elf.h文件找到

 

st_info 低4位表示符号的类型,高28位表示符号的绑定信息;

st_shndx:如果符号在本目标文件中,则是符号所在段的在段表中的下标;如果符号不是在本目标文件中,则如下:

st_value:结合《程序员自我修养》p84

特殊符号——在代码中直接声明和引用,可以被ld识别;

符号修饰和函数签名——说白了就是符号名的生成规则,和具体编译器规则相关

extern C——用这个语句概括起来的语句,会被当做c语言规则处理,例如:

强符号和弱符号

初始化的全局变量为强符号;未初始化的全局变量为弱符号;(可以通过gcc关键字在源码中修饰。)强符号和弱符号的处理规则:

gcc中可以在源码中设置某个引用为弱引用,强引用(链接找不到符号定义就报错)和弱引用(有定义就用,没有就默认为0或特殊值)。这种设定,可以用于代码库的灵活裁剪和组合,例如在库文件定义一个弱引用,可以在用户依赖的代码被覆盖,而不报错。

其他

目标文件在debug模式下,-g 参数编译,有debug的信息参数;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值