程序如何在动态库中查找符号?动态库更新后主程序无需重编的疑问
动态库符号查找的运行时机制问题
代码示例
main.c
#include <stdio.h> #include "mylib.h" int main(int argc, char **argv) { printf("%d\n", foo()); }
mylib.h
#pragma once int foo();
mylib.c
#include "mylib.h" int foo() { return 5; }
编译与现象
将mylib编译为动态库并链接到main后,通过ldd命令可查看main对动态库的依赖:
>>> ldd main ... libmylib.so => /some_path/libmylib.so ...
修改mylib.c并重新编译动态库后,foo符号的地址会发生变化,但无需重新编译或链接main程序即可正常运行。
问题
符号查找是否在运行时进行,就像使用dlopen加载库那样,且main程序中不存储外部符号地址?
回答
不是完全和dlopen一致的运行时查找逻辑,但核心确实是**main程序不会存储外部符号的固定地址**,而是由动态链接器在程序启动阶段完成符号地址的绑定工作。
具体细节如下:
- 编译链接
main时,编译器只会为foo预留一个符号引用占位,不会写入实际内存地址。链接器会将该符号标记为需要动态解析的外部符号,同时记录main依赖的动态库信息。 - 当运行
main时,操作系统的动态链接器(比如Linux下的ld-linux.so)会先加载依赖的libmylib.so,然后遍历main中所有未解析的符号,在已加载的动态库中找到foo的实际地址,完成地址重定位——把main中调用foo的指令位置替换成动态库中foo的当前地址。 - 这个绑定过程默认在程序启动时一次性完成(可通过
LD_BIND_NOW环境变量强制生效),而非每次调用foo时才执行查找。而dlopen属于显式动态加载,是在程序运行的任意阶段手动触发库加载和符号查找,和这种隐式的动态链接机制存在区别。
因此修改动态库后,只要新库中仍存在foo符号,动态链接器在下次启动main时会重新解析绑定新的地址,自然不需要重新编译main。
内容的提问来源于stack exchange,提问作者elo
相关产品推荐
相关产品推荐

