Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1258437
  • 博文数量: 254
  • 博客积分: 1586
  • 博客等级: 上尉
  • 技术积分: 2295
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-15 16:38
个人简介

linux学习中

文章分类

全部博文(254)

文章存档

2016年(6)

2015年(2)

2014年(74)

2013年(93)

2012年(12)

2011年(2)

2010年(51)

2009年(14)

分类: LINUX

2010-06-10 14:46:39

3.5.1  ELF符号表结构(1)

ELF文件中的符号表往往是文件中的一个段,段名一般叫".symtab"。符号表的结构很简单,它是一个Elf32_Sym结构(32位ELF文件)的数组,每个Elf32_Sym结构对应一个符号。这个数组的第一个元素,也就是下标0的元素为无效的"未定义"符号。Elf32_Sym的结构定义如下:

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;

这几个成员的定义如表3-14所示。

表3-14

st_name

符号名。这个成员包含了该符号名在字符串

表中的下标(还记得字符串表吧?)

st_value

符号相对应的值。这个值跟符号有关,可能

是一个绝对值,也可能是一个地址等,不同的符号,

它所对应的值含义不同,见下文“符号值”

st_size

符号大小。对于包含数据的符号,这个值是该数据

类型的大小。比如一个double型的符号它占用8个字节。

如果该值为0,则表示该符号大小为0或未知

st_info

符号类型和绑定信息,见下文“符号类型与绑定信息”

st_other

该成员目前为0,没用

st_shndx

符号所在的段,见下文“符号所在段”

符号类型和绑定信息(st_info) 该成员低4位表示符号的类型(Symbol Type),高28位表示符号绑定信息(Symbol Binding),如表3-15、表3-16所示。

表3-15

符号绑定信息

宏定义名

说明

STB_LOCAL

0

局部符号,对于目标文件的外部不可见

STB_GLOBAL

1

全局符号,外部可见

STB_WEAK

2

弱引用,详见“弱符号与强符号”

表3-16

符号类型

宏定义名

说明

STT_NOTYPE

0

未知类型符号

STT_OBJECT

1

该符号是个数据对象,比如变量、数组等

STT_FUNC

2

该符号是个函数或其他可执行代码

STT_SECTION

3

该符号表示一个段,这种符号必须是

STB_LOCAL

STT_FILE

4

该符号表示文件名,一般都是该目标文

件所对应的源文件名,它一定是

STB_LOCAL类型的,并且它的

st_shndx一定是SHN_ABS

符号所在段(st_shndx)如果符号定义在本目标文件中,那么这个成员表示符号所在的段在段表中的下标;但是如果符号不是定义在本目标文件中,或者对于有些特殊符号,sh_shndx的值有些特殊,如表3-17所示。

表3-17

符号所在段特殊常量

宏定义名

说明

SHN_ABS

0xfff1

表示该符号包含了一个绝对的值。

比如表示文件名的符号就属于这种类型的

SHN_COMMON

0xfff2

表示该符号是一个“COMMON块”

类型的符号,一般来说,未初始化的全局

符号定义就是这种类型的,比如

SimpleSection.o里面的global_uninit_var

有关“COMMON”详见“深入静态链接”

之“COMMON块”

SHN_UNDEF

0

表示该符号未定义。这个符号表示该符号

在本目标文件被引用到,但是定义在其他目标文件中

 

3.5.1  ELF符号表结构(2)

符号值(st_value) 我们前面已经介绍过,每个符号都有一个对应的值,如果这个符号是一个函数或变量的定义,那么符号的值就是这个函数或变量的地址,更准确地讲应该按下面这几种情况区别对待。

在目标文件中,如果是符号的定义并且该符号不是"COMMON块"类型的(即st_shndx不为SHN_COMMON,具体请参照"深入静态链接"一章中的"COMMON块"),则st_value表示该符号在段中的偏移。即符号所对应的函数或变量位于由st_shndx指定的段,偏移st_value的位置。这也是目标文件中定义全局变量的符号的最常见情况,比如SimpleSection.o中的"func1"、"main"和"global_init_var"。

在目标文件中,如果符号是"COMMON块"类型的(即st_shndx为SHN_COMMON),则st_value表示该符号的对齐属性。比如SimpleSection.o中的"global_uninit_var"。

在可执行文件中,st_value表示符号的虚拟地址。这个虚拟地址对于动态链接器来说十分有用。我们将在第3部分讲述动态链接器。

根据上面的介绍,我们对ELF文件的符号表有了大致的了解,接着将以SimpleSection.o里面的符号为例子,分析各个符号在符号表中的状态。这里使用readelf工具来查看ELF文件的符号,虽然objdump工具也可以达到同样的目的,但是总体来看readelf的输出格式更为清晰:

$ readelf -s SimpleSection.o
Symbol table '.symtab' contains 15 entries:
Num:    Value  Size
Type    Bind   Vis      Ndx Name
0: 00000000
0
NOTYPE  LOCAL  DEFAULT  UND
1: 00000000
0
FILE    LOCAL  DEFAULT  ABS SimpleSection.c
2: 00000000
0
SECTION LOCAL  DEFAULT    1
3: 00000000
0
SECTION LOCAL  DEFAULT    3
4: 00000000
0
SECTION LOCAL  DEFAULT    4
5: 00000000
0
SECTION LOCAL  DEFAULT    5
6: 00000000
4
OBJECT  LOCAL  DEFAULT    4 static_var2.1534
7: 00000004
4
OBJECT  LOCAL  DEFAULT    3 static_var.1533
8: 00000000
0
SECTION LOCAL  DEFAULT    7
9: 00000000
0
SECTION LOCAL  DEFAULT    6
10: 00000000
4
OBJECT  GLOBAL DEFAULT    3 global_init_var
11: 00000000  27
FUNC    GLOBAL DEFAULT    1 func1
12: 00000000
0
NOTYPE  GLOBAL DEFAULT  UND printf
13: 0000001b  64
FUNC    GLOBAL DEFAULT    1 main
14: 00000004
4
OBJECT  GLOBAL DEFAULT  COM global_uninit_var

readelf的输出格式与上面描述的Elf32_Sym的各个成员几乎一一对应,第一列Num表示符号表数组的下标,从0开始,共15个符号;第二列Value就是符号值,即st_value;第三列Size为符号大小,即st_size;第四列和第五列分别为符号类型和绑定信息,即对应st_info的低4位和高28位;第六列Vis目前在C/C++语言中未使用,我们可以暂时忽略它;第七列Ndx即st_shndx,表示该符号所属的段;当然最后一列也最明显,即符号名称。从上面的输出可以看到,第一个符号,即下标为0的符号,永远是一个未定义的符号。对于另外几个符号解释如下。

func1和main函数都是定义在SimpleSection.c里面的,它们所在的位置都为代码段,所以Ndx为1,即SimpleSection.o里面,.text段的下标为1。这一点可以通过readelf -a或objdump -x得到验证。它们是函数,所以类型是STT_FUNC;它们是全局可见的,所以是STB_GLOBAL;Size表示函数指令所占的字节数;Value表示函数相对于代码段起始位置的偏移量。

再来看printf这个符号,该符号在SimpleSection.c里面被引用,但是没有被定义。所以它的Ndx是SHN_UNDEF。

global_init_var是已初始化的全局变量,它被定义在.bss段,即下标为3。

global_uninit_var是未初始化的全局变量,它是一个SHN_COMMON类型的符号,它本身并没有存在于BSS段;关于未初始化的全局变量具体请参见"COMMON块"。

static_var.1533和static_var2.1534是两个静态变量,它们的绑定属性是STB_LOCAL,即只是编译单元内部可见。至于为什么它们的变量名从"static_var"和"static_var2"变成了现在这两个"static_var.1533"和"static_var2.1534",我们在下面一节"符号修饰"中将会详细介绍。

对于那些STT_SECTION类型的符号,它们表示下标为Ndx的段的段名。它们的符号名没有显示,其实它们的符号名即它们的段名。比如2号符号的Ndx为1,那么它即表示.text段的段名,该符号的符号名应该就是".text"。如果我们使用"objdump -t"就可以清楚地看到这些段名符号。

"SimpleSection.c"这个符号表示编译单元的源文件名。

阅读(3277) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~