Linux:库制作与原理(四)

动态链接不神秘------GOT/PLT 让 .so 真正跑起来

关键词:动态库、ldd、LD_LIBRARY_PATH、ldconfig、GOT、PLT、PIC

适合:总被 "error while loading shared libraries" 折磨的人

1.动态库 vs 静态库:本质差异是"什么时候把代码放进来"

  • 静态库 .a编译链接时 把库代码塞进可执行文件,运行时不依赖 .a

  • 动态库 .so:可执行文件里通常只记录"需要哪些符号/入口",运行时由系统把库映射进内存并完成符号解析

你可以用 ldd 看依赖关系:

ldd main.exe

输出会列出依赖的共享库,以及动态链接器(例如 /lib64/ld-linux-x86-64.so.2

2.经典报错:libxxx.so => not found 怎么办?

ldd a.out 显示 libmystdio.so => not found,说明运行时找不到库。解决方向就三类:

方案 A:把 .so 放进系统共享库目录

常见:/usr/lib/usr/local/lib/lib64 等。

方案 B:配置搜索路径 + 更新缓存(推荐更规范)

/etc/ld.so.conf.d/ 新增配置文件,写入你的库目录,然后运行:

ldconfig

系统会更新 /etc/ld.so.cache,动态链接器加载更快。

方案 C:临时用环境变量(开发调试常用)

export LD_LIBRARY_PATH=/your/so/path:$LD_LIBRARY_PATH

3.程序真正从哪开始跑?不是 main,是 _start

很多人以为执行文件一运行就进 main(),但实际上入口点是 _start。它会做一堆"你感觉不到"的初始化:

  1. 初始化栈

  2. 初始化数据段(复制 data、清零 bss)

  3. 关键:调用动态链接器完成依赖库加载、符号解析与重定位

  4. 再调用 __libc_start_main,最终才进入 main

这也是为什么 ldd 输出里会出现 ld-linux:它就是动态链接器。

4.代码段只读,那动态链接怎么"改地址"?

这就引出灵魂问题:

运行时要把外部函数地址修正到正确位置,可 .text(代码段)一般是只读的,怎么改?

答案:不改代码段,改 GOT 表

GOT(Global Offset Table)

GOT 通常位于 .data 可写区域:专门存放"外部函数/全局变量的真实地址"。动态链接器在加载库后,把 GOT 里的条目填成正确地址。

你能在 readelf -S a.out 里看到 .got,并且它在加载时往往会和 .data/.bss 合到同一个可写 segment。

5.PIC:为什么编译动态库要 -fPIC

动态库需要被加载到"任意位置",所以内部不能写死绝对地址;它依赖相对寻址 + GOT 来定位外部符号,这就是 PIC(Position Independent Code)。

典型 Makefile 写法是:

  • 编译 .ogcc -fPIC -c ...

  • 链接 .sogcc -shared -o libxxx.so ...

6.PLT:为啥第一次调用慢,后面就快了?

如果程序启动就把所有外部函数都解析完,成本太高。于是引入 延迟绑定(lazy binding),常见机制就是 PLT(Procedure Linkage Table)+ GOT:

  • 第一次调用某个外部函数:先跳到 PLT 的"桩代码",由它去解析真实地址并写回 GOT

  • 后续调用:直接从 GOT 拿到真实地址,直接跳转

这就是你常听到的:"第一次调用慢一些,后面就稳了"。

7.你真正掌握动态链接的标志:能把这 4 件事讲清楚

  1. 系统怎么找 .so (目录、LD_LIBRARY_PATHldconfig 缓存)

  2. 加载从 _start 开始,动态链接器参与早期初始化

  3. GOT 解决可写重定位 (不碰只读 .text

  4. PLT 做延迟绑定,把"解析开销"推迟到第一次调用

相关推荐
湘-枫叶情缘3 分钟前
1990:种下那棵不落叶的树-第6集 圆明园的对话
linux·系统架构
Fcy6481 小时前
Linux下 进程(一)(冯诺依曼体系、操作系统、进程基本概念与基本操作)
linux·运维·服务器·进程
袁袁袁袁满1 小时前
Linux怎么查看最新下载的文件
linux·运维·服务器
代码游侠1 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
Gary Studio1 小时前
rk芯片驱动编写
linux·学习
mango_mangojuice1 小时前
Linux学习笔记(make/Makefile)1.23
java·linux·前端·笔记·学习
主机哥哥1 小时前
阿里云OpenClaw部署全攻略,五种方案助你快速部署!
服务器·阿里云·负载均衡
Harvey9031 小时前
通过 Helm 部署 Nginx 应用的完整标准化步骤
linux·运维·nginx·k8s
珠海西格电力科技3 小时前
微电网能量平衡理论的实现条件在不同场景下有哪些差异?
运维·服务器·网络·人工智能·云计算·智慧城市
A星空1233 小时前
一、Linux嵌入式的I2C驱动开发
linux·c++·驱动开发·i2c