动静态库原理与ELF文件详解
1. 什么是库所有的库本质都是源文件对应的 .o 文件动静态库中不要包含 main 函数静态库: .a[linux]、.lib[windows]动态库:.so[linux]、.dll[windows]2. 静态库静态库.a程序在链接的时候把代码链接到可执行文件中程序运行的时候不再需要静态库编译默认使用动态链接库gcc的 -static 强制设置链接静态库2.1 静态库生成静态库命名必须遵守 libxxx.aar -rc libmyc.a *.o # 把所有 .o 文件打包成 xxx.a2.2 静态库使用# 场景1头文件和库文件安装到系统路径下 gcc main.c -lmystdio # 场景2头文件和库文件和我们的源文件在同一个路径下 gcc main.c -L . -lmymath # 场景3头文件和库文件有自己的独立路径 gcc main.c -I 头文件路径 -L 库文件路径 -lmymath选项可以不留空格-L指定库路径-I大写指定头文件搜索路径-l小写指定库名库文件名称和引入库的文件去掉前缀 lib 和 后缀 .a / .so 如 libc.a - c3. 动态库动态库.so程序在运行的时候才去链接动态库的代码多个程序共享使用库的代码动态库可以在多个程序间共享所以动态链接使得可执行文件更小节省磁盘空间3.1 动态库生成# 1. 生成位置无关的目标文件 .o gcc -c -fPIC test.c add.c ... # 2. 生成动态库 gcc -shared -o libmy.so *.oshared表示生成共享库模式fPIC产生位置无关码库文件名称和引入库的文件去掉前缀 lib 和 后缀 .a / .so 如 libc.so - c3.2 动态库的使用gcc main.c -I 头文件路径 -L 库文件路径 -lmymath选项可以不留空格L指定库路径I大写指定头文件搜索路径l小写指定库名3.3 库运行搜索路径问题编译时用 -L 能找到库生成可执行文件但是系统不知道导致运行时找不到对应库文件解决方法拷贝 .so 文件到系统共享库路径下一般指 /usr/lib、/usr/local/lib、/lib64 或者开篇指明的库路径向系统库路径下建立同名软连接更改环境变量临时常用LD_LIBRARY_PATHldconfig方案配置 /etc/ld.so.conf.d/,使用ldconfig更新3.4 总结结论1gcc/g默认使用动态库想用静态链接只能提供静态库并加 -static结论2在linux系统下默认情况安装的大部分库默认都优先安装的是动态库结论3库应用程序 1n结论4vs不仅仅形成可执行程序也能形成动静态库4. 目标文件.o/.obj可重定位目标文件目标文件.o文件是一个二进制文件文件格式是 ELF是对二进制代码的一种封装动静态库、可执行程序、可重定位目标文件都是 ELF 格式的5. ELF文件ELF文件可重定位目标文件即 xxx.o 文件可执行文件即可执行程序共享目标文件即 xxx.so 文件(静态库是 xxx.o 的打包压缩包不属于)内核转储存放当前程序的执行上下文用于dump信号触发ELF文件组成ELF头描述文件的主要特性程序头表列举所有有效的段和属性节头表包含对节的描述节ELF文件的组成单位包含特定类型的数据代码节(.txt)保存机器指令是程序的主要执行部分数据节(.data)保存已初始化的全局变量和局部静态变量6.ELF从形成到加载轮廓6.1 ELF形成可执行step1前置步骤将多份 C/C 源代码翻译成目标 .o 文件 动静态库ELFstep2将多份 .o 文件 section 进行合并6.2 ELF可执行文件加载一个 ELF 会有多种不同的 Section在加载到内存的时候也会进行 Section 合并形成 segment合并原则相同属性比如可读可写可执行需要加载时申请空间等为什么要将 section 合并成为 segment为了减少页面碎片提高内存效率链接视图 – 对应节头表 Section header table静态链接的时候一般关注的是链接视图执行视图 – 对应程序头表 Program header table如何加载可执行文件告诉操作系统哪些模块可以被加载进内存ELF HEADER主要目的是定位文件的其他部分7. 链接与加载7.1 静态链接研究静态链接本质就是研究 .o 是如何加载的在 .o 文件中不知道调用函数的地址所以在汇编时编译器只是将函数的跳转地址先暂时设为0链接的时候这个地址会修正多个 .o 合并之后在最终的可执行程序中就知道函数对应的地址了静态链接就是把库中的 .o 进行合并并修正他们的地址链接过程中会涉及到对 .o 中外部符号进行地址重定位7.2 ELF加载与进程地址空间7.2.1 虚拟地址/逻辑地址一个ELF程序在没有被加载到内存的时候就有地址ELF的逻辑地址起始地址偏移量认为是起始地址0进程 mm_struct、vm_area_struct 在刚创建的时候数据从哪里来从 ELF 各个 segment 来每个 segment 都有自己的起始地址和自己的长度用来初始化内核结构中的 [start,end] 等范围数据秒另外再用详细地址填充页表虚拟地址机制不光要OS支持编译器也要支持7.2.2 理解进程地址空间磁盘里的 ELF 存的是虚拟地址加载到内存后内核建立虚拟地址到物理地址的映射CPU 永远用虚拟地址由 MMU 转成物理地址去执行mm_struct 和 vm_area_struct 管理这个映射关系真正的映射写进页表7.3 动态链接与动态库加载库函数调用1.被进程看到动态库映射到进程的地址空间2.被进程调用在进程的地址空间中进行跳转7.3.1 进程如何看到动态库进程通过虚拟地址看到动态库7.3.2 进程间如何共享库的动态库中的代码不会重复出现了7.3.3 动态链接7.3.3.1 概要静态链接会将编译产生的所有目标文件连同用到的各种库合并形成一个独立的可执行文件静态链接的最大问题在于生成的文件体积大并且相当耗费内存资源动态链接将连接的整个过程推迟到了程序加载的时候将需要共享的代码提取出来保存成一个独立的动态链接库等到程序运行的时候再将它们加载到内存不但可以节省空间还因为同一模块在内存中只需要保留一份副本可以被不同的进程共享7.3.3.2 可执行程序_start 函数会调用动态链接器的代码来解析和加载程序所依赖的动态库sharedlibraries。动态链接器会处理所有的符号解析和重定位确保程序中的函数调用和变量访问能够正确地映射到动态库中的实际地址环境变量和配置文件指定动态库搜索路径7.3.3.3 怎么进行库函数调用访问库中任意方法只需要知道库的起始虚拟地址方法偏移量即可定位库中的方法整个调用过程是从代码区跳转到共享区调用完毕再返回代码区整个过程完全在进程地址空间中进行7.3.3.4 全局偏移量表GOT每个进程的每个动态库有独立的 GOT 表所有进程间不能共享 GOT 表在调用函数的时候会先查表然后根据表中的地址来进行跳转这些地址在动态库加载的时候会被修改为真正的地址7.3.3.5 库间依赖库也会调用其他库库之间是有以来的库中也有 GOT库在被调用到时才对函数进行重定位延迟绑定PLT动态链接实际上将链接的整个过程从编译(准确来说是汇编)时推迟到了程序的运行时
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2422209.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!