ELF文件-符号表

目标文件中的"符号表"(symbol table)中所包含的信息用于定位和重定位程序中的符号定义和符号引用; 目标文件中的其它部分通过一个符号在这个表中的索引值来使用该符号; 索引值从0开始计数,但值为0的索引表项(即第一项)并没有实际的意义,它表示未定义的符号; 用常量STN_UNDEF来表示未定义的符号;
符号表项(Symbol Table Entry)的格式使用结构体Elf32_Sym/Elf64_Sym描述:
struct Elf32_Sym
{
Elf32_Wordst_name; /* Symbol name (string tbl index) */
Elf32_Addrst_value; /* Symbol value */
Elf32_Wordst_size; /* Symbol size */
unsigned char st_info; /* Symbol type and binding */
unsigned char st_other; /* Symbol visibility */
Elf32_Section st_shndx; /* Section index */
};
struct Elf64_Sym
{
Elf64_Wordst_name; /* Symbol name (string tbl index) */
unsigned char st_info; /* Symbol type and binding */
unsigned char st_other; /* Symbol visibility */
Elf64_Section st_shndx; /* Section index */
Elf64_Addrst_value; /* Symbol value */
Elf64_Xwordst_size; /* Symbol size */
};
------字段解释------
st_name:
符号的名字,但它并不是一个字符串,而是字符串表中的一个索引值,在字符串表中该索引值的位置上存放的字符串就是该符号名字的实际文本; 如果此值不为0,则它就代表符号名字在字符串表中的索引值; 如果此值为0,则表示此符号没有名字;
st_value:
符号的值; 这个字段的值没有固定的类型,它可能代表一个数值,也可能是一个地址,具体要依据上下文来确定;
对于不同类型的目标文件,符号表项的st_value的含义也有所不同:
A、在重定位文件中,如果一个符号对应的节的索引值是SHN_COMMON,则它的st_value的值是这个节内容的字节对齐数;
B、在重定位文件中,如果一个符号是已定义的,则它的st_value值是该符号的起始地址在其所在节中的偏移量,而其所在的节的索引值由st_shndx字段给出;
C、在可执行文件和共享库文件中,符号的st_value字段的值是一个虚拟地址,直接指向符号所在的内存位置; 这时,st_shndx就不需要了;
如果一个可执行文件中含有一个函数的引用,而这个函数被定义在一个共享目标文件中,那么在可执行文件中,针对那个共享目标文件的符号表中就应该含有这个函数的符号; 符号表的st_shndx字段的值为SHN_UNDEF,这就告诉动态链接器,这个函数的符号定义并不在可执行文件中; 如果已经在可执行文件中给这个符号申请了一个函数连接表项,而且符号表项的st_value字段的值不是0,那么st_value字段的值就将是函数连接表项中第一条指令的地址; 否则,st_value字段的值就是0; 这个函数连接表项的地址被动态链接器用来解析函数地址;
st_size:
符号的大小; 各种符号的大小各不相同,比如一个对象的大小就是它实际占用的字节数; 如果一个符号的大小为0,或者大小未知,则这个值为0;
st_info:
符号的类型和属性; 该字段由一系列的二进制位构成,标识了"符号绑定(symbol binding)"、"符号类型(symbol type)"和"符号信息(symbol information)"三种属性; 这三种属性分别用下面的宏来读写:
#define ELF32_ST_BIND(val)(((unsigned char)(val))>>4)
#define ELF32_ST_TYPE(val)((val)&0xf)
#define ELF32_ST_INFO(bind,type) (((bind)<<4)+((type)&0xf))
#define ELF64_ST_BIND(val)ELF32_ST_BIND(val)
#define ELF64_ST_TYPE(val)ELF32_ST_TYPE(val)
#define ELF64_ST_INFO(bind,type) ELF32_ST_INFO((bind),(type))
符号绑定(Symbol Binding)属性由宏ELF32_ST_BIND来指定:
STB_LOCAL= 0:本地符号; 该符号只出现在本文件中,在本文件之外,该符号无效; 所以,可在不同文件中定义同名符号,它们且互不影响;
STB_GLOBAL = 1:全局符号; 当有多个文件被链接在一起时,在所有文件中,该符号都是可见的;
STB_WEAK= 2:弱符号; 类似于全局符号,但是相对于STB_GLOBAL,它们的优先级更低;
STB_NUM= 3:已定义的类型的数量;
STB_LOOS= 10;
STB_GNU_UNIQUE=10;
STB_HIOS= 12;
STB_LOPROC = 13;
STB_HIPROC = 15;
在符号表中,不同属性的符号所在的位置也不同,本地符号(STB_LOCAL)排在前面,全局符号(STB_GLOBAL/STB_WEAK)排在后面;
符号类型(Symbol Types)属性由宏ELF32_ST_TYPE来指定:
STT_NOTYPE= 0:本符号的类型未指定;
STT_OBJECT= 1:本符号是一个数据对象; 比如:变量、数组,等等;
STT_FUNC= 2:本符号是一个函数或其它的可执行代码;
STT_SECTION = 3:本符号与一个节相关联,用于重定位; 通常具有STB_LOCAL属性;
STT_FILE= 4:本符号是一个文件符号,符号名字就是文件名字; 具有STB_LOCAL属性,它的节索引值是SHN_ABS; 在符号表中如果存在本类符号的话,它会哦出现在所有STB_LOCAL类符号的前面;
STT_COMMON= 5:本符号是一个通用的数据对象;
STT_TLS= 6:本符号是一个线程本地数据对象;
STT_NUM= 7:已定义的类型数量;
STT_LOOS= 10;
STT_GNU_IFUNC=10;
STT_HIOS= 12;
STT_LOPROC= 13;
STT_HIPROC= 15;
符号信息(Symbol Information)属性由宏ELF32_ST_INFO来指定; 格式定义如下:
struct Elf32_Syminfo
{
Elf32_Half si_boundto; /* Direct bindings, symbol bound to */
Elf32_Half si_flags; /* Per symbol flags */
};
struct Elf64_Syminfo
{
Elf64_Half si_boundto; /* Direct bindings, symbol bound to */
Elf64_Half si_flags; /* Per symbol flags */
};
/* Possible values for si_boundto.*/
SYMINFO_BT_SELF= 0xffff /* Symbol bound to self */
SYMINFO_BT_PARENT= 0xfffe /* Symbol bound to parent */
SYMINFO_BT_LOWRESERVE = 0xff00 /* Beginning of reserved entries */
/* Possible bitmasks for si_flags.*/
SYMINFO_FLG_DIRECT= 0x0001 /* Direct bound symbol */
SYMINFO_FLG_PASSTHRU = 0x0002 /* Pass-thru symbol for translator */
SYMINFO_FLG_COPY= 0x0004 /* Symbol is a copy-reloc */
SYMINFO_FLG_LAZYLOAD = 0x0008 /* Symbol bound to object to be lazy loaded */
/* Syminfo version values.*/
SYMINFO_NONE= 0
SYMINFO_CURRENT = 1
SYMINFO_NUM= 2
读写符号信息:
#define ELF32_ST_VISIBILITY(o)((o) & 0x03)
#define ELF64_ST_VISIBILITY(o)ELF32_ST_VISIBILITY (o)
STV_DEFAULT= 0 /* Default symbol visibility rules */
STV_INTERNAL= 1 /* Processor specific hidden class */
STV_HIDDEN= 2 /* Sym unavailable in other modules */
STV_PROTECTED = 3 /* Not preemptible, not exported */
st_other:
该字段暂未使用,在目标文件中为0;
st_shndx:
任何一个符号表项的定义都与某一个"节"相联系,因为符号是为节而定义的,在节中被引用; 该字段指明了相关联的节; 该字段的值是一个索引值,它指向相关联的节在节头部表中的索引位置; 在重定位过程中,节的位置会改变,该字段的值也随之改变,继续指向节的新位置;
该字段指向下面三种特殊的节索引值时,本符号就具有如下特殊意义:
SHN_ABS:
符号的值是绝对的,具有常量性,在重定位过程中,此值不需要改变;
SHN_COMMON:
本符号所关联的是一个还没有分配的公共节,本符号的值规定了其内容的字节对齐规则,与sh_addralign相似; 也就是说,链接器会为本符号分配存储空间,而且其起始地址是按st_value字段的值对齐的; 本符号的值指明了要分配你的字节数;
SHN_UNDEF:
当一个符号指向第1个节(SHN_UNDEF)时,表明本符号在当前目标文件中未定义,在链接过程中,链接器会找到此符号被定义的文件,并把这些文件链接在一起;


符号表首项:
索引为STN_UNDEF的符号表项的内容为全0,该项的所有字段的值都为0,表示符号未定义;
#define STN_UNDEF 0

    推荐阅读