黑龙江住房和城乡建设厅网站首页,wordpress移动导航菜单,专业网站制作仪表多少钱,玖久建筑网文章目录【第2部分】静态链接1 编译过程2 编辑器的工作流程3 链接——模块的拼接4 目标文件目标文件中的段#xff08;section#xff09;ELF文件结构5 静态链接1 空间与地址分配2 符号解析与重定位【第3部分】装载与动态链接1 装载的方式2 进程的启动3 为什么需要动态链接sectionELF文件结构5 静态链接1 空间与地址分配2 符号解析与重定位【第3部分】装载与动态链接1 装载的方式2 进程的启动3 为什么需要动态链接4 动态链接的基本实现5 位置无关码PIC6 显式运行时链接Explicit Run-time Linking【第2部分】静态链接 1 编译过程
预编译 预编译将源文件和包含的头文件编排成xx.i的预编译文件主要是将#include的文件内容替换进源文件并且将宏定义#define展开还有处理预编译指令#if、#ifdef等以及删除注释等等。编译 简单来说就是将C语言代码转换成汇编代码汇编 汇编器将汇编代码转换成机器码产出一个xx.o目标文件链接 对目标文件进行编排组合成可执行文件或者库目标文件的包。
2 编辑器的工作流程
词法分析-语法分析-语义分析-源代码优化-目标代码生成和优化。
3 链接——模块的拼接
问题引入当一个程序被分割成多个模块时最终如何组成的一个可执行程序
链接的过程包括
地址和空间分配符号决议symbol resolution或符号绑定symbol binding重定位relocation——给程序中引用某个绝对地址的指令打补丁
链接器会根据指令所引用的符号找到符号的地址然后修正指令。
4 目标文件
Linux上我们统称目标文件和可执行文件为ELF格式的文件广义上他们几乎是一样的。
ELF文件有以下4大类
Relocatable File —— xx.oExecutable FileShared Object File —— .soCore Dump File
目标文件中的段section ELF文件结构
文件头-ELF Header 可以使用readelf -h xx.o来查看文件头。段表-Section Header Table 使用readelf -S来查看ELF文件包含的段。重定位表-Relocation Table0 .rel.text和.rel.data记录重定位信息字符串表 把字符串集中起来存放到一个表里然后通过使用偏移地址来引用字符串结尾为空字符包括.strtab符号名的字符串和.shstrtab段名的字符串
5 静态链接
1 空间与地址分配
扫描所有目标文件收集所有的符号定义和符号引用放到全局符号表中计算出各个文件的各个段在合并后的位置以及长度建立映射关系。
2 符号解析与重定位
在编译文件时一些函数是在外部文件中定义的编译器并不知道它的地址就暂时将它们的地址设为0真正的地址计算和修改则留给链接器。
那么链接器如何知道哪些指令中使用的地址需要重定位这时就轮到重定位表发挥作用了重定位表记录了每个符号的入口地址在表中的偏移地址。
【第3部分】装载与动态链接
1 装载的方式
覆盖装入由程序员管理模块何时被加载到内存该方式已被淘汰页映射以页为单元在磁盘和内存之间装载或置换数据
2 进程的启动
创建虚拟地址空间通过MMU映射到物理内存读取可执行文件的文件头建立虚拟地址空间和可执行文件的映射关系用于加载可执行文件所在的页到内存将CPU指令寄存器设置成可执行文件入口
3 为什么需要动态链接
只使用静态链接会造成内存和磁盘的浪费使用静态链接时如果某个模块更新那么整个程序都要重新编译
动态链接等到程序开始运行时才进行链接。
4 动态链接的基本实现
程序装载时动态链接器将所需要的动态库装载到进程地址空间将所有未决议的符号绑定到相应的动态链接库并进行重定位工作。
为了优化程序装载时进行链接的性能问题采取了延迟绑定等方法。
用cat /proc/xxxx/maps即可查看某个进程的的虚拟地址空间分布其中可以看到部分引用的.so动态库所被映射的位置其中有一个库为ld-x.x.so这实际上就是linux的动态链接器进程运行前会先跳转到动态链接器的代码中运行完成链接工作后再跳转回进程代码运行。
5 位置无关码PIC
装载时重定位——把动态库的重定位也推迟到装载时进行。但有一个问题动态链接库的代码在多个进程间共享而重定位需要修改其指令每个进程需要的修改可能不一样比如跳转的地址不一样那么就没法共享了。
PIC的基本思想将指令中需要修改的部分分离出来放到数据段中这样指令部分就可以保持不变而数据段对于每个进程都是有自己的独一份的。
模块间的数据访问在数据段里建立一个指向外部变量的指针数组即全局偏移表Global Offset TableGOT。在编译时即确定GOT相对于当前指令的偏移同时确定GOT中每个地址对应于哪个变量模块装载时加载器查找每个变量的实际地址填充GOT的各个项。
如何区分动态库是否为PICreadelf -d xx.so | grep TEXTREL如果输出为空则不是PIC。so库必须是PIC才能真正实现共享。
6 显式运行时链接Explicit Run-time Linking
或者叫运行时加载即程序运行时自己指定加载的模块且可以在不需要时将模块卸载。这可以用来实现插件、驱动等。程序可以通过4个API对动态库进行操作
dlopen()加载动态库到进程地址空间dlsym()找到所需的符号所在的地址dlclose()卸载模块dlerror()调用上面3个函数后可以通过调用该函数判断前者调用是否成功