在链接中,目标文件之间相互拼合实际上是目标文件之间对地址的引用,即对函数和变量的地址的引用(Reference)。
我们将函数和变量统称为符号(symbol),函数名或变量名即符号名。
每一个目标文件都有一个相应的符号表,记录了该目标文件中用到的所有符号。
每个定义的符号有一个对应的值,即符号值,对于变量和函数来说,符号值即它们的地址。
类型:(以SimpleSection.o为例)
1.定义在本目标文件的全局符号,可以被其他目标文件引用。如"func1"、"main"、"global_init_var"。
2.在本目标文件中引用的全局符号,却没有定义在本目标文件,即外部符号(External Symbol)。如“printf”。
3.段名,其值为该段的起始地址。
4.局部符号,这类符号只在编译单元内部可见。链接器往往会忽略它们,因为没用。
5.行号信息(可选的)。
查看符号表
ELF符号表往往是文件中的一个段“.symtab”,是一个Elf32_Sym结构(对应一个符号)的数组。
查看ELF文件的符号
Num:表示符号表数组的下标。
Value:符号值。对于函数,是其相对于代码段起始位置的偏移量。
Size:符号大小。
Type:符号类型。
Bind:绑定信息。
Vis:暂无。
Ndx:表示该符号所属的段。(可通过readelf -a 或 objdump -x 验证)
Name:符号名称。
---------------------------------------------------------------------------------------------------------------------------------------------------------
特殊符号
当使用ld作为链接器来链接生产可执行文件时,它会为我们定义很多特殊符号,这些符号并没有在你的程序中定义,但你可以直接声明并引用它。
这些符号被定义在链接脚本中。链接器会在将程序最终链接成可执行文件的时候将其解析成正确的值。
__executable_start 该符号为程序起始地址,是程序的最开始的地址。不是入口地址。
__etext or _etext or etext 代码段结束地址。
_edata or edata 数据段结束地址。
_end or end 程序结束地址。
以上地址都是程序被装载时的虚拟地址。
-------------------------------------------------------------------------------------------------------------------------------------
符号修饰与函数签名
缺省
------------------------------
extern "C"
C++为了和C兼容,C++有一个用来声明或定义一个C的符号的“extern "C"”关键字用法:
extern "C"{
int func(int);
int var;
}
缺省
-----------------------------------------------------------------------------------------------------
调试信息
gcc编译时加“-g”参数在目标文件中加上调试信息
$strip foo去掉ELF文件中的调试信息
现在的ELF文件采用DWARF(Debug With Arbitrary Record Format)