资讯动态

[Linux系统] 动静态库的制作与使用 | ELF加载 | 动静态链接全流程

发布时间:2026/10/17 6:53:50 来源:尧图企业网站定制
一、库是什么库是写好的、成熟的、可复用的二进制代码本质是可执行代码的二进制形式能被操作系统载入内存执行。库可以初步理解为是所有.o文件的打包分为以下两种类型LinuxWindows链接时机静态库.a.lib链接时拷入可执行文件动态库.so.dll加载/运行时才链接二、静态库与动态库的制作和使用2.1 静态库.agcc-cadd.c sub.c# 先得到目标文件ar-rclibmymath.a add.o sub.o# rreplace, ccreate使用gcc main.c -I./include -L./lib-lmymath-otest-I指定头文件搜索路径-L指定库路径-l指定库名——去掉lib前缀和.a后缀。2.2 动态库.sogcc-fPIC-cadd.c sub.c gcc-shared-olibmymath.so add.o sub.o-fPIC生成位置无关码PIC 相对编址 GOT是动态库被加载到任意地址都能正确工作的前提。使用方式与静态库完全一致。2.3 动态库找不到ldd 显示 not foundQ为什么会显示not found?A-L只告诉了 gcc 去哪找库操作系统并不知道。运行时系统只按固定顺序查找共享库路径找不到就报错。四种解法拷贝.so到系统共享库路径/usr/lib、/lib64等在系统路径下建软链接指向自己的库导出环境变量LD_LIBRARY_PATH追加自己的库路径把库路径写进/etc/ld.so.conf.d/下的配置文件执行ldconfig生效。用ldd 程序名可随时查看可执行程序依赖了哪些动态库。结论gcc/g 默认优先下载/链接动态库找不到.so才退回同名.a。三、ELF 文件一套文件两个视角.o目标文件可执行文件动态库core dumps内核转储这些都是 ELF 文件。ELF 是对二进制代码的一种封装文件头里的魔数MAGIC用于识别二进制文件类型。ELF 有两张关键的表对应两个视角表视角作用节头表section header table链接描述每个section的位置与属性链接时用程序头表program header table执行描述每个segment的起始位置、偏移、长度加载时用section是链接视角的基本单位.text存代码、.data存已初始化数据、.bss存未初始化数据。加载前相同属性的section合并成segment——原因有二单独加载每个 section 会产生页面碎片4097 字节的.text要占 3 页按读/写/执行权限归组便于内核统一管理。于是 ELF 可执行文件的形成只需两步step1多份.c文件分别翻译成.o目标文件和库step2链接时把多份.o和库中的section合并成为可执行文件的segment。四、静态链接全流程预处理 → 编译 → 汇编 → 链接 → 加载 → 运行每步只干一件事预处理文本加工——头文件展开、宏替换、去注释编译生成汇编代码汇编生成.o填入本文件内地址跨文件的函数调用如call printf地址暂时填 0链接合并所有section、统一编址把那些 0 修正成真实地址——这一步叫编译重定位静态重定位加载操作系统按segment的起始地址和长度初始化进程地址空间vm_area_struct 的 [start, end]并填充页表运行从 ELF header 的 Entry 字段拿到入口地址按页表映射找到物理地址执行。链接完成后静态库的代码已全部并入可执行文件运行时不再需要库。五、动态链接全流程同样六步前三步完全相同分岔从链接开始链接不拷贝库代码只记录程序要用哪些库并在.data区预留一张GOT全局偏移表——因为.text只读不可改而.data可读写加载操作系统把程序连同它用到的动态库一起加载进内存每个库的地址按当时内存情况动态分配库地址确定后修正GOT即运行时重定位运行调用库函数时查GOT定位——库的起始虚拟地址 方法偏移量即可找到库中任意方法全程在本进程地址空间内完成。5.1 延迟绑定动态链接在程序加载的时候需要对函数重定位非常耗时因此操作系统做出如下优化GOT的每一项初始并不指向真实函数而是指向桩代码stub首次调用某函数时桩代码查出真实跳转地址并回填GOT之后再次调用直接查表跳转。第一次稍慢后续零开销5.2 三个关键细节每个进程的每个动态库都有独立的GOT进程间不共享——所以库代码可以多进程共用一份各自数据互不干扰位置无关码PIC 相对编址 GOT代码里不写死绝对地址库加载到哪都能跑库与库之间的互相调用同样借助各自的GOT完成加载依赖库的过程就是互相完善 GOT 的过程。六、总结静态链接动态链接库何时参与链接时.o并入可执行文件加载时库单独加载映射重定位编译重定位当场修正运行重定位修GOT延迟绑定再推迟到首次调用可执行文件独立完整、体积大更小只带一张函数入口地址表运行时不再需要静态库需要动态库多进程共享一份代价浪费磁盘和内存牺牲少量性能和加载时间虚拟地址由 ELF 文件生成——程序还没加载进内存时就已统一编址不是内存给的加载的本质是建立页表映射而非搬运/拷贝数据动态链接在链接阶段只留表GOT加载才搬库运行才填地址一个程序可用多个库1 : n一份动态库也被多个进程共享n : 1——后者正是动态库省内存的根源。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑