Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3036422
  • 博文数量: 167
  • 博客积分: 613
  • 博客等级: 中士
  • 技术积分: 5473
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-13 21:35
个人简介

人, 既无虎狼之爪牙,亦无狮象之力量,却能擒狼缚虎,驯狮猎象,无他,唯智慧耳。

文章分类
文章存档

2015年(19)

2014年(70)

2013年(54)

2012年(14)

2011年(10)

分类: C/C++

2011-10-22 19:24:37

Chapter 7 Linking

任何一个源代码如果要变成一个可执行代码,就必须经过链接的过程。链接就是将各种代码和数据部分收集起来并合并成为一个单一文件的过程,最终这个文件可以被加载到存储器并执行。根据链接的阶段,我们可以简单地分成三种链接:
编译时:(compile time)如在编写好源码文件后直接编译链接成可执行文件。此时所得到的文件已经包含了执行所需要的所有数据和代码,可以在任意系统上直接执行
加载时:(load time)如利用动态链接共享库,在程序执行过程中链接器完成链接,不向可执行文件中加入任何代码和数据
运行时:(run time)如在进程中新建线程执行LoadLibrary()载入DLL库
******
Linux下编译程序步骤:
main.c----by C预处理器(cpp)---main.i[ASC2码中间文件]---by C编译器(ccl)---main.s[ASC2汇编文件]---by 汇编器(as)---main.o[relocatable object file]---by ld---p[executable object file]
******
链接器的主要作用:
1)符号解析:链接器将多个源码文件中的函数,变量引用与其相应的定义建立映射,以便程序运行时正确的访问相关引用,如函数,全局变量等
2)重定位:可重定位目标文件中的元素地址是相对于“0”的相对偏移。链接器要将每个符号(函数,变量)定义与一个存储器位置联系起来,然后修改所有对这些符号的引用。
在经过编译器和汇编器之后,系统并不晓得各种符号,指令的位置,但是在链接阶段,所有必须的文件模块均已完毕,系统了解了程序的整体情况,所以可以为其分配指定存储器地址
******
可重定位目标文件
类Unix系统对于目标文件统一使用ELF格式(Executable and Linkable),夹在ELF头和节头部表之间的都是节,常用的有以下几个:
.text--已经编译程序的机器代码
.rodata--只读数据,比如Printf函数的格式控制串
.data--已经初始化的全局C变量,局部C变量保存在栈中
.bss--未初始化的全局C变量,通常不占用空间
.symtab--符号表,它存放了在程序中定义和引用的函数和全局变量的信息,局部变量信息不在此表中
rel.text--针对.text记录的指令的位置的列表。当链接器将这个目标文件和其他文件结合时,需要修改这些位置。一般任何调用外部函数或者引用全局变量的指令都需要修改
rel.data--模块引用或者定义的任何全局变量的重定位信息
PS:每个可重定位目标模块M都有自己的符号表.symtab,它包含M定义或引用的符号的信息,这里面不包含本地局部变量,但是却包含本地静态变量。
******
符号解析
符号解析就是要为用到的符号都对应一个有效的定义。本地的符号是简单的,对于多重定义的全局符号,链接器解析时则遵循一些规则:
设定 函数和已初始化的全局变量是强符号,未初始化的全局变量是弱符号
1.不允许有多个强符号
2.一强多弱时,选择强符号
3.若有多个弱符号,任意选择一个
链接器使用静态库来解析引用:
使用静态库时,要注意依赖关系并由此决定它们之间的顺序,如依赖关系用-->表示,则
p.o-->libx.a    gcc p.o libx.a
p.o-->libx.a-->liby.a且liby.a-->libx.a-->p.o  gcc p.o libx.a liby.a
这里,链接器会区分目标文件和存档文件,链接器从目标文件中读取未定义的符号,记入集合U;而后在存档文件中查找相关的符号定义,找到就将符号计入集合E,摒弃存档文件中未被请求的定义;执行完毕后检查U是否为空,若不空,则返回一个错误。

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