库的制作与原理2.0---动静态链接,main全解析,CPU在执行文件时的作用,GOT表。 bit::Shadow✧(≖ ◡ ≖✿目录静态库链接Section段ELF文件加载与地址、进程objdump -S 【-g选项下的可执行文件/.o文件】☆☆☆可执行文件在操作系统的处理可执行文件的起始入口地址CPU处理可执行程序流程CPU图CPU处理功能区完整流程int main()前言动态链接动静态执行程序的区别连接器内核中程序是怎样和动态库映射起来的程序是怎么进行库函数的调用的GOT表的影响总结上篇静态库链接Section段静态链接就是将编译后的所有.o目标文件与用到的一些静态库拼接成为一个独立的可执行文件。其中包括地址修正当所有模块组合在一起后链接器根据我们的.o文件及静态库中的重定位表找到那些需要被重定位的函数全局变量修正它们的地址。这就是静态链接的过程。此过程可以很好的用下图表示出来Section下拥有许多节.text .data .bss .symtab等等据此.o目标文件也被称为可重定位目标文件重定位体现在数据段、代码段的重新定位组合。ELF文件加载与地址、进程前言当文件编译好后地址就已经(并未加载到内存)是虚拟地址。*虚拟地址自0从上向下增加。objdump -S 【-g选项下的可执行文件/.o文件】将文件的代码与源代码混合显示。objdump -S a.out txt.s #此处.s类型文件是为了高亮显示-S生成的并非真正的汇编类型最左侧就是映射的虚拟地址严格来说是“逻辑地址”起始地址0 偏移量。基于此图探讨CPU处理可执行程序☆☆☆可执行文件在操作系统的处理Entry point address作为可执行文件在磁盘中读取的入口地址可执行文件的起始入口地址_start是程序真正的入口点CPU处理可执行程序流程磁盘加载到内存内存映射到页表(在执行可执行程序前已经确定)CPU图CPU处理功能区EIP指令指针寄存器CPU从EIP中读取下一条指令的虚拟地址线性分布。CR3存放当前进程页目录的表的物理基址。在进程切换时新进程的物理地址写入CR3。MMU内存管理单元使用CR3把EIP的虚拟地址转成物理地址去内存取指令。完整流程EIP提供虚拟地址-MMU翻译为物理地址-读取物理内存中的指令字节-送回CPU译码执行-EIP自增进入下一轮。int main()前言_start是语言程序真正的入口点它会调用__libc_start_main来初始化C运行时环境然后调用你的main函数。现在这个阶段你应该能看懂以下图解动态链接体现在动态链接中推迟动静态执行程序的区别静态加载是文件在编译时就已经确定了call的地址因此在执行时是包含于代码区内部的跳转。动态加载是执行时从代码区跳转到共享区执行。对比项静态库 (.a)动态库 (.so)链接时机编译链接时程序加载/运行时代码归属复制进可执行文件独立文件程序依赖它文件大小大包含库代码小不含库代码内存占用高每个程序一份低多程序共享一份独立性独立运行不需库文件需要库文件存在更新库需重新编译程序替换库文件即可启动速度快稍慢需加载/链接链接命令gcc main.c libfoo.agcc main.c -lfoo库命名libxxx.alibxxx.so连接器链接器是将多个目标文件(.o)和库文件合并成可执行文件或共享库的工具。连接器的库体现绿色框内就是一个动态链接器。内核中程序是怎样和动态库映射起来的动态库也是一个文件要访问也是要被先加载要加载也是要被打开的。进程找到动态库的本质也是文件操作不过我们访问库函数是通过虚拟地址跳转访问的所以需要把动态库映射到进程的地址空间中。程序是怎么进行库函数的调用的通过GOT全局偏移量表来实现相对位置与绝对位置的映射。这种方式实现的动态链接校正PIC点地址无关代码换句话说我们的动态库位于虚拟内存无需做任何修改下当各个进程运行到此处链接时使用GOT表来实现动态库的定位。因此.o文件也叫做可重定向目标文件。GOT表的影响进程间独立每个进程都有自己的虚拟地址表对应独立的GOT表。-fPIC的产生的原因GOT下这种方式实现的动态链接叫做PIC地址无关码。换句话说我们的动态库无需做任何修改被加载到任意内存地址都可以运行并且被所有进程所共享这就是为什么给编译器指定-fPIC的原因PIC相对编址GOT。总结静态链接的出现提高了程序的模块化水平。对于一个大的项目不同的人可以独立地测试和开发自己的模块通过静态链接生成最终的可执行文件。我们知道静态链接会将编译产生的所有目标文件和用到的各种库合并成一个独立的可执行文件其中我们会修正模块间函数的调整地址也被叫做编译重定位。而动态链接实际上是将整个过程推迟到了程序加载的时候。比如我们去运行一个程序操作系统会首先将程序的数据代码连同它用到的一系列动态库先加载到内存其中每个动态库的加载地址都是不固定的每次程序启动加载但是无论加载到什么地方都要映射到进程对应的地址空间然后通过GOT表的方式进行调用运行重定位也叫做动态地址重定位。倾囊相授持续深耕Linux欢迎关注