链接器是如何链接的??

我们知道从代码到可执行程序要经过: 预处理/预编译 - > 编译 -> 汇编 -> 链接 -> 可执行程序,上一篇文章已经详细讲解了预处理 、编译、汇编是怎么进行的,都做了哪些动作,今天我们主要来看看链接器是如何把目标文件(.o/.obj文件)链接到一块的。

第一步:汇编的时候后会生成目标文件,这个目标文件是什么?

我写了两个源文件:

test2.c :

#include <stdio.h>  //引用头文件                                                                          
#define M 1000   //定义字符M 的值为1000                                                                          
#define MUL(x) (x)*(x)  //定义宏                                                                          
extern int Add(int x,int y);                                                                          
int main()                                                                          
{                                                                          
  //打印                                                                          
  printf("预处理过程\n");                                                                          
  printf("i am a Mul:%d\n",MUL(3));                                                                          
  printf("i am a M:%d\n",M);                                                                          
 printf("x+y= %d\n",Add(2,3));                                                                                                            
  return 0;                                                                          
}  

add.c :

  1 #include <stdio.h>
  2 int Add(int x,int y)
  3 {
  4   return x+y;
  5 }                                                                                                                                     

把这两个源文件(.c) 分别生成目标对应的目标文件(.o) :

用readelf查看生成的符号表 :

我们看到在test2.o中的符号有 main 、printf 、Add,在add.o中的符号只有Add,

其实每个符号都有对应的地址,链接的时候就是通过符号和地址找到对应的函数

第二步:链接

链接的时候会做两件事:1.合并段表 2. 符号表的合并和重定位

合并段表很好理解,就是每个.o文件其实是一个elf格式的文件,每个elf文件都有很多段,在链接的时候把各自相同的段合并

我们再来看符号表的合并和重定位:

这个过程它会保留有用的符号和地址,如果地址找不到会报错,例如add.c生成的符号是 Add并且有一个有效地址0x1234(假设),test2.c里声明了函数Add,这里的Add也会生成符号Add但是它的地址是无效的,在链接的过程,相同的符号中会保留一个拥有有效地址的符号,并且和其它的符号main、printf等合并成新的符号表然后跟链接库链接在一起,这样就可以通过符号表把所有目标文件链接在一块了

第三步:生成可执行程序

把目标文件add.o test2.o 生成可执行程序 mybin , ./mybin执行程序,这样一个程序就成功被执行了。

注: 链接库分为静态链接库和动态链接库

静态链接库:静态链接库实现链接操作的方式很简单,即程序文件中哪里用到了库文件中的功能模块,GCC 编译器就会将该模板代码直接复制到程序文件的适当位置,最终生成可执行文件。

动态链接库:动态链接库,又称为共享链接库。和静态链接库不同,采用动态链接库实现链接操作时,程序文件中哪里需要库文件的功能模块,GCC 编译器不会直接将该功能模块的代码拷贝到文件中,而是将功能模块的位置信息记录到文件中,直接生成可执行文件。

GCC 编译器生成可执行文件时,默认情况下会优先使用动态链接库实现链接操作,除非当前系统环境中没有程序文件所需要的动态链接库,GCC 编译器才会选择相应的静态链接库。如果两种都没有(或者 GCC 编译器未找到),则链接失败。

总结:

1. 链接的时候做了两件事:合并段表、符号表的合并和重定位;

2.目标文件其实个elf格式的文件,每个elf文件都有自己的段位,链接的时候会把相同段合并

3.符号表的作用是在链接的时候通过符号和地址找到对应的函数,符号表合并的时候只会保留有有效地址的符号,如果找不到有效地址就会出错。通过合并后的符号表可以把所有目标文件链接在一块

4.链接库分动态链接和静态链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值