程序的预处理、编译、汇编、链接

预处理:将源文件中的头文件展开,宏替换,删除注释。预处理是.c到.i文件的过程。

编译:将上一步得到的文件翻译成汇编文件,.i到.s的过程。

汇编:将汇编文件翻译成可重定位的目标文件,这个目标文件已经是二进制文件了,是由多种段组成的,这些二进制文件中的函数和变量称之为符号,这些符号都是从0地址开始往后偏移的,每个目标文件都是这样。这个过程是.s到.o的过程

链接:将不同的目标文件进行组装,组装过程中会进行重定位,因为所有的目标文件组装在一起,所以需要修改不同目标文件中函数和变量的地址,这个修改地址的过程称之为重定位,怎么知道哪些符号需要重定位呢?这是通过重定位表来实现的,链接过程中有两个表很重要,一个是符号表(.symtab),记录了变量和函数的地址以及大小,一个是重定位表,汇编过程中在当前文件内找不到符号的定义,就会把这些符号搜集起来后续进行填充,这个表就是重定位表(.rel)。这两个表是在汇编阶段生成的。

具体是怎么组装的呢?是按照链接脚本规定的段的顺序进行组装的,链接过程还需要指定一个链接地址,这个链接地址可以在链接脚本中进行指定,也可以在链接命令中进行指定来覆盖链接脚本中指定的地址。这也是为了uboot.lds脚本中指定的地址是0x00000000,实际的地址并不是0x00000000,就是因为在链接过程中通过Makefile中的变量进行了指定。

链接过程中链接器会在最后生成的可执行文件中创建一个全局符号表,这样可执行文件中的所有符号都有了自己的地址。

上面说了目标文件是由不同的段构成的:

.text段:代码段,存放程序指令。

.data段:存放已经初始化的全局变量。

.bss段:存放未初始化的全局变量和局部静态变量,BSS段在可执行文件中不占磁盘空间,运行的时候才会分配空间并清0。

静态链接和动态链接

首先明确什么叫静态库,在项目中引用了库函数,编译时,链接器会将我们引用的函数链接到可执行文件里(就是把别人写好的函数拿过来一起进行组装),和可执行程序组装在一起,这种库被称为静态库,在编译阶段链接的库。显而易见,按照这种方法得到的可执行文件占用的空间是很大的,如果多个可执行文件都包含了某些库,那么相当于重复加载,会消耗大量内存。静态链接的优点是不依赖当前的环境,因为文件其中包含了运行的所有内容。

动态链接是怎么回事呢?

动态链接就是在链接阶段,不把我们引用的第三方的库给组装进可执行文件中。当可执行文件真正运行的时候,再把可执行文件依赖的这些第三方的库加载到内存中去,此时完成组装和重定位过程(即链接)。而且这时候加载到内存中的这些库是可以被多个可执行文件共享的,节省了内存。

我们自己制作动态库的时候,制作完成以后需要把这个.so文件放到/lib,/usr/lib这些系统默认的库路径下,否则会链接失败。

Linux中我们运行一个程序,操作系统首先会给程序fork一个子进程,然后动态链接器(其也属于动态库)被加载到内存,操作系统将控制权交给动态链接器,让动态链接器完成动态库的加载和重定位,最后跳转到要运行的程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值