当前位置:   article > 正文

可执行文件详解_.gnu.version

.gnu.version

目录

 

生成可执行文件

可执行文件的结构

可执行文件的ELF Header

可执行文件的section

可执行文件的segment


生成可执行文件

可执行文件也是ELF文件,这里同样从ELF文件的观点分析可执行文件的结构

使用如下两端代码来模拟多个文件生成一个可执行文件的过程

  1. //add.c
  2. extern int times;
  3. int add(int n1, int n2) {
  4. times++;
  5. return n1 + n2;
  6. }
  1. //main.c
  2. #include <stdio.h>
  3. extern int add(int, int);
  4. int times = 0;
  5. int main(void)
  6. {
  7. int a = 2;
  8. int b = 3;
  9. printf("%d, The sum of a and b is %d\n", times, add(a,b));
  10. return 0;
  11. }

使用命令如下,先生成两个可重定位文件,然后对其进行链接,生成可执行文件add

  1. gcc -c add.c -o add.o
  2. gcc -c main.c -o main.o
  3. gcc -o add add.o main.o

注意,假如下面查看可执行文件,发现type是共享库文件类型,可能是因为gcc默认加了--enable-default-pie选项,可以使用-no-pie禁用,如下

gcc -o add add.c main.c -no-pie

可执行文件的结构

可执行文件的ELF Header

使用readelf查看文件

  1. $ readelf -h add
  2. ELF Header:
  3. Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  4. Class: ELF64
  5. Data: 2's complement, little endian
  6. Version: 1 (current)
  7. OS/ABI: UNIX - System V
  8. ABI Version: 0
  9. Type: EXEC (Executable file)
  10. Machine: Advanced Micro Devices X86-64
  11. Version: 0x1
  12. Entry point address: 0x401050
  13. Start of program headers: 64 (bytes into file)
  14. Start of section headers: 14736 (bytes into file)
  15. Flags: 0x0
  16. Size of this header: 64 (bytes)
  17. Size of program headers: 56 (bytes)
  18. Number of program headers: 13
  19. Size of section headers: 64 (bytes)
  20. Number of section headers: 31
  21. Section header string table index: 30

字段分析如下

  1. Type: EXEC (Executable file): 该文件是一个可执行文件;
  2. Entry point address: 0x401050: 文件的入口地址为0x401050,该地址是代码段的起始地址;
  3. xxx of program headers: xxx: 该文件中共有13个program header,每个的大小为56字节;
  4. xxx of section headers: xxx: 该文件中共有31个section header,每个的大小为64字节。

这里可以看出,链接之后生成的可执行文件,该文件结构具有了完整的ELF文件结构。

可执行文件的section

从ELF Header中可以看出 add 有31个 section,使用readelf查看section的内容

  1. $ readelf -S add
  2. There are 31 section headers, starting at offset 0x3990:
  3. Section Headers:
  4. [Nr] Name Type Address Offset
  5. Size EntSize Flags Link Info Align
  6. [ 0] NULL 0000000000000000 00000000
  7. 0000000000000000 0000000000000000 0 0 0
  8. [ 1] .interp PROGBITS 0000000000400318 00000318
  9. 000000000000001c 0000000000000000 A 0 0 1
  10. [ 2] .note.gnu.propert NOTE 0000000000400338 00000338
  11. 0000000000000020 0000000000000000 A 0 0 8
  12. [ 3] .note.gnu.build-i NOTE 0000000000400358 00000358
  13. 0000000000000024 0000000000000000 A 0 0 4
  14. [ 4] .note.ABI-tag NOTE 000000000040037c 0000037c
  15. 0000000000000020 0000000000000000 A 0 0 4
  16. [ 5] .gnu.hash GNU_HASH 00000000004003a0 000003a0
  17. 000000000000001c 0000000000000000 A 6 0 8
  18. [ 6] .dynsym DYNSYM 00000000004003c0 000003c0
  19. 0000000000000060 0000000000000018 A 7 1 8
  20. [ 7] .dynstr STRTAB 0000000000400420 00000420
  21. 000000000000003f 0000000000000000 A 0 0 1
  22. [ 8] .gnu.version VERSYM 0000000000400460 00000460
  23. 0000000000000008 0000000000000002 A 6 0 2
  24. [ 9] .gnu.version_r VERNEED 0000000000400468 00000468
  25. 0000000000000020 0000000000000000 A 7 1 8
  26. [10] .rela.dyn RELA 0000000000400488 00000488
  27. 0000000000000030 0000000000000018 A 6 0 8
  28. [11] .rela.plt RELA 00000000004004b8 000004b8
  29. 0000000000000018 0000000000000018 AI 6 24 8
  30. [12] .init PROGBITS 0000000000401000 00001000
  31. 000000000000001b 0000000000000000 AX 0 0 4
  32. [13] .plt PROGBITS 0000000000401020 00001020
  33. 0000000000000020 0000000000000010 AX 0 0 16
  34. [14] .plt.sec PROGBITS 0000000000401040 00001040
  35. 0000000000000010 0000000000000010 AX 0 0 16
  36. [15] .text PROGBITS 0000000000401050 00001050
  37. 00000000000001d5 0000000000000000 AX 0 0 16
  38. [16] .fini PROGBITS 0000000000401228 00001228
  39. 000000000000000d 0000000000000000 AX 0 0 4
  40. [17] .rodata PROGBITS 0000000000402000 00002000
  41. 0000000000000021 0000000000000000 A 0 0 4
  42. [18] .eh_frame_hdr PROGBITS 0000000000402024 00002024
  43. 000000000000004c 0000000000000000 A 0 0 4
  44. [19] .eh_frame PROGBITS 0000000000402070 00002070
  45. 0000000000000120 0000000000000000 A 0 0 8
  46. [20] .init_array INIT_ARRAY 0000000000403e10 00002e10
  47. 0000000000000008 0000000000000008 WA 0 0 8
  48. [21] .fini_array FINI_ARRAY 0000000000403e18 00002e18
  49. 0000000000000008 0000000000000008 WA 0 0 8
  50. [22] .dynamic DYNAMIC 0000000000403e20 00002e20
  51. 00000000000001d0 0000000000000010 WA 7 0 8
  52. [23] .got PROGBITS 0000000000403ff0 00002ff0
  53. 0000000000000010 0000000000000008 WA 0 0 8
  54. [24] .got.plt PROGBITS 0000000000404000 00003000
  55. 0000000000000020 0000000000000008 WA 0 0 8
  56. [25] .data PROGBITS 0000000000404020 00003020
  57. 0000000000000010 0000000000000000 WA 0 0 8
  58. [26] .bss NOBITS 0000000000404030 00003030
  59. 0000000000000008 0000000000000000 WA 0 0 4
  60. [27] .comment PROGBITS 0000000000000000 00003030
  61. 000000000000002a 0000000000000001 MS 0 0 1
  62. [28] .symtab SYMTAB 0000000000000000 00003060
  63. 0000000000000630 0000000000000018 29 46 8
  64. [29] .strtab STRTAB 0000000000000000 00003690
  65. 00000000000001da 0000000000000000 0 0 1
  66. [30] .shstrtab STRTAB 0000000000000000 0000386a
  67. 000000000000011f 0000000000000000 0 0 1
  68. Key to Flags:
  69. W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  70. L (link order), O (extra OS processing required), G (group), T (TLS),
  71. C (compressed), x (unknown), o (OS specific), E (exclude),
  72. l (large), p (processor specific)
  • .interp: 使用 hexdump 命令可以得到该section的内容,这是程序运行时需要用到的动态链接器的名字。
  • .note.ABI-tag: 这个section存放的是vendor或者编译者指定的一些信息。它是以ELF spec里面规定的SHT_NOTE格式存放的。
  • .note.gnu.build-id: 这个段主要保存的是build id,是文件的唯一标识符,他可以保存成多种格式,比如uuid形式,MD5, SHA1等。
  • .gnu.hash: 里面保存着一个符号hash表,所有参与动态链接的对象都必须包含一个符号hash表。
  • .dynsym: 这个section保存与动态链接相关的导入导出符号,不包括模块内部的符号。而 .symtab 则保存所有符号,包括 .dynsym中的符号。
  • 在本例中,通过readelf命令我们知道.dynsym里有四个条目:
  1. $ readelf -s add
  2. Symbol table '.dynsym' contains 4 entries:
  3. Num: Value Size Type Bind Vis Ndx Name
  4. 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
  5. 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2)
  6. 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
  7. 3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
  • .gnu.version: .gnu.version里的每一项都对应.dynsym中的一个符号;每个表项的内容为:hash值、glibc版本或global/local绑定属性 。在本例中,我们从readelf命令里得到.gnu.version里四个条目如下:
  1. $ readelf -V add
  2. Version symbols section '.gnu.version' contains 4 entries:
  3. Addr: 0x0000000000400460 Offset: 0x000460 Link: 6 (.dynsym)
  4. 000: 0 (*local*) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 0 (*local*)

从其中的内容可以知道,.gnu.version的四个条目解释了.dynsym与之相对应的四个条目的版本。比如,printf这个符号对应的是GLIBC_2.2.5这个版本中的printf函数。

  • .dynstr: 这个section保存了.dynsym中所包含的符号的符号名。
  • .eh_frame_hdr:.eh_frame里面存放的是在发生异常时解析函数调用栈所需要的信息,而.eh_frame_hdrsection保存了.eh_frame对应的header table。这些header table可以在运行时通过调用dl_iterate_phdr函数方便的找到所有的PT_GNU_EH_FRAME segments。
  • .init和.init_array: 这个section中保存了该可执行程序main函数执行之前的初始化代码, 比如设置环境变量,给main函数传递参数等。
  • .fini和.fini_array: 这个section中保存了该可执行程序main函数正常退出之后执行的代码。
  • .dynamic: 这个section里保存了动态链接器所需要的基本信息,比如依赖哪些共享对象、动态链接符号表的位置、动态链接重定位表的位置、共享对象初始化代码的地址等。它是由Elfxx_Dyn(Elf32_Dyn或者Elf64_Dyn)组成的数组。Elfxx_Dyn结构由一个类型值加上一个附加的数值或指针,对于不同的类型,后面附加的数值或者指针有着不同的含义。
  • .plt和.plt.got:plt全名(Procedure Linkage Table)保存了一组16字节代码,用于在动态链接中生成所有外部过程调用符号。
  • .got和.got.plt:got全名(Global Offset Table)保存了一个数组,用于配合PLT生成库函数的真正地址并保存该地址。
  • .rela.plt:这个section保存了.plt中保存的符号的重定位信息。
  • .rela.dyn:这个section保存了除了.plt中保存的符号外的其他符号的重定位信息。
  • .jcr:这个section保存了编译java类所必须的信息。它里面内容是编译器指定的,并且被编译器的初始化函数使用。
  • .text:这个section用来保存可执行程序的代码编译生成的二进制代码。其内容我们通过objdump -C add命令查看后发现,反编译出来的函数不仅包括我们定义的add函数和main函数还包括了其他一些函数,这些函数是链接器加进去的。

可执行文件的segment

segment是由section组成的,可以从 readelf -l add 输出的 program header table 中得到相关的信息

  1. $ readelf -l add
  2. Elf file type is EXEC (Executable file)
  3. Entry point 0x401050
  4. There are 13 program headers, starting at offset 64
  5. Program Headers:
  6. Type Offset VirtAddr PhysAddr
  7. FileSiz MemSiz Flags Align
  8. PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
  9. 0x00000000000002d8 0x00000000000002d8 R 0x8
  10. INTERP 0x0000000000000318 0x0000000000400318 0x0000000000400318
  11. 0x000000000000001c 0x000000000000001c R 0x1
  12. [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  13. LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
  14. 0x00000000000004d0 0x00000000000004d0 R 0x1000
  15. LOAD 0x0000000000001000 0x0000000000401000 0x0000000000401000
  16. 0x0000000000000235 0x0000000000000235 R E 0x1000
  17. LOAD 0x0000000000002000 0x0000000000402000 0x0000000000402000
  18. 0x0000000000000190 0x0000000000000190 R 0x1000
  19. LOAD 0x0000000000002e10 0x0000000000403e10 0x0000000000403e10
  20. 0x0000000000000220 0x0000000000000228 RW 0x1000
  21. DYNAMIC 0x0000000000002e20 0x0000000000403e20 0x0000000000403e20
  22. 0x00000000000001d0 0x00000000000001d0 RW 0x8
  23. NOTE 0x0000000000000338 0x0000000000400338 0x0000000000400338
  24. 0x0000000000000020 0x0000000000000020 R 0x8
  25. NOTE 0x0000000000000358 0x0000000000400358 0x0000000000400358
  26. 0x0000000000000044 0x0000000000000044 R 0x4
  27. GNU_PROPERTY 0x0000000000000338 0x0000000000400338 0x0000000000400338
  28. 0x0000000000000020 0x0000000000000020 R 0x8
  29. GNU_EH_FRAME 0x0000000000002024 0x0000000000402024 0x0000000000402024
  30. 0x000000000000004c 0x000000000000004c R 0x4
  31. GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
  32. 0x0000000000000000 0x0000000000000000 RW 0x10
  33. GNU_RELRO 0x0000000000002e10 0x0000000000403e10 0x0000000000403e10
  34. 0x00000000000001f0 0x00000000000001f0 R 0x1
  35. Section to Segment mapping:
  36. Segment Sections...
  37. 00
  38. 01 .interp
  39. 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
  40. 03 .init .plt .plt.sec .text .fini
  41. 04 .rodata .eh_frame_hdr .eh_frame
  42. 05 .init_array .fini_array .dynamic .got .got.plt .data .bss
  43. 06 .dynamic
  44. 07 .note.gnu.property
  45. 08 .note.gnu.build-id .note.ABI-tag
  46. 09 .note.gnu.property
  47. 10 .eh_frame_hdr
  48. 11
  49. 12 .init_array .fini_array .dynamic .got
  • 这里一共生成了13个segment,其中第0个segment对应PHDR,第1个segment对应INTERP,第2个segment对应LOAD,以此类推,第13个segment对应GNU_RELRO。
  • 第0个segment(PHDR)保存了各个segment的VirtAddr和MemSiz。
  • 第1个segment是只读的,只保存了.interp section。
  • 第2个segment就是我们常说的一个可执行文件的代码段,这部分是要由加载器加载到内存中执行的,因此其属性是可读可执行的,保存了.interp .note.ABI-tag .note.gnu.build-id ... 等section。
  • 第5个segment是我们常说的数据段,它保存了和可执行程序执行过程相关的所有数据,这部分也是要加载到内存中的,因此其属性是可读可写的,保存了.init_array .fini_array ...等section。
  • 第6个segment是可读可写的,保存了.dynamic section。
  • 第8个segment是只读的,保存了.note.gnu.build-id .note.ABI-tag这两个section。
  • 第10个segment是只读的,保存了.eh_frame_hdr section。
  • 第11个segment是可读可写的,它告诉系统,当加载这个可执行文件的时候,如何设置其栈。
  • 第12个segment是只读的,保存了.init_array .fini_array .dynamic .got这几个section。

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/160660
推荐阅读
相关标签
  

闽ICP备14008679号