链接原理 (2012-04-20 00:28)
1.链接器的任务
链接器将多个目标文件(可重定位目标文件)链接成一个完整的,可加载的,可执行的目标文件。
主要任务:
(1)符号解析:将目标文件内的引用符号和该符号的定义联系起来
(2)将符号定义与存储器的位置联系起来,修改对这些符号的引用
2.目标文件
(1)可重定位目标文件:这种文件包含二进制代码和数据,代码和数据已经转换成机器指令代码和数据。但是这种目标文件还不能被执行,因为这些指令和数据往往引用其他模块(目标文件)中的符号。其他模块的符号对于本模块是未知的。这些符号的解析需要链接器将所有的模块进行链接。这个操作叫做---重定位。
(2)可执行目标文件:这种文件也包含二进制代码和数据,但是已经被链接过,可以执行。
(3)共享目标文件:在需要他的程序运行或加载时,动态地加载到内存中运行。这种文件的后缀.so。共享目标文件又叫“共享库”或“动态库”文件。
3.elf格式的可重定位目标文件
ELF(Executable linkable file)是linux环境下常用的目标文件格式。大多数情况下,可重定位+可执行的目标文件都采用这种格式。
——————
高 | 段头部表 |
| ------------
| | .strtab |
| ------------
| | .line |
| ------------
| | .debug |
| ------------
| | .rel.data |
| ------------
| | .rel.text |
| ------------
| | .symtab |
| ------------
| | .bss |
| ------------
| | .data |
| ------------
| | .rodata |
| ------------
| | .text |
| ------------
| | ELF 头 |
| -------------
低
(1)ELF文件头的前16字节构成一个字节序,描述了生成该文件系统的字长和字节序。还有一些其他信息,包括ELF文件头的大小,目标文件的类型,目标机类型。
(2).text:代码段,存储二进制的机器代码。
(3).rodata:只读数据段
(4).data:数据段,如初始化的全局数据,包括全局变量和静态变量,都是初始化过的。
(5).bss:块存储段,存储未初始化的全局数据。在目标文件上,该段不占空间,仅仅是一个占位符(?),告知指定位置上应当预留全局数据的空间。
(6).symtab:符号表。存储定义和引用的函数和全局变量,链接过程中的重定位操作就是根据这个表来确定全局符号的位置
(7).rel.text:代码段需要重定位的信息。是一些需要靠重定位操作,来修改位置的符号的汇总。如函数名和标号
(8).rel.data:数据段需要重定位的信息。同上,这些符号在数据段,如全局变量
(9).debug:调试信息。gcc -g 选项可以生成该表。该表包含源程序中所有符号的定义及引用。
(10).line:源程序的行号映射。 也是-g选项生成该段。存储源程序中每一个语句的行号。
(11).strtab:字符串表。存储.symtab&.debug符号表中的名字,是一些字符串,以‘\0’结尾。
4.目标文件中的符号表
每个可重定位目标文件都有一个符号表:.symtab。
里面有三类符号:本模块中引用的其他模块定义的全局符号,本模块中定义的全局符号,本模块中定义和引用的局部符号。
注:局部符号!=局部变量。局部变量在栈中,仅在内存出现,局部符号包括静态变量和局部标号,这些内容可能出现在磁盘文件中。
例子:add.c
点击(此处)折叠或打开
- void add()
- {
- int static count = 2; //静态局部变量,局部符号
- int a = 0; //局部变量
-
- count++; //静态局部变量累加
- if(count>=10)
- goto lab:
- else{
- printf("%d\t",count);
- return;
- }
-
- lab:
- printf("count=%d\t",count);
- a=10;
- printf("a=%d\n",a);
- return ;
- }
readelf -a add.o
5.符号解析
.symtab中的符号,链接器会查找所有参与链接的文件,找到该符号的定义,这个过程叫做符号解析
6.重定位操作
链接器在进行符号解析后,就要进行重定位操作了。链接器将所有参与链接的文件合并,并为每个符号分配存储内容的运行时地址。
包括两方面:重定位段,重定位符号
(1)重定位段:将目标文件中同类型的段合并,生成一个大段。
(2)重定位符号引用:合并段后,各个文件中对符号的引用都已经是无效的,因为现在是一个整体段。链接器要修改这些符号的地址,使其指向正确的运行地址。