从ELF文件谈起
本文信息来源:
What's the difference of section and segment in ELF file format
ELF Sections & Segments and Linux VMA Mappings
ELF简介
ELF全称 executable and linkable format 精灵
是一种linux下常用的可执行文件 对象 共享库的标准文件格式
还有许多其他可执行文件格式 PE Mach-O COFF COM
内核中处理elf相关代码参考: binfmt_elf.c
elf中的数据按照Segment(段)和Section(节)两个概念进行划分
ELF文件格式


ELF Header
- 架构 ABI版本等基础信息
- program header table的位置和数量
- section header table的位置和数量
Program header table
- 每个表项定义了一个segment
- 每个segment可包含多个section
Section header table
- 每个表项定义了一个section
readelf命令
可用readelf命令来展示elf文件的相关信息
用法如下:
用法:readelf <选项> elf-文件
 显示关于 ELF 格式文件内容的信息
 Options are:
  -a --all               Equivalent to: -h -l -S -s -r -d -V -A -I
  -h --file-header       Display the ELF file header
  -l --program-headers   Display the program headers
     --segments          An alias for --program-headers
  -S --section-headers   Display the sections' header
     --sections          An alias for --section-headers
  -g --section-groups    Display the section groups
  -t --section-details   Display the section details
  -e --headers           Equivalent to: -h -l -S
比如,使用readelf来查看date的信息
readelf -l /bin/date
输出
Elf 文件类型为 DYN (Position-Independent Executable file)
Entry point 0x38c0
There are 13 program headers, starting at offset 64
程序头:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x00000000000002d8 0x00000000000002d8  R      0x8
  INTERP         0x0000000000000318 0x0000000000000318 0x0000000000000318
                 0x000000000000001c 0x000000000000001c  R      0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x00000000000028a8 0x00000000000028a8  R      0x1000
  LOAD           0x0000000000003000 0x0000000000003000 0x0000000000003000
                 0x0000000000010001 0x0000000000010001  R E    0x1000
  LOAD           0x0000000000014000 0x0000000000014000 0x0000000000014000
                 0x0000000000005cf0 0x0000000000005cf0  R      0x1000
  LOAD           0x0000000000019ff0 0x000000000001aff0 0x000000000001aff0
                 0x00000000000010b0 0x0000000000001268  RW     0x1000
  DYNAMIC        0x000000000001ab98 0x000000000001bb98 0x000000000001bb98
                 0x00000000000001f0 0x00000000000001f0  RW     0x8
  NOTE           0x0000000000000338 0x0000000000000338 0x0000000000000338
                 0x0000000000000040 0x0000000000000040  R      0x8
  NOTE           0x0000000000000378 0x0000000000000378 0x0000000000000378
                 0x0000000000000044 0x0000000000000044  R      0x4
  GNU_PROPERTY   0x0000000000000338 0x0000000000000338 0x0000000000000338
                 0x0000000000000040 0x0000000000000040  R      0x8
  GNU_EH_FRAME   0x0000000000018000 0x0000000000018000 0x0000000000018000
                 0x0000000000000454 0x0000000000000454  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x0000000000019ff0 0x000000000001aff0 0x000000000001aff0
                 0x0000000000001010 0x0000000000001010  R      0x1
 Section to Segment mapping:
  段节...
   00
   01     .interp
   02     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
   03     .init .plt .text .fini
   04     .rodata .eh_frame_hdr .eh_frame
   05     .init_array .fini_array .data.rel.ro .dynamic .got .data .bss
   06     .dynamic
   07     .note.gnu.property
   08     .note.gnu.build-id .note.ABI-tag
   09     .note.gnu.property
   10     .eh_frame_hdr
   11
   12     .init_array .fini_array .data.rel.ro .dynamic .got 
可知:
- 在加载到内存中时,程序被分成了13个Segment(从PHDR到GNU_RELRO)
- 每个Segment都包含了1个或者更多的Section
Segment vs Section
Segment
- 包含着运行时需要的信息 
- 用于告诉操作系统,段应该被加载到虚拟内存中的什么位置?每个段都有那些权限?(read, write, execute) 
- 每个Segment主要包含加载地址 文件中的范围 内存权限 对齐方式等信息 
Section
- 包含着链接时需要的信息 
- 用于告诉链接器,elf中每个部分是什么,哪里是代码,哪里是只读数据,哪里是重定位信息 
- 每个Section主要包含Section类型 文件中的位置 大小等信息 
- 链接器会把Section放入Segment中 
Segment和Section的关系
- 相同权限的Section会放入同一个Segment,例如.text和.rodata section
- 一个Segment包含许多Section,一个Section可以属于多个Segment
链接脚本
运行
ld --verbose
可以看到本系统中所用的脚本
我的Archlinux 5.16.13-arch1-1的链接脚本一部分是这样:
  .gnu.version_r  : { *(.gnu.version_r) }
  .rela.dyn       :
    {
      *(.rela.init)
      *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
      *(.rela.fini)
      *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
      *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
      *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
      *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
      *(.rela.ctors)
      *(.rela.dtors)
      *(.rela.got)
      *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
      *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
      *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
      *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
      *(.rela.ifunc)
    }
表示:
 .gnu.version_r  Section 会被放入 .gnu.version_r Segment
.rela.init等一大堆的Section,会被放入 .rela.dyn  Segment
汇编中的伪指令全部都是Section,要等链接之后才会有Segment
NASM中
.section和.segment这两个是等效的,都表示Section
ELF文件分类
可执行文件(ET_EXEC)
可直接运行的程序,必须包含segment
对象文件(ET_REL,*.o)
需要与其他对象文件链接,必须包含section
动态库(ET_DYN,*.so)
与其他对象文件/可执行文件链接
必须同时包含segment和section
ELF的内存映射

查看内存映射情况
cat /proc/[pid]/maps
比如运行
cat /proc/self/maps
查看cat本身的内存映射
563b04d75000-563b04d77000 r--p 00000000 fe:00 6294104                    /usr/bin/cat
563b04d77000-563b04d7c000 r-xp 00002000 fe:00 6294104                    /usr/bin/cat
563b04d7c000-563b04d7f000 r--p 00007000 fe:00 6294104                    /usr/bin/cat
563b04d7f000-563b04d80000 r--p 00009000 fe:00 6294104                    /usr/bin/cat
563b04d80000-563b04d81000 rw-p 0000a000 fe:00 6294104                    /usr/bin/cat
563b058b6000-563b058d7000 rw-p 00000000 00:00 0                          [heap]
7f5f7324b000-7f5f73837000 r--p 00000000 fe:00 6364075                    /usr/lib/locale/locale-archive
7f5f73837000-7f5f7383a000 rw-p 00000000 00:00 0
7f5f7383a000-7f5f73866000 r--p 00000000 fe:00 6294921                    /usr/lib/libc.so.6
7f5f73866000-7f5f739dc000 r-xp 0002c000 fe:00 6294921                    /usr/lib/libc.so.6
7f5f739dc000-7f5f73a30000 r--p 001a2000 fe:00 6294921                    /usr/lib/libc.so.6
7f5f73a30000-7f5f73a31000 ---p 001f6000 fe:00 6294921                    /usr/lib/libc.so.6
7f5f73a31000-7f5f73a34000 r--p 001f6000 fe:00 6294921                    /usr/lib/libc.so.6
7f5f73a34000-7f5f73a37000 rw-p 001f9000 fe:00 6294921                    /usr/lib/libc.so.6
7f5f73a37000-7f5f73a46000 rw-p 00000000 00:00 0
7f5f73a70000-7f5f73a92000 rw-p 00000000 00:00 0
7f5f73a92000-7f5f73a94000 r--p 00000000 fe:00 6294911                    /usr/lib/ld-linux-x86-64.so.2
7f5f73a94000-7f5f73abb000 r-xp 00002000 fe:00 6294911                    /usr/lib/ld-linux-x86-64.so.2
7f5f73abb000-7f5f73ac6000 r--p 00029000 fe:00 6294911                    /usr/lib/ld-linux-x86-64.so.2
7f5f73ac7000-7f5f73ac9000 r--p 00034000 fe:00 6294911                    /usr/lib/ld-linux-x86-64.so.2
7f5f73ac9000-7f5f73acb000 rw-p 00036000 fe:00 6294911                    /usr/lib/ld-linux-x86-64.so.2
7ffec90a6000-7ffec90c8000 rw-p 00000000 00:00 0                          [stack]
7ffec918d000-7ffec9191000 r--p 00000000 00:00 0                          [vvar]
7ffec9191000-7ffec9193000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
从左到右为:
- 虚拟地址的起始和结束
- 该内存映射的类型flag r(read) w(write) x(execute) p(private) s(shared)
- 实际对象在该内存映射上相对于起始的偏移量
- major:minor: the major and minor number pairs of the device holding the file that has been mapped.
- 映射文件的索引节点号码
- 该内存映射文件的名称
从ELF文件谈起的更多相关文章
- linux实践之ELF文件分析
		linux实践之ELF文件分析 下面开始elf文件的分析. 我们首先编写一个简单的C代码. 编译链接生成可执行文件. 首先,查看scn15elf.o文件的详细信息. 以16进制形式查看scn15elf ... 
- ELF文件
		ELF文件格式是一个开发标准,各种UNIX系统的可执行文件都采用ELF格式,它有三种不同的类型: 可重定位的目标文件 可执行文件 共享库 现在分析一下上一篇文章中经过汇编之后生成的目标文件max.o和 ... 
- elf文件中的.plt .rel.dyn .rel.plt .got .got.plt的关系
		.plt的作用是一个跳板,保存了某个符号在重定位表中的偏移量(用来第一次查找某个符号)和对应的.got.plt的对应的地址 .rel.dyn重定向表,在程序启动时就需要重定位完成. .rel.plt保 ... 
- 实例分析ELF文件动态链接
		参考文献: <ELF V1.2> <程序员的自我修养---链接.装载与库>第6章 可执行文件的装载与进程 第7章 动态链接 <Linux GOT与PLT> 开发平台 ... 
- 实例分析ELF文件静态链接
		参考文献: <ELF V1.2> <程序员的自我修养---链接.装载与库>第4章 静态链接 开发平台: [thm@tanghuimin static_link]$ uname ... 
- ldconfig报错 :libstdc++.so.6.0.18-gdb.py不是一个elf文件
		今天安装wxWidgets,输入ldconfig竟然提示 /usr/lib64/libstdc++.so.6.0.18-gdb.py 不是一个elf文件,开头魔数错误 摸不着头脑,上网搜了一下,有说是 ... 
- axf、elf文件转换成bin、hex脚本工具
		在嵌入式开发过程中常常遇到将axf或elf文件转换成bin的情况,大家都知道通过gnu toolchain中的objcopy和keil中的fromelf能做到.可是为了这么一个小事而记住复杂的选项以及 ... 
- 为什么ELF文件的加载地址是0x8048000
		在一个进程的虚拟地址空间中,ELF文件是从0x8048000这个地址开始加载的,为什么会是这个地址? 回答:用命令ld --verbose可以看到0x08048000,ld的默认脚本用这个地址作为EL ... 
- ELF文件数据布局探索(1)
		作为一名Linux小白,第一次看到a.out这个名字,感觉实在是奇怪,搜了一下才知道这是编译器输出的默认可执行文件名 然后vi一下,哇,各种乱码,仔细看看,发现了三个清晰的字符ELF.继续搜索, 第一 ... 
随机推荐
- 「NOI十联测」黑暗
			「NOI十联测」黑暗 \(n\) 个点的无向图,每条边都可能存在,一个图的权值是连通块个数的 \(m\) 次方,求所有可能的图的权值和.(n≤30000,m≤15) 令\(ans[n][m]\)为n个 ... 
- 男孩和女孩(二)-->相识
			转载请注明来源:https://www.cnblogs.com/hookjc/ 那天是男孩的十九岁生日:男孩还是像平常一样,一大早就起来了(快七点了).一切都是那么的平常,直到第一节课下课,男孩的同窗 ... 
- Ajax使用post方式发送数据注意事项
			Ajax使用post方式给服务器传递数据时,需要将传递的字符串转化为模拟from表单发送数据的XML格式 在open之后奢姿头协议信息,模拟from表单传递数据 xhr.setRequestHeade ... 
- Linux Shell脚本攻略复习
			1. 打开终端后的提示符中,$表示普通用户,#表示管理员用户root,root是linux系统中权限最高的用户. 2. shell脚本通常是一个#!起始的文本文件,其中#!位于解释器路径之前. 例如: ... 
- LNMP架构的源码编译以及yum安装
			LNMP架构的源码编译以及yum安装 目录 LNMP架构的源码编译以及yum安装 一.LNMP架构的编译安装 1. 安装nginx服务 (1)关闭防火墙 (2)安装依赖包 (3)创建运行用户 (4)编 ... 
- 一个好用的多方隐私求交算法库JasonCeng/MultipartyPSI-Pro
			Github链接传送:JasonCeng/MultipartyPSI-Pro 大家好,我是阿创,这是我的第29篇原创文章. 今天是一篇纯技术性文章,希望对工程狮们有所帮助. 向大家推荐一个我最近改造的 ... 
- linux_18
			简述keepalived工作原理 编译安装haproxy 总结haproxy各调度算法的实现方式及其应用场景 使用haproxy的ACL实现基于文件后缀名的动静分离 
- 《PHP程序员面试笔试宝典》——在被企业拒绝后是否可以再申请?
			如何巧妙地回答面试官的问题? 本文摘自<PHP程序员面试笔试宝典> 很多企业为了能够在一年一度的招聘季节中,提前将优秀的程序员锁定到自己的麾下,往往会先下手为强.他们通常采取的措施有两种: ... 
- PHP7.x环境下安装redis扩展
			注:以下介绍的安装方式为PHP的安装路径为/usr/local/php,如果你的服务器上PHP的安装目录不一致请按实际情况处理. 首先下载PHP7的redis扩展 wget https://githu ... 
- Linux文件处理三剑客(grep、sed、awk)
			下面所说的是Linux中最重要的三个命令在业界被称为"三剑客",它们是grep.sed.awk. 我们现在知道Linux下一切皆文件,对Linux的操作就是对文件的处理,那么怎么能 ... 
