文章目录

  • 前言
  • gemfield.c 代码
  • 第一步:编译。
  • 第二步:有关可执行文件。
  • 第三步:什么是ELF格式?
  • 第四步:ELF头
  • 第五步、ELF文件中的节头表 节头表的作用是什么呢?
  • 第六步、摘选几个节来研究下
    • 第一部分、节头字符串表(节,.shstrtab)
    • 第二部分、字符串表(节,.strtab)
    • 第三部分、代码节(.text)
    • 第四部分:符号表(.symtab)
  • 第七步、程序头表(Program header table)
  • 第八步、摘录一个段的内容进行分析
  • 第九步:readelf工具

前言

本想写一下程序和进程之间,以及线程和进程之间的关联和使用操作,然后看了网上一些文章,觉得如果从0到1的记录,可能效果会更好,所以此篇博客将详细讲述一个可执行文件是如何形成的,它和代码之间的故事又是怎么样的,下面将详细揭露。

一段程序gemfield本文 可能对你的编码能力不会产生影响,也可能对提高你的社会地位起不到任何帮助,但世界上总有一些事务是为改变你的世界观而诞生的——就像gemfield本文《从代码到可执行文件》 。

gemfield.c 代码

正如题目所说的那样,我们得先从一段程序代码开始——gemfield.c

又正如程序的名字所说的,这是个c语言文件,极其简单。

 int main(int argc,char *argv[]){ int a = 0; char gemfield[32]; printf(“input gemfield’s blog: “); scanf(“%s”,gemfield); printf(“gemfield’s blog is %s\n”,gemfield); }

正如代码量所揭示的,这真的是个简单的c程序,但 gemfield 还是要强调一点——main函数书写的规范性。 从 gemfield.c 的代码可以看出:

  1. main函数是有返回值的,为int型,操作系统可以感知这个值。
  2. main函数的第一个参数 argc,是argument count的缩写,意思是参数数量;
  3. main函数的第二个参数 argv,是argument vector的缩写,意思是存放参数的vector。

下面的研究步骤展示了从程序(gemfield.c)代码到可执行文件(gemfield)的一步步变化。

第一步:编译。

 gcc gemfield.c -o gemfield

可执行文件gemfield在GCC的帮助下诞生了。那么这个gemfield文件究竟是什么?

第二步:有关可执行文件。

objdump -f gemfield 输出:

gemfield: file format elf32-i386 architecture: i386,
flags 0×00000112: EXEC_P, HAS_SYMS, D_PAGED start address 0x080483d0

上面的信息明确的告诉我们,gemfield文件是 elf 可执行文件格式(什么是elf可执行格式?看第四步!),起始地址是 0x080483d0(这个地址是什么含意?看第六步中的第三部分!)。先了解这么多吧,下文或许继续会有新发现。

第三步:什么是ELF格式?

ELF是 “Executable and Linking Format” 首字母的缩写,也就是上文中gemfield这个可执行文件的格式。这种格式主要用于UNIX家族中。对于本文的讨论,将关注ELF的三大部分:

  1. ELF头

  2. 节(section)头表

  3. 程序头表

一个ELF文件(比如gemfield)是由若干个 Segment 构成的。有些 Segment 需要被装入、即被映射到用户空间,有些则不需要被装入(只有类型为 PT_LOADSegment 才需要被装入,参考第七部分)。所以,ELF文件被操作系统装入的过程只 “管” 到Segment为止。

而从ELF文件的动态连接、重定位(即浮动)、和启动运行的角度看,ELF文件是由若干个“节(Section)”构成的。我们通常所说映像中的“代码段”、“数据段”等等都是Section。所以,动态连接和启动运行的过程所涉及的则是Section。

一个Segment可以包含多个Section。其实,Segment和Section都是从操作/处理 的角度对ELF的划分;对于不同的操作/处理,划分的方式也就可以不同。

第四步:ELF头

我们首先关注ELF文件头格式,因为 ELF文件头(header)位于文件的最开始处,包含整个文件(如gemfield 可执行文件)的结构信息(使用二进制编辑器察看可执行文件的数据,gemfield 直接使用 Qt creator 就可以查看 gemfield 文件了):

typedef struct { unsigned char e_ident[16]; /* Magic number and other info */ Elf32_Half e_type; /* Object file type */ Elf32_Half e_machine; /* Architecture */ Elf32_Word e_version; /* Object file version */ Elf32_Addr e_entry; /* Entry point virtual address*/ Elf32_Off e_phoff; /* Program header table file offset */ Elf32_Off e_shoff; /*Section header table file offset */ Elf32_Word e_flags; /* Processor-specific flags */ Elf32_Half e_ehsize; /* ELF header size in bytes */ Elf32_Half e_phentsize; /* Program header table entry size */ Elf32_Half e_phnum; /* Program header table entry count */ Elf32_Half e_shentsize; /* Section header table entry size */ Elf32_Half e_shnum; /* Section header table entry count */ Elf32_Half e_shstrndx;/* Section header string table index */
} Elf32_Ehdr;//52个字节
  1. e_ident 数组,16个字节。 1、前4个字节被称为魔数,值是固定的,并且是:0x7f,’E’,’L’,’F’。表明这是个ELF文件; 2、第5个字节有三种值:0,非法目标文件;1,32位目标文件;2,64位目标文件。 3、第6个字节指定编码格式,有3种值:0,非法编码;1,LSB编码(小端格式);2,MSB编码(大端格式)。 4、第7个字节指定ELF头版本,值为1; 5、第8~16为保留字节,默认填充零; 可执行文件gemfield的此处值是:7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00

  2. e_type,2个字节,指明文件类型:

    1. 未知文件类型;
    2. 可重定位文件;
    3. 可执行文件;
    4. 动态链接库文件;
    5. Core 文件;0xff00,特定处理器文件扩展下边界 ;0xffff 特定处 理器文件扩展上边界 。

    可执行文件gemfield的此处值是:02 00。

  3. e_machine,2个字节,指明cpu架构:如intel的是3,其他的去CivilNet BBS上自行查找;可执行文件gemfield的此处值是:03 00。

  4. e_version,4个字节,指明版本:0,非法版本号;1,当前版本号;可执行文件gemfield的此处值是:01 00 00 00。

  5. e_entry,4个字节,程序入口的虚拟地址;可执行文件gemfield的此处值是:d0 83 04 08。

  6. e_phoff,4个字节,程序头表在文件中的偏移量;可执行文件gemfield的此处值是:34 00 00 00。

  7. e_shoff,4个字节,节头表的起始地址;可执行文件gemfield的此处值是:44 11 00 00。

  8. e_flags,4个字节,处理器特定标志位,intel为0;可执行文件gemfield的此处值是:00 00 00 00。

  9. e_ehsize,2个字节,ELF文件头大小(52字节);可执行文件gemfield的此处值是:34 00。

  10. e_phentsize,2个字节,程序头表中每一个表项的大小;可执行文件gemfield的此处值是:20 00。

  11. e_phnum,2个字节,程序头表中表项的数目;可执行文件gemfield的此处值是:09 00。

  12. e_shentsize,2个字节,节头表中每一个表项的大小(40个字节);可执行文件gemfield的此处值是:28 00。

  13. e_shnum,2个字节,节头表中的表项的数目;可执行文件gemfield的此处值是:1e 00。

  14. e_shstrndx,2个字节,Section header string table index(节头字符串表的索引);可执行文件gemfield的此处值是:1b 00。

第五步、ELF文件中的节头表 节头表的作用是什么呢?

gemfield 这样的可执行文件里,包含了多个节,其中每个节的信息都登记在这个节头表中(30个),用一个 Elf32_Shdr 结构体来描述:

typedef struct {  Elf32_Word sh_name; //本节的名字。 Elf32_Word sh_type; //类型。 Elf32_Word sh_flags ;  Elf32_Addr sh_addr; Elf32_Off  sh_offset;  Elf32_Word sh_size;  Elf32_Word sh_link;  Elf32_Word sh_info;  Elf32_Word sh_addralign;  Elf32_Word sh_entsize;
} Elf32_Shdr; //刚好4×10=40个字节。
  1. sh_name 存放的是个索引号,指向“字符串表”中的相对位置。在字符串中才有真正的以“\0”结束的字符串。

  2. sh_type 类型值:

    SHT_NULL 0 //无效的节头
    SHT_PROGBITS 1 //程序定义
    SHT_SYMTAB 2 //完整的符号表,往往会包含很多在运行期间( 动态连接) 用不到的符号
    SHT_STRTAB 3 //表明本节是字符串表
    SHT_RELA 4 //重定位节
    SHT_HASH 5 //符号哈希表
    SHT_DYNAMIC 6 //本节包含的是动态连接信息
    SHT_NOTE 7 //本节包含的信息用于以某种方式来标记本文件
    SHT_NOBITS 8 //这一节的内容是空的
    SHT_REL 9 //一个重定位节,含有带明确加数的重定位项
    SHT_SHLIB 0xa //一个保留值,暂未指定语义
    SHT_DYNSYM 0xb //本节是符号表,含有一个较小的符号表,专门用于动态连接
    SHT_LOPROC 0×70000000 //为特殊处理器保留的节类型索引值的下边界
    SHT_HIPROC 0x7fffffff //为特殊处理器保留的节类型索引值的上边界
    SHT_LOUSER 0×80000000 //为应用程序保留节类型索引值的下边界
    SHT_HIUSER 0xffffffff //为应用程序保留节类型索引值的下边界
    
  3. sh_flags , 本节的一些属性,各个位定义了节的不同属性,当某种属性被设置时,相应的标志位被设为1,反之则设为0。未定义的标志位被全部置0。 类型值:

     SHF_WRITE 0×1 //表示本节所包含的内容在进程运行过程中是可写的 SHF_ALLOC 0×2 //表示本节内容在进程运行过程中要占用内存单元 SHF_EXECINSTR 0×4 //表示此节内容是指令代码 SHF_MASHPROC 0xf0000000 //所有被此值所覆盖的位都是保留做特殊处理器扩展用的
    
  4. sh_addr, 如果本节的内容需要映射到进程空间中去,此成员指定映射的起始地址;如果不需要映射,此值为0。

  5. sh_offset, 指明了本节所在的位置,该值是节的第一个字节在文件中的位置,即相对于文件开头的偏移量。单位是字节。如果该节的类型为 SHT_NOBITS 的话,表明这一节的内容是空的,节并不占用实际 的空间,这时 sh_offset 只代表一个逻辑上的位置概念,并不代表实际的内容。

  6. sh_size, 指明节的大小,单位是字节。如果该节的类型为 SHT_NOBITS,此值仍然可能为非零,但没有实际的意义。

  7. sh_link, 此成员是一个索引值,指向节头表中本节所对应的位置。根据节的类型不同,本成员的意义也有所不同。

  8. sh_info, 此成员含有此节的附加信息,根据节的类型不同,本成员的意义也有所不同。 对于某些节类型来说,sh_link 和sh_info 含有特殊的信息。

    sh_type sh_link sh_info  SHT_DYNAMIC //用于本节中项目的字符串表在节头表中相应的索引值 0
    SHT_HASH //用于本节中哈希表的符号表在节头表中相应的索引值 0
    SHT_REL/SHT_RELA //相应符号表在节头表中的索引值 本重定位节所应用到目标节在节头表中的索引值
    SHT_SYMTAB/SHT_DYNSYM //相关字符串表的节头索引 符号表中最后一个本地符号的索引值加1
    其它 SHN_UNDEF 0
    
  9. sh_addralign, 此成员指明本节内容如何对齐字节,即该节的地址应该向多少个字节对齐。比如,在这个节中如果含有一个双字(doubleword) ,系统必须保证整个节的内容向双字对齐。也就是说,本节内容在进程空间中的映射地址sh_addr必须是一个向sh_addralign对齐,即能被 sh_addralign 整除的值。目前,sh_addralign 只能取0、1或者2 的正整数倍。如果该值为0 或1,表明本节没有字节对齐约束。

  10. sh_entsize, 有一些节的内容是一张表,其中每一个表项的大小是固定的,比如符号表。对于这种表来说,本成员指定其每一个表项的大小。如果此值为0 ,则表明本节内容不是这种表格。

    e_shoff处我们知道这个节头表起始地址是:0×1144,表中有0x1e项(e_shnum),每一项大小40个字节(e_shentsize)。那么这个节头表的大小为30×40=1200个字节(0x4b0),因此,节头表的地址范围是:0×1144~0x15f3。数据摘录如下:

    //空节 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00
    //.interp 1b 00 00 00 01 00 00 00 02 00 00 00 54 81 04 08 54 01 00 00  13 00 00 00 00               00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
    //.note.ABI-tag 23 00 00 00 07 00 00 00 02 00 00 00 68 81 04 08 68 01 00 00 20 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    //.note.gnu.build-id 31 00
    00 00 07 00 00 00 02 00 00 00 88 81 04 08 88 01 00 00  24 00 00 00 00 00 00 00 00 00
    00 00 04 00 00 00 00 00 00 00
    //.gnu.hash 44 00 00 00 f6 ff ff 6f 02 00 00 00 ac 81
    04 08 ac 01 00 00  20 00 00 00 05 00 00 00 00 00 00 00 04 00 00 00 04 00 00 00
    //.dynsym 4e 00 00 00 0b 00 00 00 02 00 00 00 cc 81 04 08 cc 01 00 00  70 00 00 00 06 00 00 00 01 00 00 00 04 00 00 00 10 00 00 00
    //.dynstr 56 00 00 00 03 00 00 00 02 00 00 00 3c 82 04 08 3c 02 00 00  80 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
    //.gnu.version 5e 00 00 00 ff ff ff 6f 02 00 00 00 bc 82 04 08 bc 02 00 00  0e 00
    00 00 05 00 00 00 00 00 00 00 02 00 00 00 02 00 00 00
    //.gnu.version_r  6b 00 00 00 fe ff ff 6f 02 00 00 00 cc 82 04 08 cc 02 00 00  40 00 00 00 06 00 00 00 01 00 00 00 04 00 00 00 00 00 00 00
    //.rel.dyn  7a 00 00 00 09 00 00 00 02 00 00 00 0c 83 04 08 0c 03 00 00  08 00 00 00 05 00 00 00 00 00 00 00 04 00 00 00 08 00 00 00
    //.rel.plt  83 00 00 00 09 00 00 00 02 00 00 00 14 83 04 08 14 03 00 00  28 00 00 00 05 00 00 00 0c 00 00 00 04 00 00 00 08 00 00 00
    //.init  8c 00 00 00 01 00 00 00 06 00 00 00 3c 83 04 08 3c 03 00 00  2e 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 .plt 87 00 00 00 01 00 00 00 06 00 00 00 70 83 04 08 70 03 00 00  60 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 04 00 00 00
    //.text  92 00 00 00 01 00 00 00 06 00 00 00 d0 83 04 08 d0 03 00 00 dc 01 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00
    //.fini 98 00 00 00 01 00 00 00 06 00 00 00 ac 85 04 08 ac 05 00 00  1a 00 00 00 00
    00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    //.rodata 9e 00 00 00 01 00 00 00 02 00 00 00 c8 85 04 08 c8 05 00 00  3b 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    //.eh_frame_hdr  a6 00 00 00 01 00 00 00 02 00 00 00 04 86 04 08 04 06 00 00  34 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    //.eh_frame  b4 00 00 00 01 00 00 00 02 00 00 00 38 86 04 08 38 06 00 00  c4 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    //.ctors  be 00 00 00 01 00 00 00 03 00 00 00 14 9f 04 08 14 0f 00 00  08 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    //.dtors c5 00 00 00 01 00 00 00 03 00 00 00 1c 9f 04 08 1c 0f 00 00  08 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    //.jcr cc 00 00 00 01 00 00 00 03 00 00 00 24 9f 04 08 24 0f 00 00  04 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    //.dynamic d1 00 00 00 06 00 00 00 03 00 00 00 28 9f 04 08 28 0f 00 00  c8 00 00 00
    06 00 00 00 00 00 00 00 04 00 00 00 08 00 00 00
    //.got da 00 00 00 01 00 00 00 03 00 00 00 f0 9f 04 08 f0 0f 00 00  04 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 04 00 00 00
    //.got.plt df 00 00 00 01 00 00 00 03 00 00 00 f4 9f 04 08 f4 0f 00 00 20 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 04 00 00 00
    //.data  e8 00 00 00 01 00 00 00 03 00 00 00 14 a0 04 08 14 10 00 00  08 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    //.bss ee 00 00 00 08 00 00 00 03 00 00 00 1c a0 04 08 1c 10 00 00 08 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    //.comment f3 00 00 00 01 00 00 00 30 00 00 00 00 00 00 00 1c 10 00 00  2a 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00
    //.shstrtab 11 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 46 10 00 00  fc 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
    //.symtab 01 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 f4 15 00 00  30 04 00 00 1d 00 00 00 2d 00 00 00 04 00 00 00 10 00 00 00
    //.strtab 09 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 24 1a 00 00  32 02 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
    

第六步、摘选几个节来研究下

那我们就摘选出4个关键的节来探讨一下:节头字符串表(节)、字符串表(节)、代码节、符号表(节)。

第一部分、节头字符串表(节,.shstrtab)

一个明显的疑问就是:一个可执行文件(gemfield)中可能会有多个字符串节区,怎么确定哪个就是和sh_name 这个索引相关的字符串表呢(也就是节名字表(.shstrtab))?谜底就在本文开始介绍 的第一个结构体中。e_shstrndx代表了该字符串表的索引,该值为:0x1b。上面不是说gemfield中一共有0x1e个节区吗,那么这个特殊的字符串表就是第0x1b个,起始地址就应该是:0×1144+ (0x1b)*0×28 = 0×1554。从gemfield中把这它复制出来,如下:

11 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 46 10 00 00 fc 00 00 00 00
00 00 00 00 00 00 00 01 00 00 00 00 00 00 00

从中我们可以看出,起始地址(偏移)是0×1046,大小是0xfc,也就是这个特定的字符串表的地址范围是:0×1046 ~ 0×1141

我们再从gemfield文件中把0×1046 ~ 0×1141处的数据拿出来,如下:

00 2e 73 79 6d 74 61 62 00 2e 73 74 72 74 61 62 00 2e 73 68 73 74 72 74 61 62 00 2e 69 6e
74 65 72 70 00 2e 6e 6f 74 65 2e 41 42 49 2d 74 61 67 00 2e 6e 6f 74 65 2e 67  6e 75 2e
62 75 69 6c 64 2d 69 64 00 2e 67 6e 75 2e 68 61 73 68 00 2e 64 79 6e 73 79 6d 00 2e 64 79
6e 73 74 72 00 2e 67 6e 75 2e 76 65 72 73 69 6f 6e 00 2e 67 6e 75 2e  76 65 72 73 69 6f
6e 5f 72 00 2e 72 65 6c 2e 64 79 6e 00 2e 72 65 6c 2e 70 6c 74 00 2e 69 6e 69 74 00 2e 74
65 78 74 00 2e 66 69 6e 69 00 2e 72 6f 64 61 74 61 00 2e 65  68 5f 66 72 61 6d 65 5f 68
64 72 00 2e 65 68 5f 66 72 61 6d 65 00 2e 63 74 6f 72 73 00 2e 64 74 6f 72 73 00 2e 6a 63
72 00 2e 64 79 6e 61 6d 69 63 00 2e 67 6f 74 00 2e  67 6f 74 2e 70 6c 74 00 2e 64 61 74
61 00 2e 62 73 73 00 2e 63 6f 6d 6d 65 6e 74 00

既然上面的是字符串表,那么我再把它翻译成ASCII字符的形式:

symtab .strtab .shstrtab .interp .note.ABI-tag .note.gnu.build-id .gnu.hash
.dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .text .fini
.rodata  .eh_frame_hdr .eh_frame .ctors .dtors .jcr .dynamic .got .got.plt .data
.bss .comment

从这些熟悉的名字中,我们已经知道了 gemfield 中包含的各种各样的节区的名字了。这些节区的属性如下:

名字 类型 属性
.bss SHT_NOBITS SHF_ALLOC+SHF_WRITE
.comment SHT_PROGBITS
.data SHT_PROGBITS SHF_ALLOC+SHF_WRITE
.data1 SHT_PROGBITS SHF_ALLOC+SHF_WRITE
.debug SHT_PROGBITS
.dynamic SHT_DYNAMIC 见下文
.dynstr SHT_STRTAB SHF_ALLOC
.dynsym SHT_DYNSYM SHF_ALLOC
.fini SHT_PROGBITS SHF_ALLOC + SHF_EXECINSTR
.got SHT_PROGBITS SHF_ALLOC + SHF_WRITE
.hash SHT_HASH SHF_ALLOC
.init SHT_PROGBITS SHF_ALLOC + SHF_EXECINSTR
.interp SHT_PROGBITS 见下文
.line SHT_PROGBITS
.note SHT_NOTE
.plt SHT_PROGBITS SHF_ALLOC + SHF_EXECINSTR
.relname SHT_REL 见下文
.relaname SHT_RELA 见下文
.rodata SHT_PROGBITS SHF_ALLOC
.rodata1 SHT_PROGBITS SHF_ALLOC
.shstrtab SHT_STRTAB
.strtab SHT_STRTAB 见下文
.symtab SHT_SYMTAB 见下文
.text SHT_PROGBITS SHF_ALLOC + SHF_EXECINSTR
  1. .bss 本节中包含目标文件中未初始化的全局变量。一般情况下,可执行程序在开始运行的时候,系统会把这一段内容清零。但是,在运行期间的bss段是由系统初始化而成的,在目标文件中.bss 节并不包含任何内容,其长度为0,所以它的节类型为SHT_NOBITS
  2. .comment 本节包含版本控制信息。
  3. .data/.data1 这两个节用于存放程序中被初始化过的全局变量。在目标文件中,它们是占用实际的存储空间的,与.bss 节不同。
  4. .debug 本节中含有调试信息,内容格式没有统一规定。所有以 ”.debug” 为前缀的节名字都是保留的。
  5. .dynamic 本节包含动态连接信息,并且可能有SHF_ALLOC 和SHF_WRITE 等属性。是否具有SHF_WRITE 属性取决于操作系统和处理器。
  6. .dynstr 此节含有用于动态连接的字符串,一般是那些与符号表相关的名字。
  7. .dynsym 此节含有动态连接符号表。
  8. .fini 此节包含进程终止时要执行的程序指令。当程序正常退出时,系统会执行这一节中的代码。
  9. .got 此节包含全局偏移量表。
  10. .hash 本节包含一张符号哈希表。
  11. .init 此节包含进程初始化时要执行的程序指令。当程序开始运行时,系统会在进入主函数之前执行这一节中的代码。
  12. .interp 此节含有ELF 程序解析器的路径名。如果此节被包含在某个可装载的段中,那么本节的属性中应置SHF_ALLOC 标志位,否则不置此标志。
  13. .line 本节也是一个用于调试的节,它包含那些调试符号的行号,为程序指令码与源文件的行号建立起联系。其内容格式没有统一规定。
  14. .note 注释节(note section)。
  15. .plt 此节包含函数连接表。
  16. .relname 和.relaname 这两个节含有重定位信息。如果此节被包含在某个可装载的段中,那么本节的属性中应置 SHF_ALLOC 标志位,否则不置此标志。注意,这两个节的名字中”name”是可替换的部分,执照惯例 ,对哪一节做重定位就把”name”换成哪一节的名字。比如,.text 节的重定位节的名字将是.rel.text 或.rela.text 。
  17. .rodata/.rodata1 本节包含程序中的只读数据,在程序装载时,它们一般会被装入进程空间中那些只读的段中去。
  18. .shstrtab 本节是“节名字表”,含有所有其它节的名字。
  19. .strtab 本节用于存放字符串,主要是那些符号表项的名字。如果一个目标文件有一个可装载的段,并且其中含有符号表,那么本节的属性中应该有SHF_ALLOC 。
  20. .symtab 本节用于存放符号表。如果一个目标文件有一个可载入的段,并且其中含有符号表,那么本节的属性中应该有SHF_ALLOC
  21. .text 本节包含程序指令代码。

以点号 ”.” 为前缀的节名字是为系统保留的。应用程序也可以构造自己的段,但最好不要取与上述系统已定义的节相同的名字,也不要取以点号开头的名字,以避免潜在的冲突。注意,目标文件中节的名字并不具有唯一性,可以存在多个相同名字的节。

第二部分、字符串表(节,.strtab)

09 00 00 00 //.strtab
03 00 00 00 //3 ,表明本节是字符串表
00 00 00 00 //标志
00 00 00 00 //还没重定位,所以为0
24 1a 00 00 //起始地址:0x1a24
32 02 00 00 //大小 0×232
00 00 00 00
00 00 00 00
01 00 00 00 //对齐
00 00 00 00 //指向的不是表

根据上面的解析,把字符串表拿出来,地址为0x1a24~0x1c55:

 00 63 72 74 73 74 75 66 66 2e 63 00 5f 5f 43 54 4f 52 5f 4c 49 53 54 5f 5f 00 5f 5f 44 54 4f 52 5f 4c 49 53 54 5f 5f 00 5f 5f 4a 43 52 5f 4c 49 53 54 5f 5f 00 5f 5f 64  6f 5f 67 6c 6f 62 61 6c 5f 64 74 6f 72 73 5f 61 75 78 00 63 6f 6d 70 6c 65 74 65 64 2e 36 30 38 36 00 64 74 6f 72 5f 69 64 78 2e 36 30 38 38 00 66 72 61 6d 65 5f 64 75  6d 6d 79 00 5f 5f 43 54 4f 52 5f 45 4e 44 5f 5f 00 5f 5f 46 52 41 4d 45 5f 45 4e 44 5f 5f 00 5f 5f 4a 43 52 5f 45 4e 44 5f 5f 00 5f 5f 64 6f 5f 67 6c 6f 62 61 6c 5f 63  74 6f 72 73 5f 61 75 78 00 6c 65 61 66 2e 63 00 5f 5f 69 6e 69 74 5f 61 72 72 61 79 5f 65 6e 64 00 5f 44 59 4e 41 4d 49 43 00 5f 5f 69 6e 69 74 5f 61 72 72 61 79 5f 73  74 61 72 74 00 5f 47 4c 4f 42 41 4c 5f 4f 46 46 53 45 54 5f 54 41 42 4c 45 5f 00 5f 5f 6c 69 62 63 5f 63 73 75 5f 66 69 6e 69 00 5f 5f 69 36 38 36 2e 67 65 74 5f 70 63  5f 74 68 75 6e 6b 2e 62 78 00 64 61 74 61 5f 73 74 61 72 74 00 70 72 69 6e 74 66 40 40 47 4c 49 42 43 5f 32 2e 30 00 5f 65 64 61 74 61 00 5f 66 69 6e 69 00 5f 5f 73 74  61 63 6b 5f 63 68 6b 5f 66 61 69 6c 40 40 47 4c 49 42 43 5f 32 2e 34 00 5f 5f 44 54 4f 52 5f 45 4e 44 5f 5f 00 5f 5f 64 61 74 61 5f 73 74 61 72 74 00 5f 5f 67 6d 6f 6e  5f 73 74 61 72 74 5f 5f 00 5f 5f 64 73 6f 5f 68 61 6e 64 6c 65 00 5f 49 4f 5f 73 74 64 69 6e 5f 75 73 65 64 00 5f 5f 6c 69 62 63 5f 73 74 61 72 74 5f 6d 61 69 6e 40 40  47 4c 49 42 43 5f 32 2e 30 00 5f 5f 6c 69 62 63 5f 63 73 75 5f 69 6e 69 74 00 5f 65 6e 64 00 5f 73 74 61 72 74 00 5f 66 70 5f 68 77 00 5f 5f 62 73 73 5f 73 74 61 72 74  00 6d 61 69 6e 00 5f 4a 76 5f 52 65 67 69 73 74 65 72 43 6c 61 73 73 65 73 00 5f 5f 69 73 6f 63 39 39 5f 73 63 61 6e 66 40 40 47 4c 49 42 43 5f 32 2e 37 00 5f 69 6e 69 74 00

既然是字符串表,那就翻译成ASCII字符串,如下:

crtstuff.c __CTOR_LIST__ __DTOR_LIST__ __JCR_LIST__ __do_global_dtors_aux completed.6086
dtor_idx.6088 frame_dummy __CTOR_END__ __FRAME_END__ __JCR_END__ __do_global_ctors_aux
leaf.c __init_array_end _DYNAMIC __init_array_start _GLOBAL_OFFSET_TABLE_ __libc_csu_fini__i686.get_pc_thunk.bx data_start printf@@GLIBC_2.0 _edata _fini __stack_chk_fail@@GLIBC_2.4 __DTOR_END__ __data_start __gmon_start__ __dso_handle _IO_stdin_used __libc_start_main@@GLIBC_2.0 __libc_csu_init _end _start _fp_hw __bss_start main _Jv_RegisterClasses __isoc99_scanf@@GLIBC_2.7 _init

仔细看看上面的字符串,我们会发现我们定义的全局变量和函数的名字都在这里,像printf、scanfmain等。但是 printf() 函数调用中用到的字符串(像 ”input gemfield’s blog:” )却没有发现,它们被定义在 .rodata 节中,因为它们是字符串常量。

第三部分、代码节(.text)

数据如下:

92 00 00 00 //.text
01 00 00 00 //1 ,程序定义
06 00 00 00 //表示此节内容是指令代码,并且要使用内存单元
d0 83 04 08 //代码映射到虚拟内存中的起始地址,为0x080483d0,记住这个数字。
d0 03 00 00 //在gemfield中的偏移地址 0x03d0
dc 01 00 00 //大小 0x1dc个字节
00 00 00 00 // 00 00 00 00
10 00 00 00 //对齐
00 00 00 00 //指向的不是表

我们把这个代码段的数据拿出来,地址为0x3d0~0x5ab,如下:

31 ed 5e 89 e1 83 e4 f0 50 54 52 68 70 85 04 08 68 00 85 04 08 51 56 68 84 84 04 08 e8 bf
ff ff ff f4 90 90 90 90 90 90 90 90 90 90 90 90 90 90 55 89 e5 53 83 ec 04 80  3d 1c a0
04 08 00 75 3f a1 20 a0 04 08 bb 20 9f 04 08 81 eb 1c 9f 04 08 c1 fb 02 83 eb 01 39 d8 73
1e 8d b6 00 00 00 00 83 c0 01 a3 20 a0 04 08 ff 14 85 1c 9f 04 08 a1  20 a0 04 08 39 d8
72 e8 c6 05 1c a0 04 08 01 83 c4 04 5b 5d c3 8d 74 26 00 8d bc 27 00 00 00 00 55 89 e5 83
ec 18 a1 24 9f 04 08 85 c0 74 12 b8 00 00 00 00 85 c0 74 09  c7 04 24 24 9f 04 08 ff d0
c9 c3 90 55 89 e5 83 e4 f0 83 ec 50 8b 45 0c 89 44 24 1c 65 a1 14 00 00 00 89 44 24 4c 31
c0 c7 44 24 28 00 00 00 00 b8 d0 85 04 08 89 04 24  e8 cb fe ff ff b8 e8 85 04 08 8d 54
24 2c 89 54 24 04 89 04 24 e8 f6 fe ff ff b8 eb 85 04 08 8d 54 24 2c 89 54 24 04 89 04 24
e8 a1 fe ff ff 8b 54 24 4c 65 33 15 14 00  00 00 74 05 e8 9f fe ff ff c9 c3 90 90 90 90
90 90 90 90 90 90 90 90 90 55 57 56 53 e8 69 00 00 00 81 c3 eb 1a 00 00 83 ec 1c 8b 6c 24
30 8d bb 20 ff ff ff e8 1b fe ff  ff 8d 83 20 ff ff ff 29 c7 c1 ff 02 85 ff 74 29 31 f6
8d b6 00 00 00 00 8b 44 24 38 89 2c 24 89 44 24 08 8b 44 24 34 89 44 24 04 ff 94 b3 20 ff
ff ff 83 c6 01 39 fe 75  df 83 c4 1c 5b 5e 5f 5d c3 eb 0d 90 90 90 90 90 90 90 90 90 90
90 90 90 f3 c3 8b 1c 24 c3 90 90 90 90 90 90 90 90 90 90 55 89 e5 53 83 ec 04 a1 14 9f 04
08 83 f8 ff 74  13 bb 14 9f 04 08 66 90 83 eb 04 ff d0 8b 03 83 f8 ff 75 f4 83 c4 04 5b
5d c3 90 90

我们使用反汇编 objdump –disassemble gemfield,输出如下:

Disassembly of section .text
080483d0 <_start>: 80483d0: 31 ed xor %ebp,%ebp 80483d2: 5e pop %esi 80483d3: 89 e1 mov %esp,%ecx 80483d5: 83 e4 f0 and $0xfffffff0,%esp 80483d8: 50 push %eax 80483d9: 54 push
%esp 80483da: 52 push %edx 80483db: 68 70 85 04 08 push $0×8048570 80483e0: 68 00 85 04
08 push $0×8048500 80483e5: 51 push %ecx 80483e6: 56 push %esi 80483e7: 68 84 84 04 08
push $0×8048484 80483ec: e8 bf ff ff ff call 80483b0 <__libc_start_main@plt> 80483f1: f4
hlt  80483f2: 90 nop 80483f3: 90 nop 80483f4: 90 nop 80483f5: 90 nop 80483f6: 90 nop
80483f7: 90 nop 80483f8: 90 nop 80483f9: 90 nop 80483fa: 90 nop 80483fb: 90 nop 80483fc:
90 nop 80483fd: 90 nop 80483fe: 90 nop 80483ff: 90 nop08048400 <__do_global_dtors_aux>: 8048400: 55 push %ebp 8048401: 89 e5 mov %esp,%ebp
8048403: 53 push %ebx 8048404: 83 ec 04 sub $0×4,%esp 8048407: 80 3d 1c a0 04 08 00 cmpb
$0×0,0x804a01c 804840e: 75 3f jne 804844f <__do_global_dtors_aux+0x4f> 8048410: a1 20 a0
04 08 mov 0x804a020,%eax 8048415: bb 20 9f 04 08 mov $0x8049f20,%ebx 804841a: 81 eb 1c 9f
04 08 sub $0x8049f1c,%ebx 8048420: c1 fb 02 sar $0×2,%ebx 8048423: 83 eb 01 sub $0×1,%ebx
8048426: 39 d8 cmp %ebx,%eax 8048428: 73 1e jae 8048448 <__do_global_dtors_aux+0×48>
804842a: 8d b6 00 00 00 00 lea 0×0(%esi),%esi 8048430: 83 c0 01 add $0×1,%eax 8048433: a3
20 a0 04 08 mov %eax,0x804a020 8048438: ff 14 85 1c 9f 04 08 call *0x8049f1c(,%eax,4)
804843f: a1 20 a0 04 08 mov 0x804a020,%eax 8048444: 39 d8 cmp %ebx,%eax 8048446: 72 e8 jb
8048430 <__do_global_dtors_aux+0×30> 8048448: c6 05 1c a0 04 08 01 movb $0×1,0x804a01c
804844f: 83 c4 04 add $0×4,%esp 8048452: 5b pop %ebx 8048453: 5d pop %ebp 8048454: c3
ret  8048455: 8d 74 26 00 lea 0×0(%esi,%eiz,1),%esi 8048459: 8d bc 27 00 00 00 00 lea
0×0(%edi,%eiz,1),%edi08048460 <frame_dummy>: 8048460: 55 push %ebp 8048461: 89 e5 mov %esp,%ebp 8048463: 83 ec
18 sub $0×18,%esp 8048466: a1 24 9f 04 08 mov 0x8049f24,%eax 804846b: 85 c0 test
%eax,%eax 804846d: 74 12 je 8048481 <frame_dummy+0×21> 804846f: b8 00 00 00 00 mov
$0×0,%eax 8048474: 85 c0 test %eax,%eax 8048476: 74 09 je 8048481 <frame_dummy+0×21>
8048478: c7 04 24 24 9f 04 08 movl $0x8049f24,(%esp) 804847f: ff d0 call *%eax 8048481:
c9 leave  8048482: c3 ret  8048483: 90 nop08048484 <main>: 8048484: 55 push %ebp 8048485: 89 e5 mov %esp,%ebp 8048487: 83 e4 f0 and
$0xfffffff0,%esp 804848a: 83 ec 50 sub $0×50,%esp 804848d: 8b 45 0c mov 0xc(%ebp),%eax
8048490: 89 44 24 1c mov %eax,0x1c(%esp) 8048494: 65 a1 14 00 00 00 mov %gs:0×14,%eax
804849a: 89 44 24 4c mov %eax,0x4c(%esp) 804849e: 31 c0 xor %eax,%eax 80484a0: c7 44 24
28 00 00 00 movl $0×0,0×28(%esp) 80484a7: 00  80484a8: b8 d0 85 04 08 mov $0x80485d0,%eax
80484ad: 89 04 24 mov %eax,(%esp) 80484b0: e8 cb fe ff ff call 8048380 <printf@plt>
80484b5: b8 e8 85 04 08 mov $0x80485e8,%eax 80484ba: 8d 54 24 2c lea 0x2c(%esp),%edx
80484be: 89 54 24 04 mov %edx,0×4(%esp) 80484c2: 89 04 24 mov %eax,(%esp) 80484c5: e8 f6
fe ff ff call 80483c0 <__isoc99_scanf@plt> 80484ca: b8 eb 85 04 08 mov $0x80485eb,%eax
80484cf: 8d 54 24 2c lea 0x2c(%esp),%edx 80484d3: 89 54 24 04 mov %edx,0×4(%esp) 80484d7:
89 04 24 mov %eax,(%esp) 80484da: e8 a1 fe ff ff call 8048380 <printf@plt> 80484df: 8b 54
24 4c mov 0x4c(%esp),%edx 80484e3: 65 33 15 14 00 00 00 xor %gs:0×14,%edx 80484ea: 74 05
je 80484f1 <main+0x6d> 80484ec: e8 9f fe ff ff call 8048390 <__stack_chk_fail@plt>
80484f1: c9 leave  80484f2: c3 ret  80484f3: 90 nop 80484f4: 90 nop 80484f5: 90 nop
80484f6: 90 nop 80484f7: 90 nop 80484f8: 90 nop 80484f9: 90 nop 80484fa: 90 nop 80484fb:
90 nop 80484fc: 90 nop 80484fd: 90 nop 80484fe: 90 nop 80484ff: 90 nop08048500 <__libc_csu_init>: 8048500: 55 push %ebp 8048501: 57 push %edi 8048502: 56 push
%esi 8048503: 53 push %ebx 8048504: e8 69 00 00 00 call 8048572 <__i686.get_pc_thunk.bx>
8048509: 81 c3 eb 1a 00 00 add $0x1aeb,%ebx 804850f: 83 ec 1c sub $0x1c,%esp 8048512: 8b
6c 24 30 mov 0×30(%esp),%ebp 8048516: 8d bb 20 ff ff ff lea -0xe0(%ebx),%edi 804851c: e8
1b fe ff ff call 804833c <_init> 8048521: 8d 83 20 ff ff ff lea -0xe0(%ebx),%eax 8048527:
29 c7 sub %eax,%edi 8048529: c1 ff 02 sar $0×2,%edi 804852c: 85 ff test %edi,%edi
804852e: 74 29 je 8048559 <__libc_csu_init+0×59> 8048530: 31 f6 xor %esi,%esi 8048532: 8d
b6 00 00 00 00 lea 0×0(%esi),%esi 8048538: 8b 44 24 38 mov 0×38(%esp),%eax 804853c: 89 2c
24 mov %ebp,(%esp) 804853f: 89 44 24 08 mov %eax,0×8(%esp) 8048543: 8b 44 24 34 mov
0×34(%esp),%eax 8048547: 89 44 24 04 mov %eax,0×4(%esp) 804854b: ff 94 b3 20 ff ff ff
call *-0xe0(%ebx,%esi,4) 8048552: 83 c6 01 add $0×1,%esi 8048555: 39 fe cmp %edi,%esi
8048557: 75 df jne 8048538 <__libc_csu_init+0×38> 8048559: 83 c4 1c add $0x1c,%esp
804855c: 5b pop %ebx 804855d: 5e pop %esi 804855e: 5f pop %edi 804855f: 5d pop %ebp
8048560: c3 ret  8048561: eb 0d jmp 8048570 <__libc_csu_fini> 8048563: 90 nop 8048564: 90
nop 8048565: 90 nop 8048566: 90 nop 8048567: 90 nop 8048568: 90 nop 8048569: 90 nop
804856a: 90 nop 804856b: 90 nop 804856c: 90 nop 804856d: 90 nop 804856e: 90 nop 804856f:
90 nop08048570 <__libc_csu_fini>: 8048570: f3 c3 repz ret08048572 <__i686.get_pc_thunk.bx>: 8048572: 8b 1c 24 mov (%esp),%ebx 8048575: c3 ret  8048576: 90 nop 8048577: 90 nop 8048578: 90 nop 8048579: 90 nop 804857a: 90 nop 804857b:
90 nop 804857c: 90 nop 804857d: 90 nop 804857e: 90 nop 804857f: 90 nop08048580 <__do_global_ctors_aux>: 8048580: 55 push %ebp 8048581: 89 e5 mov %esp,%ebp
8048583: 53 push %ebx 8048584: 83 ec 04 sub $0×4,%esp 8048587: a1 14 9f 04 08 mov
0x8049f14,%eax 804858c: 83 f8 ff cmp $0xffffffff,%eax 804858f: 74 13 je 80485a4
<__do_global_ctors_aux+0×24> 8048591: bb 14 9f 04 08 mov $0x8049f14,%ebx 8048596: 66 90 xchg %ax,%ax 8048598: 83 eb 04 sub $0×4,%ebx 804859b: ff d0 call *%eax 804859d: 8b 03 mov
(%ebx),%eax 804859f: 83 f8 ff cmp $0xffffffff,%eax 80485a2: 75 f4 jne 8048598
<__do_global_ctors_aux+0×18> 80485a4: 83 c4 04 add $0×4,%esp 80485a7: 5b pop %ebx
80485a8: 5d pop %ebp 80485a9: c3 ret  80485aa: 90 nop 80485ab: 90 nop

上面数据可以看出和我们自己解析的数据是完全匹配的。

第四部分:符号表(.symtab)

数据如下:

01 00 00 00 //.symtab
02 00 00 00 //完整的符号表,它往往会包含很多在运行期间( 动态连接) 用不到的符号。
00 00 00 00 //flag
00 00 00 00 //因为没有重定位,地址为0
f4 15 00 00 //在gemfield文件中的偏移:0x15f4
30 04 00 00 //大小:0×0430
1d 00 00 00 //相关字符串表的节头索引
2d 00 00 00 //符号表中最后一个本地符号的索引值加1
04 00 00 00 //对齐 4个字节
10 00 00 00 //指向的是表(没错,符号表),每一个表项大小为0×10个字节

数据摘录如下,地址范围为0x15f4~1a23,一共67项:

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  00 00 00 00 54 81 04 08 00 00 00 00 03
00 01 00  00 00 00 00 68 81 04 08 00 00 00 00 03 00 02 00  00 00 00 00 88 81 04 08 00 00
00 00 03 00 03 00  00 00 00 00 ac 81 04 08 00 00 00 00 03 00 04 00  00 00 00 00 cc 81 04
08 00 00 00 00 03 00 05 00  00 00 00 00 3c 82 04 08 00 00 00 00 03 00 06 00  00 00 00 00
bc 82 04 08 00 00 00 00 03 00 07 00  00 00 00 00 cc 82 04 08 00 00 00 00 03 00 08 00  00
00 00 00 0c 83 04 08 00 00 00 00 03 00 09 00  00 00 00 00 14 83 04 08 00 00 00 00 03 00
0a 00  00 00 00 00 3c 83 04 08 00 00 00 00 03 00 0b 00  00 00 00 00 70 83 04 08 00 00 00
00 03 00 0c 00  00 00 00 00 d0 83 04 08 00 00 00 00 03 00 0d 00  00 00 00 00 ac 85 04 08
00 00 00 00 03 00 0e 00  00 00 00 00 c8 85 04 08 00 00 00 00 03 00 0f 00  00 00 00 00 04
86 04 08 00 00 00 00 03 00 10 00  00 00 00 00 38 86 04 08 00 00 00 00 03 00 11 00  00 00
00 00 14 9f 04 08 00 00 00 00 03 00 12 00  00 00 00 00 1c 9f 04 08 00 00 00 00 03 00 13
00  00 00 00 00 24 9f 04 08 00 00 00 00 03 00 14 00  00 00 00 00 28 9f 04 08 00 00 00 00
03 00 15 00  00 00 00 00 f0 9f 04 08 00 00 00 00 03 00 16 00  00 00 00 00 f4 9f 04 08 00
00 00 00 03 00 17 00  00 00 00 00 14 a0 04 08 00 00 00 00 03 00 18 00  00 00 00 00 1c a0
04 08 00 00 00 00 03 00 19 00  00 00 00 00 00 00 00 00 00 00 00 00 03 00 1a 00  01 00 00
00 00 00 00 00 00 00 00 00 04 00 f1 ff  0c 00 00 00 14 9f 04 08 00 00 00 00 01 00 12 00
1a 00 00 00 1c 9f 04 08 00 00 00 00 01 00 13 00  28 00 00 00 24 9f 04 08 00 00 00 00 01
00 14 00  35 00 00 00 00 84 04 08 00 00 00 00 02 00 0d 00  4b 00 00 00 1c a0 04 08 01 00
00 00 01 00 19 00  5a 00 00 00 20 a0 04 08 04 00 00 00 01 00 19 00  68 00 00 00 60 84 04
08 00 00 00 00 02 00 0d 00  01 00 00 00 00 00 00 00 00 00 00 00 04 00 f1 ff  74 00 00 00
18 9f 04 08 00 00 00 00 01 00 12 00  81 00 00 00 f8 86 04 08 00 00 00 00 01 00 11 00  8f
00 00 00 24 9f 04 08 00 00 00 00 01 00 14 00  9b 00 00 00 80 85 04 08 00 00 00 00 02 00
0d 00  b1 00 00 00 00 00 00 00 00 00 00 00 04 00 f1 ff  b8 00 00 00 14 9f 04 08 00 00 00
00 00 00 12 00  c9 00 00 00 28 9f 04 08 00 00 00 00 01 00 15 00  d2 00 00 00 14 9f 04 08
00 00 00 00 00 00 12 00  e5 00 00 00 f4 9f 04 08 00 00 00 00 01 00 17 00  fb 00 00 00 70
85 04 08 02 00 00 00 12 00 0d 00  0b 01 00 00 72 85 04 08 00 00 00 00 12 02 0d 00  22 01
00 00 14 a0 04 08 00 00 00 00 20 00 18 00  2d 01 00 00 00 00 00 00 00 00 00 00 12 00 00
00  3f 01 00 00 1c a0 04 08 00 00 00 00 10 00 f1 ff  46 01 00 00 ac 85 04 08 00 00 00 00
12 00 0e 00  4c 01 00 00 00 00 00 00 00 00 00 00 12 00 00 00  68 01 00 00 20 9f 04 08 00
00 00 00 11 02 13 00  75 01 00 00 14 a0 04 08 00 00 00 00 10 00 18 00  82 01 00 00 00 00
00 00 00 00 00 00 20 00 00 00  91 01 00 00 18 a0 04 08 00 00 00 00 11 02 18 00  9e 01 00
00 cc 85 04 08 04 00 00 00 11 00 0f 00  ad 01 00 00 00 00 00 00 00 00 00 00 12 00 00 00
ca 01 00 00 00 85 04 08 61 00 00 00 12 00 0d 00  da 01 00 00 24 a0 04 08 00 00 00 00 10
00 f1 ff  df 01 00 00 d0 83 04 08 00 00 00 00 12 00 0d 00  e6 01 00 00 c8 85 04 08 04 00
00 00 11 00 0f 00  ed 01 00 00 1c a0 04 08 00 00 00 00 10 00 f1 ff  f9 01 00 00 84 84 04
08 6f 00 00 00 12 00 0d 00  fe 01 00 00 00 00 00 00 00 00 00 00 20 00 00 00  12 02 00 00
00 00 00 00 00 00 00 00 12 00 00 00  2c 02 00 00 3c 83 04 08 00 00 00 00 12 00 0b 00

符号表(symbol table) 所包含的信息用于定位和重定位程序中的符号定义和引用。目标文件的其它部分通过一个符号在这个表中的索引值来使用该符号。索引值从0 开始计数,但值为0 的表项(即第一项)并没有实际的意义,它表示未定义的符号。这里用常量 STN_UNDEF 来表示未定义的符号。

一个符号表项的格式定义如下:

 typedef struct {  Elf32_Word st_name; //符号的名字 Elf32_Addr st_value ; //符号的值 Elf32_Word st_size; //符号的大小 unsigned char st_info;  unsigned char st_other ;  Elf32_Half st_shndx ;  } Elf32_Sym;//恰好16个字节
  1. st_name,符号的名字。但它并不是一个字符串,而是一个指向字符串表(.strtab)的索引值,在字符串表中对应位置上的字符串就是该符号名字的实际文本。如果此值为非0,它代表符号名在字符串 表中的索引值。如果此值为0,那么此符号无名字。

  2. 符号的值,这个值其实没有固定的类型,它可能代表一个数值,也可以是一个地址,具体是什么要看上下文。对于不同的目标文件类型,符号表项的st_value 的含义略有不同:

    在重定位文件中,如果一个符号对应的节的索引值是SHN_COMMONst_value 值是这个节内容的字节对齐数。 在重定位文件中,如果一个符号是已定义的,那么它的st_value 值是该符号的起始地址在其所在节中的偏移量,而其所在的节的索引由st_shndx 给出。 *在可执行文件和共享库文件中,st_value 不再是一个节内的偏移量,而是一个虚拟地址,直接指向符号所在的内存位置。这种情况下,st_shndx就不再需要了。 如果一个可执行文件中含有一个函数的引用,而这个函数是定义在一个共享目标文件中,那么在可执行文件中,针对那个共享目标文件的符号表应该含有这个函数的符号。符号表的st_shndx 成员值为SHN_UNDEF ,这就告诉了动态连接器,这个函数的符号定义并不在可执行文件中。如果已经在可执行文件中给这个符号申请了一个函数连接表项,而且符号表项的st_value 成员不是 0,那么st_value值就将是函数连接表项中第一条指令的地址。否则,st_value 成员是0。这个函数连接表项地址被动态连接器用来解析函数地址。细节参见 http://civilnet.cn/bbs/topicno/71157 。

  3. st_size,符号的大小。各种符号的大小各不相同,比如一个对象的大小就是它实际占用的字节数。如果一个符号的大小为0 或者大小未知,则这个值为0。

  4. st_info,符号的类型和属性。st_info 由一系列的比特位构成,标识了“符号绑定(symbol binding) ”、“符号类型(symbol type) ”和“符号信息(symbol infomation)”三种属性。下面几个宏分 别用于读取这三种属性值。

    #define ELF32_ST_BIND( i ) ((i)>>4)
    #define ELF32_ST_TYPE( i ) ((i)&0xf)
    #define ELF32_ST_INFO( b,t ) (((b)<<4)+((t)&0xf))
    

    下面分别说明: 符号绑定(Symbol Binding) 属性由ELF32_ST_BIND指定。 名字值

    STB_LOCAL 0
    STB_GLOBAL 1
    STB_WEAK 2
    STB_LOPROC 13
    STB_HIPROC 15
    
    • STB_LOCAL 表明本符号是一个本地符号。它只出现在本文件中,在本文件外该符号无效。所以在不同的文件中可以定义相同的符号名,它们之间不会互相影响。

    • STB_GLOBAL 表明本符号是一个全局符号。当有多个文件被连接在一起时,在所有文件中该符号都是可见的。正常情况下,在一个文件中定义的全局符号,一定是在其它文件中需要被引用,否则无须定义为全局。

    • STB_WEAK 类似于全局符号,但是相对于STB_GLOBAL,它们的优先级更低。 全局符号(global symbol) 和弱符号(weak symbol) 在以下两方面有区别:
      当连接编辑器把若干个可重定位目标文件连接起来时,同名的STB_GLOBAL 符号不允许出现多次。而如果在一个目标文件中已经定义了一个全局的符号(global symbol) ,当一个同名的弱符 号(weak symbol) 出现时,并不会发生错误。连接编辑器会以全局符号为准,忽略弱符号。与全局符号相似,如果已经存在的是一个公用符号,即st_shndx 域为SHN_COMMON值的符号,当一个同名的弱符号(weak symbol) 出现时,也不会发生错误。连接编辑器会以公用符号为准,忽略弱符号。

      *在查找符号定义时,连接编辑器可能会搜索存档的库文件。如果是查找全局符号,连接编辑器会提取包含该未定义的全局符号的存档成员,存档成员可能是一个全局的符号,也可能是弱符号 ;而如果是查找弱符号,连接编辑器不会去提取存档成员。未解析的弱符号值为0。

      STB_LOPROC ~ STB_HIPROC 为特殊处理器保留的属性区间。 在符号表中,不同属性的符号所在位置也有不同,本地符号(STB_LOCAL)排在前面,全局符号(STB_GLOBAL/STB_WEAK) 排在后面。 符号类型(Symbol Types) 属性由ELF32_ST_TYPE 指定:
      名字值 :

       STT_NOTYPE 0  STT_OBJECT 1  STT_FUNC 2  STT_SECTION 3  STT_FILE 4  STT_LOPROC 13  STT_HIPROC 15
      
      • STT_NOTYPE 本符号类型未指定。
      • STT_OBJECT 本符号是一个数据对象,比如变量、数组等。
      • STT_FUNC 本符号是一个函数,或者其它的可执行代码。函数符号在共享目标文件中有特殊的意义。当另外一个目标文件引用一个共享目标文件中的函数符号时,连接编辑器为被引用符号自动创建一个连接表项。非STT_FUNC类型的共享目标符号不会通过这种连接表项被自动引用。
      • STT_SECTION 本符号与一个节相关联,用于重定位,通常具有STB_LOCAL 属性。
      • STT_FILE 本符号是一个文件符号,它具有STB_LOCAL 属性,它的节索引值是SHN_ABS。在符号表中如果存在本类符号的话,它会出现在所有STB_LOCAL 类符号的前部。
      • STT_LOPROC ~ STT_HIPROC 这一区间的符号类型为特殊处理器保留。
  5. st_other, 本数据成员目前暂未使用,在目标文件中一律赋值为0。

  6. st_shndx, 任何一个符号表项的定义都与某一个“节”相联系,因为符号是为节而定义,在节中被引用。本数据成员即指明了相关联的节。本数据成员是一个索引值,它指向相关联的节在节头表中的索引。在重定位过程中,节的位置会改变,本数据成员的值也随之改变,继续指向节的新位置。当本数据成员指向下面三种特殊的节索引值时,本符号具有如下特别的意义:

    SHN_ABS 符号的值是绝对的,具有常量性,在重定位过程中,此值不需要改变。 SHN_COMMON 本符号所关联的是一个还没有分配的公共节,本符号的值规定了其内容的字节对齐规则,与sh_addralign相似。也就是说,连接器会为本符号分配存储空间,而且其起始地址是向st_value 对 齐的。本符号的值指明了要分配的字节数。 SHN_UNDEF 当一个符号指向第1 节(SHN_UNDEF) 时,表明本符号在当前目标文件中未定义,在连接过程中,连接器会找到此符号被定义的文件,并把这些文件连接在一起。本文件中对该符号的引用会被连接到实际的定义上去。

第七步、程序头表(Program header table)

在gemfield中,程序头表的偏移是0×34,表中每一项(一个程序头)的大小是0×20,表项的数目是0×09,也就是程序头表的地址范围是:0×34~0×153,其中结束地址是通过0×34+0×20*0×09-1 的出来的。

那我们先从gemfield将这一块的数据拿出来:

06 00 00 00 34 00 00 00 34 80 04 08 34 80 04 08 20 01 00 00 20 01 00 00 05 00 00 00 04 00
00 00  03 00 00 00 54 01 00 00 54 81 04 08 54 81 04 08 13 00 00 00 13 00 00 00 04 00 00
00 01 00 00 00 01 00 00 00 00 00 00 00 00 80 04 08 00 80 04 08 fc 06 00 00 fc 06 00 00 05
00 00 00 00 10 00 00  01 00 00 00 14 0f 00 00 14 9f 04 08 14 9f 04 08 08 01 00 00 10 01
00 00 06 00 00 00 00 10 00 00  02 00 00 00 28 0f 00 00 28 9f 04 08 28 9f 04 08 c8 00 00
00 c8 00 00 00 06 00 00 00 04 00 00 00  04 00 00 00 68 01 00 00 68 81 04 08 68 81 04 08
44 00 00 00 44 00 00 00 04 00 00 00 04 00 00 00  50 e5 74 64 04 06 00 00 04 86 04 08 04
86 04 08 34 00 00 00 34 00 00 00 04 00 00 00 04 00 00 00  51 e5 74 64 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 00 00 00  52 e5 74 64 14 0f 00
00 14 9f 04 08 14 9f 04 08 ec 00 00 00 ec 00 00 00 04 00 00 00 01 00 00 00

每个程序头表项通过下面的结构体描述

 typedef struct { Elf32_Word p_type;  Elf32_Off p_offset;  Elf32_Addr p_vaddr;  Elf32_Addr p_paddr;  Elf32_Word p_filesz ;  Elf32_Word p_memsz;  Elf32_Word p_flags;  Elf32_Word p_align;  } Elf32_Phdr;//刚好0×20个字节 每一个程序头描述了一个“段(segment)”或者一块用于准备执行程序的信//息。一个目标文件中的“段(segment) ”包含一个或者多个“节(section) ”。//程序头只对可执行文件或共享目标文件有意义,对于其它类型的目标文件,该信息可以忽略。

下面来解释一下Elf32_Phdr每一个成员的意义。

  1. p_type 此数据成员说明了本程序头所描述的段的类型,或者如何解析本程序头的信息。 名字值:

     PT_NULL 0 //没有意义 PT_LOAD 1 //见下面 PT_DYNAMIC 2 //表明本段指明了动态连接的信息 PT_INTERP 3 //指向一个以”null” 结尾的字符串,该字符串是一个ELF 解析器的路径。 PT_NOTE 4 //指向一个以”null” 结尾的字符串,字符串包含附加的信息。 PT_SHLIB 5 //该段类型是保留的,而且未定义语法 PT_PHDR 6 //表明的是其自身所在的程序头表在文件或内存中的位置和大小 PT_LOPROC 0×70000000 //为特定处理器保留 PT_HIPROC 0x7fffffff //为特定处理器保留
    

    其中,PT_LOAD是个比较关键的成员,表明本程序头指向的是一个可装载的段。段的内容会被从文件中拷贝到内存中。段在文件中的大小是p_filesz,在内存中的大小是p_memsz 。如果 p_memsz 大于p_filesz,在内存中多出的存储空间应填 0 填充,也就是说,段在内存中可以比在文件中占用空间更大;而相反,p_filesz永远不应该比p_memsz 大,因为这样的话,内存中就将无法完整地映射段的内容。在程序头表中,所有PT_LOAD 类型的程序头按照p_vaddr的值做升序排列。

  2. p_offset 本段内容在文件中(gemfield)的位置,即段内容的开始位置相对于文件开头的偏移量。

  3. p_vaddr 本段内容的开始位置在进程空间中的虚拟地址

  4. p_paddr 本段内容的开始位置在进程空间中的物理地址。对于目前大多数现代操作系统而言,应用程序中段的物理地址事先是不可知的,所以目前这个成员多数情况下保留不用,或者被操作系统改作它用。

  5. p_filesz 本段内容在文件中的大小,单位是字节,可以是0。

  6. p_memsz 本段内容在内存镜像中的大小,单位是字节,可以是0。

  7. p_flags本段内容的属性。虽然ELF 文件格式中没有规定,但是一个可执行程序至少会有一个可加载的段。当为可加载段创建内存镜像时,系统会按照p_flags 的指示给段赋予一定的权限。名字值含义:

    PF_X 0×1 可执行
    PF_W 0×2 只写
    PF_R 0×4 只读
    PF_MASKPROC 0xf0000000 未指定
    

    如果p_flags 中没有指定PF_W 的话,系统一定不会给出写权限。其他的情况就不一定了,可以参考下表:

    标志位 所需权限 实际权限
    none 0 无任何权限 无任何权限
    PF_X 1 可执行 可读,可执行
    PF_W 2 可写 可读,可写,可执行
    PF_W + PF_X 3 可写,可执行 可读,可写,可执行
    PF_R 4 可读 可读,可执行
    PF_R + PF_X 5 可读,可执行 可读,可执行
    PF_R + PF_W 6 可读,可写 可读,可写,可执行
    PF_R + PF_W + PF_X 7 可读,可写,可执行 可读,可写,可执行
  8. p_align 对于可装载的段来说,其p_vaddrp_offset的值至少要向内存页面大小对齐。此数据成员指明本段内容如何在内存和文件中对齐。如果该值为0 或1,表明没有对齐要求;否则,p_align应该是一个正整数,并且是 2 的幂次数。p_vaddrp_offset在对p_align取模后应该相等。

第八步、摘录一个段的内容进行分析

下面我们分析一个类型为PT_LOAD的段,数据为

01 00 00 00 //类型
14 0f 00 00 //在gemfield中的偏移
14 9f 04 08 //虚拟地址
14 9f 04 08 //物理地址
08 01 00 00 //本段在文件(gemfield)中的大小
10 01 00 00 //本段在内存中的大小
06 00 00 00 //可读,可写 可读,可写,可执行
00 10 00 00 //以0×1000(也就使4096个字节)字节对齐

我们从gemfield将这一段数据拿出来,地址为0x0f14~0x101b,数据如下:

ff ff ff ff 00 00 00 00 ff ff ff ff 00 00 00 00 00 00 00 00 01 00 00 00 10 00 00 00 0c 00
00 00 3c 83 04 08 0d 00 00 00 ac 85 04 08 f5 fe ff 6f ac 81 04 08 05 00 00 00  3c 82 04
08 06 00 00 00 cc 81 04 08 0a 00 00 00 80 00 00 00 0b 00 00 00 10 00 00 00 15 00 00 00 00
00 00 00 03 00 00 00 f4 9f 04 08 02 00 00 00 28 00 00 00 14 00 00 00  11 00 00 00 17 00
00 00 14 83 04 08 11 00 00 00 0c 83 04 08 12 00 00 00 08 00 00 00 13 00 00 00 08 00 00 00
fe ff ff 6f cc 82 04 08 ff ff ff 6f 01 00 00 00 f0 ff ff 6f  bc 82 04 08 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  28 9f 04 08 00 00 00 00 00 00 00 00
86 83 04 08 96 83 04 08 a6 83 04 08 b6 83 04 08 c6 83 04 08 00 00 00 00 00 00 00

通过第七步,我们知道了gemfield中一共有9个程序头表项指定的段,但是每个段还是分成好几个节的,因为段指向的文件地址包含了各种节,我们也可以通过readelf来获得这种包含关系:

Section to Segment mapping: Segment Sections… 00  01 .interp  02 .interp .note.ABI-tag
.note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn
.rel.plt .init .plt .text .fini .rodata .eh_frame_hdr  .eh_frame  03 .ctors .dtors .jcr
.dynamic .got .got.plt .data .bss  04 .dynamic  05 .note.ABI-tag .note.gnu.build-id  06
.eh_frame_hdr  07  08 .ctors .dtors .jcr .dynamic .got

第九步:readelf工具

最后,我们通过readelf -a gemfield 来获得关于这个gemfield可执行文件的所有信息,然后和本文前面讲述的人工解析对比下,作为最后的总结:

ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00  Class: ELF32 Data:
2′s complement, little endian Version: 1 (current) OS/ABI: UNIX – System V ABI Version: 0
Type: EXEC (Executable file) Machine: Intel 80386 Version: 0×1 Entry point address:
0x80483d0 Start of program headers: 52 (bytes into file) Start of section headers: 4420
(bytes into file) Flags: 0×0 Size of this header: 52 (bytes) Size of program headers: 32
(bytes) Number of program headers: 9 Size of section headers: 40 (bytes) Number of
section headers: 30 Section header string table index: 27Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000
000000 00 0 0 0 [ 1] .interp PROGBITS 08048154 000154 000013 00 A 0 0 1 [ 2] .note.ABI-
tag NOTE 08048168 000168 000020 00 A 0 0 4 [ 3] .note.gnu.build-i NOTE 08048188 000188
000024 00 A 0 0 4 [ 4] .gnu.hash GNU_HASH 080481ac 0001ac 000020 04 A 5 0 4 [ 5] .dynsym
DYNSYM 080481cc 0001cc 000070 10 A 6 1 4 [ 6] .dynstr STRTAB 0804823c 00023c 000080 00 A
0 0 1 [ 7] .gnu.version VERSYM 080482bc 0002bc 00000e 02 A 5 0 2 [ 8] .gnu.version_r
VERNEED 080482cc 0002cc 000040 00 A 6 1 4 [ 9] .rel.dyn REL 0804830c 00030c 000008 08 A 5
0 4 [10] .rel.plt REL 08048314 000314 000028 08 A 5 12 4 [11] .init PROGBITS 0804833c
00033c 00002e 00 AX 0 0 4 [12] .plt PROGBITS 08048370 000370 000060 04 AX 0 0 16 [13]
.text PROGBITS 080483d0 0003d0 0001dc 00 AX 0 0 16 [14] .fini PROGBITS 080485ac 0005ac
00001a 00 AX 0 0 4 [15] .rodata PROGBITS 080485c8 0005c8 00003b 00 A 0 0 4 [16]
.eh_frame_hdr PROGBITS 08048604 000604 000034 00 A 0 0 4 [17] .eh_frame PROGBITS 08048638
000638 0000c4 00 A 0 0 4 [18] .ctors PROGBITS 08049f14 000f14 000008 00 WA 0 0 4 [19]
.dtors PROGBITS 08049f1c 000f1c 000008 00 WA 0 0 4 [20] .jcr PROGBITS 08049f24 000f24
000004 00 WA 0 0 4 [21] .dynamic DYNAMIC 08049f28 000f28 0000c8 08 WA 6 0 4 [22] .got
PROGBITS 08049ff0 000ff0 000004 04 WA 0 0 4 [23] .got.plt PROGBITS 08049ff4 000ff4 000020
04 WA 0 0 4 [24] .data PROGBITS 0804a014 001014 000008 00 WA 0 0 4 [25] .bss NOBITS
0804a01c 00101c 000008 00 WA 0 0 4 [26] .comment PROGBITS 00000000 00101c 00002a 01 MS 0
0 1 [27] .shstrtab STRTAB 00000000 001046 0000fc 00 0 0 1 [28] .symtab SYMTAB 00000000
0015f4 000430 10 29 45 4 [29] .strtab STRTAB 00000000 001a24 000232 00 0 0 1 Key to
Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link
order), G (group), T (TLS), E (exclude), x (unknown) O (extra OS processing required) o
(OS specific), p (processor specific)There are no section groups in this file.Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0×000034
0×08048034 0×08048034 0×00120 0×00120 R E 0×4 INTERP 0×000154 0×08048154 0×08048154
0×00013 0×00013 R 0×1 [Requesting program interpreter: /lib/ld-linux.so.2] LOAD 0×000000
0×08048000 0×08048000 0x006fc 0x006fc R E 0×1000 LOAD 0x000f14 0x08049f14 0x08049f14
0×00108 0×00110 RW 0×1000 DYNAMIC 0x000f28 0x08049f28 0x08049f28 0x000c8 0x000c8 RW 0×4
NOTE 0×000168 0×08048168 0×08048168 0×00044 0×00044 R 0×4 GNU_EH_FRAME 0×000604
0×08048604 0×08048604 0×00034 0×00034 R 0×4 GNU_STACK 0×000000 0×00000000 0×00000000
0×00000 0×00000 RW 0×4 GNU_RELRO 0x000f14 0x08049f14 0x08049f14 0x000ec 0x000ec R 0×1Section to Segment mapping: Segment Sections… 00  01 .interp  02 .interp .note.ABI-tag
.note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn
.rel.plt .init .plt .text .fini .rodata .eh_frame_hdr  .eh_frame  03 .ctors .dtors .jcr
.dynamic .got .got.plt .data .bss  04 .dynamic  05 .note.ABI-tag .note.gnu.build-id  06
.eh_frame_hdr  07  08 .ctors .dtors .jcr .dynamic .gotDynamic section at offset 0xf28 contains 20 entries: Tag Type Name/Value 0×00000001
(NEEDED) Shared library: [libc.so.6] 0x0000000c (INIT) 0x804833c 0x0000000d (FINI)
0x80485ac 0x6ffffef5 (GNU_HASH) 0x80481ac 0×00000005 (STRTAB) 0x804823c 0×00000006
(SYMTAB) 0x80481cc 0x0000000a (STRSZ) 128 (bytes) 0x0000000b (SYMENT) 16 (bytes)
0×00000015 (DEBUG) 0×0 0×00000003 (PLTGOT) 0x8049ff4 0×00000002 (PLTRELSZ) 40 (bytes)
0×00000014 (PLTREL) REL 0×00000017 (JMPREL) 0×8048314 0×00000011 (REL) 0x804830c
0×00000012 (RELSZ) 8 (bytes) 0×00000013 (RELENT) 8 (bytes) 0x6ffffffe (VERNEED) 0x80482cc
0x6fffffff (VERNEEDNUM) 1 0x6ffffff0 (VERSYM) 0x80482bc 0×00000000 (NULL) 0×0Relocation section ‘.rel.dyn’ at offset 0x30c contains 1 entries: Offset Info Type
Sym.Value Sym. Name 08049ff0 00000306 R_386_GLOB_DAT 00000000 __gmon_start__Relocation section ‘.rel.plt’ at offset 0×314 contains 5 entries: Offset Info Type
Sym.Value Sym. Name 0804a000 00000107 R_386_JUMP_SLOT 00000000 printf 0804a004 00000207
R_386_JUMP_SLOT 00000000 __stack_chk_fail 0804a008 00000307 R_386_JUMP_SLOT 00000000
__gmon_start__ 0804a00c 00000407 R_386_JUMP_SLOT 00000000 __libc_start_main 0804a010
00000507 R_386_JUMP_SLOT 00000000 __isoc99_scanfThere are no unwind sections in this file.Symbol table ‘.dynsym’ contains 7 entries: Num: Value Size Type Bind Vis Ndx Name 0:
00000000 0 NOTYPE LOCAL DEFAULT UND  1: 00000000 0 FUNC GLOBAL DEFAULT UND
printf@GLIBC_2.0 (2) 2: 00000000 0 FUNC GLOBAL DEFAULT UND __stack_chk_fail@GLIBC_2.4 (3)
3: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 4: 00000000 0 FUNC GLOBAL DEFAULT
UND __libc_start_main@GLIBC_2.0 (2) 5: 00000000 0 FUNC GLOBAL DEFAULT UND
__isoc99_scanf@GLIBC_2.7 (4) 6: 080485cc 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_usedSymbol table ‘.symtab’ contains 67 entries: Num: Value Size Type Bind Vis Ndx Name 0:
00000000 0 NOTYPE LOCAL DEFAULT UND  1: 08048154 0 SECTION LOCAL DEFAULT 1  2: 08048168 0
SECTION LOCAL DEFAULT 2  3: 08048188 0 SECTION LOCAL DEFAULT 3  4: 080481ac 0 SECTION
LOCAL DEFAULT 4  5: 080481cc 0 SECTION LOCAL DEFAULT 5  6: 0804823c 0 SECTION LOCAL
DEFAULT 6  7: 080482bc 0 SECTION LOCAL DEFAULT 7  8: 080482cc 0 SECTION LOCAL DEFAULT 8
9: 0804830c 0 SECTION LOCAL DEFAULT 9  10: 08048314 0 SECTION LOCAL DEFAULT 10  11:
0804833c 0 SECTION LOCAL DEFAULT 11  12: 08048370 0 SECTION LOCAL DEFAULT 12  13:
080483d0 0 SECTION LOCAL DEFAULT 13  14: 080485ac 0 SECTION LOCAL DEFAULT 14  15:
080485c8 0 SECTION LOCAL DEFAULT 15  16: 08048604 0 SECTION LOCAL DEFAULT 16  17:
08048638 0 SECTION LOCAL DEFAULT 17  18: 08049f14 0 SECTION LOCAL DEFAULT 18  19:
08049f1c 0 SECTION LOCAL DEFAULT 19  20: 08049f24 0 SECTION LOCAL DEFAULT 20  21:
08049f28 0 SECTION LOCAL DEFAULT 21  22: 08049ff0 0 SECTION LOCAL DEFAULT 22  23:
08049ff4 0 SECTION LOCAL DEFAULT 23  24: 0804a014 0 SECTION LOCAL DEFAULT 24  25:
0804a01c 0 SECTION LOCAL DEFAULT 25  26: 00000000 0 SECTION LOCAL DEFAULT 26  27:
00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 28: 08049f14 0 OBJECT LOCAL DEFAULT 18
__CTOR_LIST__ 29: 08049f1c 0 OBJECT LOCAL DEFAULT 19 __DTOR_LIST__ 30: 08049f24 0 OBJECT
LOCAL DEFAULT 20 __JCR_LIST__ 31: 08048400 0 FUNC LOCAL DEFAULT 13 __do_global_dtors_aux
32: 0804a01c 1 OBJECT LOCAL DEFAULT 25 completed.6086 33: 0804a020 4 OBJECT LOCAL DEFAULT
25 dtor_idx.6088 34: 08048460 0 FUNC LOCAL DEFAULT 13 frame_dummy 35: 00000000 0 FILE
LOCAL DEFAULT ABS crtstuff.c 36: 08049f18 0 OBJECT LOCAL DEFAULT 18 __CTOR_END__ 37:
080486f8 0 OBJECT LOCAL DEFAULT 17 __FRAME_END__ 38: 08049f24 0 OBJECT LOCAL DEFAULT 20
__JCR_END__ 39: 08048580 0 FUNC LOCAL DEFAULT 13 __do_global_ctors_aux 40: 00000000 0
FILE LOCAL DEFAULT ABS leaf.c 41: 08049f14 0 NOTYPE LOCAL DEFAULT 18 __init_array_end 42:
08049f28 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC 43: 08049f14 0 NOTYPE LOCAL DEFAULT 18
__init_array_start 44: 08049ff4 0 OBJECT LOCAL DEFAULT 23 _GLOBAL_OFFSET_TABLE_ 45:
08048570 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini 46: 08048572 0 FUNC GLOBAL HIDDEN 13
__i686.get_pc_thunk.bx 47: 0804a014 0 NOTYPE WEAK DEFAULT 24 data_start 48: 00000000 0
FUNC GLOBAL DEFAULT UND printf@@GLIBC_2.0 49: 0804a01c 0 NOTYPE GLOBAL DEFAULT ABS _edata
50: 080485ac 0 FUNC GLOBAL DEFAULT 14 _fini 51: 00000000 0 FUNC GLOBAL DEFAULT UND
__stack_chk_fail@@GLIBC_2 52: 08049f20 0 OBJECT GLOBAL HIDDEN 19 __DTOR_END__ 53:
0804a014 0 NOTYPE GLOBAL DEFAULT 24 __data_start 54: 00000000 0 NOTYPE WEAK DEFAULT UND
__gmon_start__ 55: 0804a018 0 OBJECT GLOBAL HIDDEN 24 __dso_handle 56: 080485cc 4 OBJECT
GLOBAL DEFAULT 15 _IO_stdin_used 57: 00000000 0 FUNC GLOBAL DEFAULT UND
__libc_start_main@@GLIBC_ 58: 08048500 97 FUNC GLOBAL DEFAULT 13 __libc_csu_init 59:
0804a024 0 NOTYPE GLOBAL DEFAULT ABS _end 60: 080483d0 0 FUNC GLOBAL DEFAULT 13 _start
61: 080485c8 4 OBJECT GLOBAL DEFAULT 15 _fp_hw 62: 0804a01c 0 NOTYPE GLOBAL DEFAULT ABS
__bss_start 63: 08048484 111 FUNC GLOBAL DEFAULT 13 main 64: 00000000 0 NOTYPE WEAK
DEFAULT UND _Jv_RegisterClasses 65: 00000000 0 FUNC GLOBAL DEFAULT UND
__isoc99_scanf@@GLIBC_2.7 66: 0804833c 0 FUNC GLOBAL DEFAULT 11 _initHistogram for `.gnu.hash’ bucket list length (total of 2 buckets): Length Number % of
total Coverage 0 1 ( 50.0%) 1 1 ( 50.0%) 100.0%Version symbols section ‘.gnu.version’ contains 7 entries: Addr: 00000000080482bc Offset:
0x0002bc Link: 5 (.dynsym) 000: 0 (*local*) 2 (GLIBC_2.0) 3 (GLIBC_2.4) 0 (*local*)  004:
2 (GLIBC_2.0) 4 (GLIBC_2.7) 1 (*global*)Version needs section ‘.gnu.version_r’ contains 1 entries: Addr: 0x00000000080482cc
Offset: 0x0002cc Link: 6 (.dynstr) 000000: Version: 1 File: libc.so.6 Cnt: 3 0×0010:
Name: GLIBC_2.7 Flags: none Version: 4 0×0020: Name: GLIBC_2.4 Flags: none Version: 3
0×0030: Name: GLIBC_2.0 Flags: none Version: 2Notes at offset 0×00000168 with length 0×00000020: Owner Data size Description GNU
0×00000010 NT_GNU_ABI_TAG (ABI version tag) OS: Linux, ABI: 2.6.15Notes at offset 0×00000188 with length 0×00000024: Owner Data size Description GNU
0×00000014 NT_GNU_BUILD_ID (unique build ID bitstring) Build ID:
2aebea6a183e8ffe7ab9fcbd7155670c8ce1429c

详述 从代码如何到可执行文件 的过程和解耦相关推荐

  1. 解释源代码文件、目标代码文件和可执行文件之间的区别

    源代码到可执行文件的过程: 编译器驱动程序读取源文件(hello.c和main.c),经过预处理.编译.汇编.链接(分别使用预处理器.编译器.汇编器.链接器,这四个程序构成了编译系统)四个步骤,将其翻 ...

  2. C基础——目标代码文件、可执行文件和库

    目标代码文件.可执行文件和库 C编程的基本策略是使用程序将源代码文件转换为可执行文件,此文件包含可以运行的机器语言代码.C分两步完成这一工作:编译和链接.编译器将源代码转换为中间代码,链接器将此中间代 ...

  3. java request 处理过程_小猿圈Java开发之从代码看spring mvc请求处理过程

    原标题:小猿圈Java开发之从代码看spring mvc请求处理过程 Java作为编程界的常青树,有自己生存的独到之处,小猿圈java讲师今天就分享一个关于从代码看spring mvc请求处理过程,通 ...

  4. 执行引擎的工作过程、Java代码编译和执行的过程、解释器、JIT编译器

    执行引擎概述 执行引擎是Java虛拟机核心的组成部分之一. "虚拟机"是-一个相对于"物理机"的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接 ...

  5. 【Android4.4蓝牙代码分析】- 蓝牙Enable过程

    [Android4.4蓝牙代码分析]- 蓝牙Enable过程 (一)基本说明 本文的代码选用的是Android4.4的kitkat代码. 本文是在Windows环境下通过source insight进 ...

  6. Linux下gcc编译c程序生成可执行文件的过程

    Linux下gcc编译c程序生成可执行文件 一.准备 hello.c 文件 1.在当前目录下新建c文件 $:vim hello.c 2.按i进入编辑模式.按esc退出编辑模式,输入源代码 #inclu ...

  7. C语言生成可执行文件的过程

    今天用gcc编译器为大家演示一下c语言的编译过程 首先,我们将贴上我们朴实无华的源代码 1. 预编译过程 由.c --生成–> .o文件 通过 gcc -E main.c -o main.i 执 ...

  8. 实验四:汇编代码调用系统调用的工作过程

    钟晶晶 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 工作过程 以41 ...

  9. 目标代码文件、可执行文件和库

    C编程的基本策略是使用程序将源代码转换为可执行文件,此文件包含可运行的机器语言代码.C分两步完成这一工作:编译和链接.编译器将源代码转换为中间代码,连接器将此中间代码与其他代码相结合来生成可执行文件. ...

最新文章

  1. 新书推荐 |《PostgreSQL实战》出版
  2. [usb]usb otg和host
  3. 漫画:程序员一时单身一时爽,一直单身...有点惨
  4. 【渝粤教育】国家开放大学2018年秋季 1167t环境水利学 参考试题
  5. Kaggle新赛:通过音频识别鸟类和青蛙物种
  6. PTA c语言 数组元素循环右移问题
  7. 【Elasticsearch】 Elasticsearch Suggester 自动纠错 详解
  8. Mysql 中将blob类型转换成varchar类型
  9. Atitit php db mysql api<?php$mysql_conf = array( ‘host‘ => ‘localhost‘, ‘db‘ => ‘mysql
  10. 最大功率跟踪mppt
  11. 评价得分计算:确立权重的方法
  12. 好用的屏幕录像截图工具:Movavi Screen Capture Pro 10 Mac
  13. 2、接口测试-mitmproxy录制及回放使用
  14. java poi word 复制_java poi实现word导出(包括word模板的使用、复制表格、复制行、插入图片的使用)...
  15. UltraVNC源码编译运行
  16. iOS Presenting view controllers on detached view controllers is discouraged
  17. 美国医院权威评估体系
  18. 创业公司股权分配较好方案推荐
  19. win10 dpc_watchdog_violation 蓝屏
  20. 全球最大同性交友平台的“黑历史”

热门文章

  1. 民宿管理系统课程设计_民宿开致辞.doc
  2. 【windows】常见系统环境变量路径,如%appdata%等
  3. 【活动发布】捷微H5-微信新年砍价活动,开源发布了
  4. 博士之路-大龄博士也能发光
  5. 地球末日服务器不稳定,神雕侠侣2手游侠客传功功能上线 4月9日更新内容一览[多图]...
  6. 小学生计算机管理员寄语,小学生寄语简短
  7. python c++情侣网名含义_集Python、C++、R为一体的语言,她是?
  8. 优雅源自国力--中国可以更优雅
  9. 厦大小学期C语言程序设计实践(一)
  10. 图形学相关数学(反射,折射公式)