请先关注 [低调大师] 公众号 优秀的自媒体个人博客,低调大师,许军

低调大师

您现在的位置是:首页>文章详情

文章详情

鸿蒙内核源码分析(ELF解析篇) | 都这样了码农还能忘了她俩? | 百篇博客分析HarmonyOS源码 | v53.01

2021-05-14 23热度

将 HarmonyOS | 鸿蒙 研究到底 < 国内 | 国外 >

在这里插入图片描述

百篇博客系列篇.本篇为:

系列篇将花四篇介绍ELF,它实在是太重要了,内核加载运行的源头就是它,不说清楚它怎么去说清楚应用程序运行的过程呢.本篇在

  • v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main | 51 .c .h .o 基础上进一步追问,发现还是有很多内容没讲清楚.例如下面这一坨一坨的,除了.text,.bss,.data听过见过外,其他的咱也没啥交情.
    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 .plt.got .plt.sec .text .fini 04 .rodata .eh_frame_hdr .eh_frame 05 .init_array .fini_array .dynamic .got .data .bss 

要全说清楚也不太可能,可以去看 ELF官方文档(106页) ,本篇试图与它多些交情,混个脸熟,方便后续办事.从两个命令入手. readelf -S appreadelf -s app这俩宝贝长的很像,但仔细看中间参数是大S和小s,说到大S小s又有点意思了,这两姐妹上了点年纪的码农都应该不陌生,但性格可完全不同.个人喜欢大的,甜美安静,小的太聒噪,受不了,码农最需要安静了.

readelf -S app

先看老大是干啥的,其实她是她们家老二,上面还有个姐姐,没啥存在感,不管她了.

root@5e3abe332c5a:/home/docker/test4harmony# readelf -h ... -S --section-headers Display the sections' header --sections An alias for --section-headers -s --syms Display the symbol table --symbols An alias for --syms 

显示所有区头信息 | sections' header

root@5e3abe332c5a:/home/docker/test4harmony# readelf -S app There are 31 section headers, starting at offset 0x39c0: 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 0000000000000318 00000318 000000000000001c 0000000000000000 A 0 0 1 [ 2] .note.gnu.propert NOTE 0000000000000338 00000338 0000000000000020 0000000000000000 A 0 0 8 [ 3] .note.gnu.build-i NOTE 0000000000000358 00000358 0000000000000024 0000000000000000 A 0 0 4 [ 4] .note.ABI-tag NOTE 000000000000037c 0000037c 0000000000000020 0000000000000000 A 0 0 4 [ 5] .gnu.hash GNU_HASH 00000000000003a0 000003a0 0000000000000024 0000000000000000 A 6 0 8 [ 6] .dynsym DYNSYM 00000000000003c8 000003c8 00000000000000a8 0000000000000018 A 7 1 8 [ 7] .dynstr STRTAB 0000000000000470 00000470 0000000000000084 0000000000000000 A 0 0 1 [ 8] .gnu.version VERSYM 00000000000004f4 000004f4 000000000000000e 0000000000000002 A 6 0 2 [ 9] .gnu.version_r VERNEED 0000000000000508 00000508 0000000000000020 0000000000000000 A 7 1 8 [10] .rela.dyn RELA 0000000000000528 00000528 00000000000000d8 0000000000000018 A 6 0 8 [11] .rela.plt RELA 0000000000000600 00000600 0000000000000018 0000000000000018 AI 6 24 8 [12] .init PROGBITS 0000000000001000 00001000 000000000000001b 0000000000000000 AX 0 0 4 [13] .plt PROGBITS 0000000000001020 00001020 0000000000000020 0000000000000010 AX 0 0 16 [14] .plt.got PROGBITS 0000000000001040 00001040 0000000000000010 0000000000000010 AX 0 0 16 [15] .plt.sec PROGBITS 0000000000001050 00001050 0000000000000010 0000000000000010 AX 0 0 16 [16] .text PROGBITS 0000000000001060 00001060 00000000000001b5 0000000000000000 AX 0 0 16 [17] .fini PROGBITS 0000000000001218 00001218 000000000000000d 0000000000000000 AX 0 0 4 [18] .rodata PROGBITS 0000000000002000 00002000 000000000000001b 0000000000000000 A 0 0 4 [19] .eh_frame_hdr PROGBITS 000000000000201c 0000201c 000000000000004c 0000000000000000 A 0 0 4 [20] .eh_frame PROGBITS 0000000000002068 00002068 0000000000000128 0000000000000000 A 0 0 8 [21] .init_array INIT_ARRAY 0000000000003db8 00002db8 0000000000000008 0000000000000008 WA 0 0 8 [22] .fini_array FINI_ARRAY 0000000000003dc0 00002dc0 0000000000000008 0000000000000008 WA 0 0 8 [23] .dynamic DYNAMIC 0000000000003dc8 00002dc8 00000000000001f0 0000000000000010 WA 7 0 8 [24] .got PROGBITS 0000000000003fb8 00002fb8 0000000000000048 0000000000000008 WA 0 0 8 [25] .data PROGBITS 0000000000004000 00003000 0000000000000018 0000000000000000 WA 0 0 8 [26] .bss NOBITS 0000000000004018 00003018 0000000000000008 0000000000000000 WA 0 0 1 [27] .comment PROGBITS 0000000000000000 00003018 000000000000002a 0000000000000001 MS 0 0 1 [28] .symtab SYMTAB 0000000000000000 00003048 0000000000000648 0000000000000018 29 46 8 [29] .strtab STRTAB 0000000000000000 00003690 0000000000000216 0000000000000000 0 0 1 [30] .shstrtab STRTAB 0000000000000000 000038a6 000000000000011a 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) 

解读 命令结果主要三个部分,区名称(Section Head Name),区类型 (Section Head Type) 和区标签(Section Head Flag)

  • Name部分 出现了一些熟悉的内容 .bss,.text,但更多是看不懂的 .fini,.plt ,.relname
  • Type部分 就有更多看不懂的 NULL,PROGBITS,INIT_ARRAY 等等.
  • Flag部分 好像也似懂非懂.

一个区只属于一个类型,具有排它性,跟男人,女人一样. 区跟人一样可以有多个标签.可以是码农,可以是高富帅,可以是脱发男,不对!!! 码农你还想是高富帅,想多了.脱发才是你的标配.例如:

  • 代码区(.text)属于PROGBITS类型被贴上了AX (alloc + execute)标签.原来代码区可以被CPU取指运行是因为在ELF中被贴上了可运行标签.但注意.text是只读不可写,因为它身上没有write标签.
  • 再看熟悉两个数据区.bss.data,它们都有WA(write+alloc)标签,可写+运行过程中需要占用内存,但二者区别是类型的不用,.bssNOBITS类型 .dataPROGBITS类型

区名称 | Section Head Name

简称:SHN

在ELF文件中有一些特定的区是预定义好的,其内容是指令代码或者控制信息.这些区专门为操作系统使用,对于不同的操作系统,这些区的类型和属性有所不同.

在构建可执行程序时,连接器(linker)可能需要把一些独立的目标文件和库文件连接在一起,在这个过程中,连接器要解析各个文件中的相互引用,调整某些目标文件中的绝对引用,并重定位指令码.

每种操作系统都有自己的一套连接模型,但总的来说,不外乎静态和动态两类:

  • 静态连接:所有的目标文件和动态连接库被静态地绑定在一起,所有的符号都被解析出来.所创建的目标文件是完整的,运行时不依赖于任何外部的库.

  • 动态连接:所有的目标文件,系统共享资源以及共享库以动态的形式连接在一起,外部库的内容没有完整地拷贝进来.如果创建的是可执行文件的话,程序在运行的时候,在构建时所依赖的那些库必须在系统中能找到,把它们一并装载之后,程序才能运行起来.运行期间如何解析那些动态连接进来的符号引用,不同的系统有各自不同的方式.

有些区包含调试信息,比如.debug和.line区. 有些区包含程序控制信息,比如.bss,.data,.data1,.rodata和.rodata1这些区. 还有一些区含有程序或控制信息,这些区由系统使用,有指定的类型和属性.它们中的大多数都将用于连接过程.动态连接过程所需要的信息由.dynsym,.dynstr,.interp,.hash,.dynamic,.rel,.rela,.got,.plt等区提供.其中有些区(比如.plt和.got)的内容依处理器而不同,但它们都支持同样的连接模型.

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

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

详细解读

  • .text 通常是指用来存放程序执行代码的一块内存区域.这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码区为可写,即允许修改程序.在代码区中,也有可能包含一些只读的常数变量,例如字符串常量等.
  • .rodata.data区类型一样但标签有别,.rodata只有A标,是个只读区,比如字符串常量,全局const变量和#define定义的常量,又称为常量区 但是注意,并不是所有的常量都放在rodata区的,其特殊情况如下:
    • 有些立即数与指令编译在一起直接放在代码区.
    • 对于字符串常量,编译器会去掉重复的常量,让程序的每个字符串常量只有一份
    • 有些系统中rodata区是多个进程共享的,目的是为了提高空间的利用率
  • .bss.data是标签一样但类型有别,.bss区属于静态内存分配.通常是指用来存放程序中未初始化的全局变量和未初始化的局部静态变量.未初始化的全局变量和未初始化的局部静态变量默认值是0,本来这些变量也可以放到data区的,但是因为它们都是0,所以它们在data区分配空间并且存放数据0是没有必要的.在程序运行时,才会给BSS区里面的变量分配内存空间.在目标文件(*.o)和可执行文件中,.bss只是为未初始化的全局变量和未初始化的局部静态变量预留位置而已,它并没有内容,所以它不占据空间.
  • .data 通常是指用来存放程序中已初始化的全局变量和已初始化的静态变量的一块内存区域,属于静态内存分配.

区类型 | Section Head Type

简称:SHT

SHT_NULL 本区头是一个无效的(非活动的)区头,它也没有对应的区.本区头中的其它成员的值也都是没有意义的. SHT_PROGBITS 本区所含有的信息是由程序定义的,本区内容的格式和含义都由程序来决定. SHT_SYMTAB 同DYNSYM SHT_DYNSYM 这两类区都含有符号表.目前,目标文件中最多只能各包含一个这两种区,但这种限制以后可能会取消. 一般来说,SYMTAB提供的符号用于在创建目标文件的时候编辑连接,在运行期间也有可能会用于动态连接. SYMTAB包含完整的符号表,它往往会包含很多在运行期间(动态连接)用不到的符号.所以,一个目标文件 可以再有一个DYNSYM区,它含有一个较小的符号表,专门用于动态连接. SHT_STRTAB 本区是字符串表.目标文件中可以包含多个字符串表区. SHT_RELA 本区是一个重定位区,含有带明确加数(addend)的重定位项,对于32位类型的目标文件来说, 这个加数就是Elf32_Rela.一个目标文件可能含有多个重定位区. SHT_HASH 本区包含一张哈希表.所有参与动态连接的目标文件都必须要包含一个符号哈希表.目前,一个目标文件中最多只能有一个哈希表, 但这一限制以后可能会取消. SHT_DYNAMIC 本区包含的是动态连接信息.目前,一个目标文件中最多只能有一个DYNAMIC区, 但这一限制以后可能会取消. SHT_NOTE 本区包含的信息用于以某种方式来标记本文件. SHT_NOBITS 这一区的内容是空的,区并不占用实际的空间.只代表一个逻辑上的位置概念,并不代表实际的内容. SHT_REL 本区是一个重定位区,含有带明确加数的重定位项,对于32位类型的目标文件来说,这个加数就是Elf32_Rel.一个目标文件可能含有多个重定位区. SHT_SHLIB 此值是一个保留值,暂未指定语义. SHT_LOPROC 为特殊处理器保留的区类型索引值的下边界. SHT_HIPROC 为特殊处理器保留的区类型索引值的上边界.LOPROC ~ HIPROC区间是为特殊处理器区类型的保留值. SHT_LOUSER 为应用程序保留区类型索引值的下边界. SHT_HIUSER 为应用程序保留区类型索引值的下边界.LOUSER ~ HIUSER区间的区类型可由应用程序自行定义,是一区保留值. 

解读

  • .bss 类型为 NOBITS,这一区的内容是空的,区并不占用实际的空间, 没有初值的全局变量就放在这个区.它是真没有值,由运行过程中映射到哪个地址就取哪个地址的值.鬼知道跑哪个位置的.
  • PROGBITS本区内容的格式和含义都由程序来决定,属于这个区的内容还挺多的 .text,.data, .init, .rodata ,这些区默认自带运行时数据.不需要你额外提供,区别是这些自带数据运行时可不可以被改变. .data可以被程序运行时逻辑所修改,.rodata不可改,即常量数据.

区标签 | Section Head Flag

简称:SHF

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) 
名字 值 描述 SHF_WRITE 0x01 如果此标志被设置,表示本区所包含的内容在进程运行过程中是可写的. SHF_ALLOC 0x02 如果此标志被设置,表示本区内容在进程运行过程中要占用内存单元.并不是所有区 都会占用实际的内存,有一些起控制作用的区,在目标文件映射到进程空间时,并不需要占用内存. SHF_EXECUTE 0x04 如果此标志被设置,表示本区内容是指令代码. 

解读 此处看下与数据相关的三个区,仔细对照看参数发现其真正的区别.

Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [18] .rodata PROGBITS 0000000000002000 00002000 000000000000001b 0000000000000000 A 0 0 4 [25] .data PROGBITS 0000000000004000 00003000 0000000000000018 0000000000000000 WA 0 0 8 [26] .bss NOBITS 0000000000004018 00003018 0000000000000008 0000000000000000 WA 0 0 1 

readelf -s app

说完大S再来说小S

root@5e3abe332c5a:/home/docker/test4harmony# readelf -h ... -S --section-headers Display the sections' header --sections An alias for --section-headers -s --syms Display the symbol table --symbols An alias for --syms 

显示所有符号表 | Symbol Table.

root@5e3abe332c5a:/home/docker/test4harmony# readelf -s app Symbol table '.dynsym' contains 7 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) 4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 5: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable 6: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (2) Symbol table '.symtab' contains 67 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000318 0 SECTION LOCAL DEFAULT 1 2: 0000000000000338 0 SECTION LOCAL DEFAULT 2 3: 0000000000000358 0 SECTION LOCAL DEFAULT 3 4: 000000000000037c 0 SECTION LOCAL DEFAULT 4 5: 00000000000003a0 0 SECTION LOCAL DEFAULT 5 6: 00000000000003c8 0 SECTION LOCAL DEFAULT 6 7: 0000000000000470 0 SECTION LOCAL DEFAULT 7 8: 00000000000004f4 0 SECTION LOCAL DEFAULT 8 9: 0000000000000508 0 SECTION LOCAL DEFAULT 9 10: 0000000000000528 0 SECTION LOCAL DEFAULT 10 11: 0000000000000600 0 SECTION LOCAL DEFAULT 11 12: 0000000000001000 0 SECTION LOCAL DEFAULT 12 13: 0000000000001020 0 SECTION LOCAL DEFAULT 13 14: 0000000000001040 0 SECTION LOCAL DEFAULT 14 15: 0000000000001050 0 SECTION LOCAL DEFAULT 15 16: 0000000000001060 0 SECTION LOCAL DEFAULT 16 17: 0000000000001218 0 SECTION LOCAL DEFAULT 17 18: 0000000000002000 0 SECTION LOCAL DEFAULT 18 19: 000000000000201c 0 SECTION LOCAL DEFAULT 19 20: 0000000000002068 0 SECTION LOCAL DEFAULT 20 21: 0000000000003db8 0 SECTION LOCAL DEFAULT 21 22: 0000000000003dc0 0 SECTION LOCAL DEFAULT 22 23: 0000000000003dc8 0 SECTION LOCAL DEFAULT 23 24: 0000000000003fb8 0 SECTION LOCAL DEFAULT 24 25: 0000000000004000 0 SECTION LOCAL DEFAULT 25 26: 0000000000004018 0 SECTION LOCAL DEFAULT 26 27: 0000000000000000 0 SECTION LOCAL DEFAULT 27 28: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 29: 0000000000001090 0 FUNC LOCAL DEFAULT 16 deregister_tm_clones 30: 00000000000010c0 0 FUNC LOCAL DEFAULT 16 register_tm_clones 31: 0000000000001100 0 FUNC LOCAL DEFAULT 16 __do_global_dtors_aux 32: 0000000000004018 1 OBJECT LOCAL DEFAULT 26 completed.8060 33: 0000000000003dc0 0 OBJECT LOCAL DEFAULT 22 __do_global_dtors_aux_fin 34: 0000000000001140 0 FUNC LOCAL DEFAULT 16 frame_dummy 35: 0000000000003db8 0 OBJECT LOCAL DEFAULT 21 __frame_dummy_init_array_ 36: 0000000000000000 0 FILE LOCAL DEFAULT ABS main.c 37: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 38: 000000000000218c 0 OBJECT LOCAL DEFAULT 20 __FRAME_END__ 39: 0000000000000000 0 FILE LOCAL DEFAULT ABS 40: 0000000000003dc0 0 NOTYPE LOCAL DEFAULT 21 __init_array_end 41: 0000000000003dc8 0 OBJECT LOCAL DEFAULT 23 _DYNAMIC 42: 0000000000003db8 0 NOTYPE LOCAL DEFAULT 21 __init_array_start 43: 000000000000201c 0 NOTYPE LOCAL DEFAULT 19 __GNU_EH_FRAME_HDR 44: 0000000000003fb8 0 OBJECT LOCAL DEFAULT 24 _GLOBAL_OFFSET_TABLE_ 45: 0000000000001000 0 FUNC LOCAL DEFAULT 12 _init 46: 0000000000001210 5 FUNC GLOBAL DEFAULT 16 __libc_csu_fini 47: 0000000000004010 8 OBJECT GLOBAL DEFAULT 25 my_name 48: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab 49: 0000000000004000 0 NOTYPE WEAK DEFAULT 25 data_start 50: 0000000000004018 0 NOTYPE GLOBAL DEFAULT 25 _edata 51: 0000000000001218 0 FUNC GLOBAL HIDDEN 17 _fini 52: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@@GLIBC_2.2.5 53: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_ 54: 0000000000004000 0 NOTYPE GLOBAL DEFAULT 25 __data_start 55: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 56: 0000000000004008 0 OBJECT GLOBAL HIDDEN 25 __dso_handle 57: 0000000000002000 4 OBJECT GLOBAL DEFAULT 18 _IO_stdin_used 58: 00000000000011a0 101 FUNC GLOBAL DEFAULT 16 __libc_csu_init 59: 0000000000004020 0 NOTYPE GLOBAL DEFAULT 26 _end 60: 0000000000001060 47 FUNC GLOBAL DEFAULT 16 _start 61: 0000000000004018 0 NOTYPE GLOBAL DEFAULT 26 __bss_start 62: 0000000000001174 30 FUNC GLOBAL DEFAULT 16 main 63: 0000000000001149 43 FUNC GLOBAL DEFAULT 16 say_hello 64: 0000000000004018 0 OBJECT GLOBAL HIDDEN 25 __TMC_END__ 65: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable 66: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.2 

解读 .dynsym,.symtab两区的类型如下,是一个含义.

SHT_SYMTAB 同DYNSYM SHT_DYNSYM 这两类区都含有符号表.目前,目标文件中最多只能各包含一个这两种区,但这种限制以后可能会取消. 一般来说,SYMTAB提供的符号用于在创建目标文件的时候编辑连接,在运行期间也有可能会用于动态连接. SYMTAB包含完整的符号表,它往往会包含很多在运行期间(动态连接)用不到的符号.所以,一个目标文件 可以再有一个DYNSYM区,它含有一个较小的符号表,专门用于动态连接. 

正如描述所言,.dynsym是.symtab的缩小版,在其中能看到亲切的printf.具体请参考以下四个维度来理解符号表.

符号表绑定 | Symbol Table Bind

简称 STB

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 为特殊处理器保留的属性区间. 

符号表类型 | Symbol Table Type

简称 STT

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

符号表可见性 | Symbol Table Visibility

简称 STV

STV_DEFAULT 当符号的可见性是STV_DEFAULT时,那么该符号的可见性由符号的绑定属性决定. 这类情况下,(可执行文件和共享库中的)全局符号和弱符号默认是外部可访问的, 本地符号默认外部是无法被访问的.但是,可见性是STV_DEFAULT的全局符号和弱符号是可被覆盖的. 什么意思?举个最典型的例子,共享库中的可见性值为STV_DEFAULTD的全局符号和弱符号 是可被可执行文件中的同名符号覆盖的. STV_HIDDEN 当符号的可见性是STV_HIDDEN时,证明该符号是外部无法访问的.这个属性主要 用来控制共享库对外接口的数量.需要注意的是,一个可见性为STV_HIDDEN的数据对象, 如果能获取到该符号的地址,那么依然是可以访问或者修改该数据对象的.在可重定位文件中, 如果一个符号的可见性是STV_HIDDEN的话,那么在链接生成可执行文件或者共享库的过程中, 该符号要么被删除,要么绑定属性变成STB_LOCAL. STV_PROTECTED 当符号的可见性是STV_PROTECTED时,它是外部可见的,这点跟可见性是STV_DEFAULT的一样, 但不同的是它是不可覆盖的.这样的符号在共享库中比较常见.不可覆盖意味着如果是在该符号 所在的共享库中访问这个符号,那么就一定是访问的这个符号,尽管可执行文件中也会存在 同样名字的符号也不会被覆盖掉.规定绑定属性为STB_LOCAL的符号的可见性不可以是STV_PROTECTED. STV_INTERNAL 该可见性属性的含义可以由处理器补充定义,以进一步约束隐藏的符号. 处理器补充程序的定义 应使通用工具可以安全地将内部符号视为隐藏符号.当可重定位对象包含在可执行文件或共享对象中时, 可重定位对象中包含的内部符号必须被链接编辑器删除或转换为STB_LOCAL绑定. 

符号表索引 | Symbol Table Ndx

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

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

百篇博客.往期回顾

在加注过程中,整理出以下文章.内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆.说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思.更希望让内核变得栩栩如生,倍感亲切.确实有难度,自不量力,但已经出发,回头已是不可能的了.:P 与代码有bug需不断debug一样,文章和注解内容会存在不少错漏之处,但会反复修正,持续更新,.xx代表修改的次数,精雕细琢,言简意赅,力求打造精品内容.

关于 51 .c .h .o

看系列篇文章会常看到 51 .c .h .o,希望这对大家阅读不会造成影响. 分别对应以下四个站点的首个字符,感谢这些站点一直以来对系列篇的支持和推荐,尤其是 oschina gitee ,很喜欢它的界面风格,简洁大方,让人感觉到开源的伟大!

而巧合的是.c .h .o是C语言的头/源/目标文件,这就很有意思了,冥冥之中似有天数,将这四个宝贝以这种方式融合在一起. 51 .c .h .o , 我要CHO ,嗯嗯,hin 顺口 : )

百万汉字注解.百篇博客分析

百万汉字注解 >> 精读鸿蒙源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee | github | csdn | coding >

百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点定期更新中< 51cto | csdn | harmony | osc >

关注不迷路.代码即人生

鸿蒙内核源码分析

热爱是所有的理由和答案 - turing

原创不易,欢迎转载,但麻烦请注明出处.

收藏 (0)

相关文章

    文章评论

    共有0条评论来说两句吧...