ELF(五)符号表

符号表

         符号是表示每个ELF文件的一个重要部分,因为它保存了程序实现或使用的所有(全局)变量和函数。如果程序引用了一个自身代码未定义的符号,则称之为未定义的符号(例如一般程序中printf函数,就定义在c标准函数中)。此类引用必须在静态链接期间用其他目标模块或者库解决,或在加载期间通过动态链接(使用ld-linux.so)解决。nm工具可以生成程序定义和使用的所有符合列表。

         符号表保存了查找程序符号、为符号赋值、重定位符号所需的全部信息。

         符号的主要任务是讲一个字符串和一个值关联起来。例如,printf符号表示printf函数在虚拟地址空间中的地址,该函数的机器代码就存在于该地址。符号也可能有绝对值,由程序解释,例如数值常数。

         以32为为例,

数据结构

/* Symbol table entry.  */

 

typedef struct

{

 Elf32_Word  st_name;          /* Symbol name (string tbl index) */字符串表中的字节偏移,指向符号的以null结尾的字符串名称。

 Elf32_Addr   st_value;           /* Symbol value */符号的地址,是距定义目标的节的起始位置的偏移,对于可执行目标文件来说,该值是一个绝对运行时地址。

 Elf32_Word  st_size;             /* Symbol size */对象的长度,例如一个指针的长度或struct中包含的字节数,如果长度未知,其值可以设置为0。

 unsigned char      st_info;              /* Symbol type and binding */

 其实是unsignedchar type:4,binding:4;type要么是数据要么是函数。binding表示本地还是全局的。

         一个符号的确切用途由st_info定义,它分为两部分。其中定义了下列信息:

         STB_LOCAL局部符号,只在目标文件内可见,在于程序其他部分合并时,是不可见的。如果一个程序的几个目标文件都定义了同名的此类符号,是没有问题的。只要这些都是局部符号,就不会彼此干扰。

         STB_GLOBAL全局符号,在定义的目标文件内部可见,也可以有构成程序的其他目标引用。每个全局符号在一个程序内部都只能定义一次,否则链接器报告错误。

         指向全局符号未定义引用,将在重定位期间确定相关的符号位置。如果对全局符号的未定义引用无法解决,则拒绝程序执行或静态绑定。

         STB_WEAK弱符号,也在整个程序可见,但可以有多个定义。如果程序中的一个全局符号和一个局部符号名称相同,全局符号就优先处理。即使弱符号未定义,程序也可以静态或动态图链接,这种情况下将符号值指定0值。

         STT_OBJECT表示符号关联的一个数据对象,如变量、数组或者指针。

         STT_FUNC表示符号关联到一个函数或者过程。

         STT_NOTYPE表示符号的类型未指定。它用于未定义引用。

         其他还有若干略

 unsigned char      st_other;          /* Symbol visibility */未使用

 Elf32_Section       st_shndx;                   /* Section index */保存一个节的索引(在节头表中),符号将绑定到该节,该符号通常定义在此节的代码中。下列两个值具有特殊意义:

         SHN_ABS指定符号的绝对值,不因重定位而改变

         SHN_UNDEF标示未定义符号,必须通过外部来源(如其他文件或库)解决。

         SHN_COMMON表示还未分配位置的未初始化的数据目标。对于common符号,value字段给出对齐要求,而size给出最小的大小。

} Elf32_Sym;

截图例子

首先通过nm获取所有符号列表:


左侧给出了符号的值,即符号定义在目标文件中的位置。函数定义在text段(由缩写T标明),而未定义的引用由U标明,逻辑上,未定义的引用没有符号值。

         在可执行未见中还会出现更多的符号。但由于多数都是由编译器自动生成的,供运行系统内部使用。

readelf 工具


         源文件名称存储为一个绝对值,它是常数,不随重定位而改变。该局部符号使用STT_FILE类型,将一个目标文件关联到对应的源文件。

         文件中定义的函数main,存储为STT_FUNC类型的全局符号。符号都指向节1,即文件的text节,保存了函数的机器代码。

         puts和printf符号属于未定义引用,节索引值为UND。因而,在程序链接时它们必须关联到标准库中的函数(或其他库中以该名称定义的符号)。因为编译器并不指定所涉及符号的类型,因而这两个符号的类型为STT_NOTYPE。

程序举例(以后补上)

猜你喜欢

转载自blog.csdn.net/ylcangel/article/details/18145287
今日推荐