《程序员的自我修养——链接、装载与库》读书笔记—— 3.4 ELF文件结构

elf文件结构:

在这里插入图片描述

文件头

整个elf文件的
基本属性,包括elf类型(可重定向、可执行、共享目标文件),字节序(大小端)等等。使用readelf -h 可以查看文件头
在这里插入图片描述

段表

各个段的信息,包括段名,段的长度,各段在文件中的偏移等,包括:
1. 段名
2. 段类型:包括程序段(代码段、数据段)、无效段、符号表、字符串表、重定位表、符号表的哈希表、动态链接信息等
3. 段标志位:是否可写,是否可执行等
4. 段虚地址:如果该段可被加载,则为被加载后在进程地址空间中的虚拟地址
5. 段偏移
… …
使用readelf -S 可以查看段表。从下边的段表中可以看到,strtab 字符串表位于下标为29 的段中,与文件头中的“Section headerstring table index: 29”相对应。如下
在这里插入图片描述

这里大胆猜测一下,elf 被解析的过程可能是下边这样的:
1. 根据文件头中的“start of section header” 找到段表的所在位置
2. 根据段表中的段偏移等信息,找到每一个段

zqxl@ubuntu:~/work/practice/_3.4_SimpleSection$ readelf -S simplesection.o
There are 30 section headers, starting at offset 0x1a28:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000000238  00000238
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             0000000000000254  00000254
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .note.gnu.build-i NOTE             0000000000000274  00000274
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         0000000000000298  00000298
       000000000000001c  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           00000000000002b8  000002b8
       00000000000000a8  0000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           0000000000000360  00000360
       0000000000000084  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           00000000000003e4  000003e4
       000000000000000e  0000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          00000000000003f8  000003f8
       0000000000000020  0000000000000000   A       6     1     8
  [ 9] .rela.dyn         RELA             0000000000000418  00000418
       00000000000000c0  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             00000000000004d8  000004d8
       0000000000000018  0000000000000018  AI       5    22     8
  [11] .init             PROGBITS         00000000000004f0  000004f0
       0000000000000017  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         0000000000000510  00000510
       0000000000000020  0000000000000010  AX       0     0     16
  [13] .plt.got          PROGBITS         0000000000000530  00000530
       0000000000000008  0000000000000008  AX       0     0     8
  [14] .text             PROGBITS         0000000000000540  00000540
       00000000000001d2  0000000000000000  AX       0     0     16
  [15] .fini             PROGBITS         0000000000000714  00000714
       0000000000000009  0000000000000000  AX       0     0     4
  [16] .rodata           PROGBITS         0000000000000720  00000720
       000000000000000a  0000000000000000   A       0     0     4
  [17] .eh_frame_hdr     PROGBITS         000000000000072c  0000072c
       0000000000000044  0000000000000000   A       0     0     4
  [18] .eh_frame         PROGBITS         0000000000000770  00000770
       0000000000000128  0000000000000000   A       0     0     8
  [19] .init_array       INIT_ARRAY       0000000000200db8  00000db8
       0000000000000008  0000000000000008  WA       0     0     8
  [20] .fini_array       FINI_ARRAY       0000000000200dc0  00000dc0
       0000000000000008  0000000000000008  WA       0     0     8
  [21] .dynamic          DYNAMIC          0000000000200dc8  00000dc8
       00000000000001f0  0000000000000010  WA       6     0     8
  [22] .got              PROGBITS         0000000000200fb8  00000fb8
       0000000000000048  0000000000000008  WA       0     0     8
  [23] .data             PROGBITS         0000000000201000  00001000
       0000000000000018  0000000000000000  WA       0     0     8
  [24] Test_Section      PROGBITS         0000000000201018  00001018
       0000000000000004  0000000000000000  WA       0     0     4
  [25] .bss              NOBITS           000000000020101c  0000101c
       000000000000000c  0000000000000000  WA       0     0     4
  [26] .comment          PROGBITS         0000000000000000  0000101c
       0000000000000029  0000000000000001  MS       0     0     1
  [27] .symtab           SYMTAB           0000000000000000  00001048
       0000000000000690  0000000000000018          28    46     8
  [28] .strtab           STRTAB           0000000000000000  000016d8
       0000000000000243  0000000000000000           0     0     1
  [29] .shstrtab         STRTAB           0000000000000000  0000191b
       000000000000010b  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

重定位表

字符串表

各段对应的源码

在这里插入图片描述

  1. BSS段:Block Started by Symbol,存放未初始化的全局变量。BSS段属于静态内存分配。

  2. 数据段:存放已初始化的全局变量。数据段属于静态内存分配。

  3. 代码段:code segment/text segment,存放程序执行代码。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

  4. 其他段:如下图
    在这里插入图片描述

    另外:
    全局的未初始化变量存在于.bss段中,具体体现为一个占位符;全局的已初始化变量存于.data段中;而函数内的自动变量都在栈上分配空间。.bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);而.data却需要占用,其内容由程序初始化,因此造成了上述情况。

    bss段(未手动初始化的数据)并不给该段的数据分配空间,只是记录数据所需空间的大小。

    data(已手动初始化的数据)段则为数据分配空间,数据保存在目标文件中。 数据段包含经过初始化的全局变量以及它们的值。BSS段的大小从可执行文件中得到 ,然后链接器得到这个大小的内存块,紧跟在数据段后面。当这个内存区进入程序的地址空间后全部清零。包含数据段和BSS段的整个区段此时通常称为数据区。

各个段的内容

使用objdump -s -d将所有段的内容以16进制打印出来

zqxl@ubuntu:/work/myprojects/code3-1$ objdump -s -d simple_section.o

simple_section.o:     file format elf64-x86-64

Contents of section .text:
 0000 554889e5 4883ec10 897dfc8b 45fc89c6  UH..H....}..E...
 0010 488d3d00 000000b8 00000000 e8000000  H.=.............
 0020 0090c9c3 554889e5 4883ec10 c745fc01  ....UH..H....E..
 0030 0000008b 15000000 008b0500 00000001  ................
 0040 d089c7e8 00000000 b8000000 00c9c3    ...............
Contents of section .data:
 0000 5a000000 59000000                    Z...Y...
Contents of section TestSection:
 0000 7e000000                             ~...
Contents of section .rodata:
 0000 613d2564 0a00                        a=%d..
Contents of section .comment:
 0000 00474343 3a202855 62756e74 7520372e  .GCC: (Ubuntu 7.
 0010 342e302d 31756275 6e747531 7e31382e  4.0-1ubuntu1~18.
 0020 30342e31 2920372e 342e3000           04.1) 7.4.0.
Contents of section .eh_frame:
 0000 14000000 00000000 017a5200 01781001  .........zR..x..
 0010 1b0c0708 90010000 1c000000 1c000000  ................
 0020 00000000 24000000 00410e10 8602430d  ....$....A....C.
 0030 065f0c07 08000000 1c000000 3c000000  ._..........<...
 0040 00000000 2b000000 00410e10 8602430d  ....+....A....C.
 0050 06660c07 08000000                    .f......

Disassembly of section .text:

0000000000000000 <func1>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 ec 10             sub    $0x10,%rsp
   8:   89 7d fc                mov    %edi,-0x4(%rbp)
   b:   8b 45 fc                mov    -0x4(%rbp),%eax
   e:   89 c6                   mov    %eax,%esi
  10:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi        # 17 <func1+0x17>
  17:   b8 00 00 00 00          mov    $0x0,%eax
  1c:   e8 00 00 00 00          callq  21 <func1+0x21>
  21:   90                      nop
  22:   c9                      leaveq
  23:   c3                      retq

0000000000000024 <main>:
  24:   55                      push   %rbp
  25:   48 89 e5                mov    %rsp,%rbp
  28:   48 83 ec 10             sub    $0x10,%rsp
  2c:   c7 45 fc 01 00 00 00    movl   $0x1,-0x4(%rbp)
  33:   8b 15 00 00 00 00       mov    0x0(%rip),%edx        # 39 <main+0x15>
  39:   8b 05 00 00 00 00       mov    0x0(%rip),%eax        # 3f <main+0x1b>
  3f:   01 d0                   add    %edx,%eax
  41:   89 c7                   mov    %eax,%edi
  43:   e8 00 00 00 00          callq  48 <main+0x24>
  48:   b8 00 00 00 00          mov    $0x0,%eax
  4d:   c9                      leaveq
  4e:   c3                      retq

elf 文件查看常用命令

readelf:查看elf文件
	-h:查看elf文件头
	-S:段表结构
objdump:查看elf文件
	-s:打印所有段的内容
	-d:将指令内容反汇编
size:查看elf各段的长度

将变量放入指定的名为“FOO1”的段中
__attribute__((section("FOO1"))) int var=126; 

参考
https://www.cnblogs.com/ggds/p/8324761.html

附录 源码

int printf(const char *format,...);

int global_init_var=90;
int g_uninit_var;

__attribute__((section("Test_Section"))) int var=126;

void func1(int i)
{
        printf("a=%d\n",i);
}

int main(void)
{
    static int var = 89;
    static int var2;
    int a=1;
    int b;

    func1(var + var2);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值