记录应用 dlclose 后 so 无奈卸载问题
问题形容
有一个相似插件的性能,应用 dlopen 形式加载一个 so,降级 so 的时候,先 dlclose,而后再 dlopen 加载。这样能够做到更换 so 的时候不必重新启动程序。原本所有运行的比拟好,但有一个 so 比拟奇怪,降级 so 后,某些函数无奈应用新的 so 外面的实现,还是旧的 so 中的实现。
问题定位
在 gdb 中应用 info sharedlibrary 命令查看加载的 so,再应用 lsof 查看如下:
(gdb) info sharedlibrary
0x00007fff2132a2c0 0x00007fff213bc5f8 Yes /xxxx/xxx/libxxx.so
[email protected]:~# lsof |grep libxxx.so
nginx 3391245 root mem REG 253,0 8604544 5250054 /xxx/xxx/libxxx.so
从这些信息中能够看到,目前正在应用的 so 的 inode 是 5250054,而是用 stat 查看当初 so 的 inode 信息,发现 inode 是 5377891,如下所示:
[email protected]:~# stat /xxx/xxx/libxxx.so
File: /apisec/modules/component/sensitive_data/libs/libdi_rechk.so
Size: 8604544 Blocks: 16808 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 5377891 Links: 1
Access: (0644/-rw-r--r--) Uid: (0/ root) Gid: (0/ root)
Access: 2022-10-21 17:01:57.404283135 +0800
Modify: 2022-10-21 15:48:29.000000000 +0800
Change: 2022-10-21 17:00:23.423822609 +0800
两者 inode 不一样,阐明应用的不是同一个 so 文件,因为旧的 so 曾经被删除。但程序中曾经 dlclose 并从新 dlopen 了,于是从网上查找材料,有些材料中都说查看下是否有 NODELET 标记。于是应用 readelf 命令查看下:
[email protected]:~# readelf -d libxxx.so |grep NODELETE
0x000000006ffffffb (FLAGS_1) Flags: NODELETE
so 中有此标识,则动静加载程序已被告知不要卸载库,所以调用 dlclose 后,不会从过程中卸载此 so。
手动测试
本人写一个 test.c 的测试例子,代码如下:
#include <stdio.h>
int test()
{printf("this is test function.\n");
return 0;
}
应用如下编译命令编译:
gcc -fpic -shared -o libtest.so test.c
而后应用 readelf 命令查看是否有标识:
gcc -fpic -shared -o libtest.so test.c
发现没有任何输入。
从新应用以下命令编译并应用 readelf 命令查看:
gcc -fpic -shared -znodelete -o libtest.so test.c
readelf -d libtest.so |grep NODELETE
0x000000006ffffffb (FLAGS_1) Flags: NODELETE
能够看到,增加了 -znodelete 选项后,编译出的 so 中曾经有了 NODELETE 选项。
-znodelete 选项是链接器程序 ld 的一个参数, 应用 ld –help 能够看到 -znodelete 选项的作用。有了此选项后,程序会常驻在过程中,在调用 dlclose 后,不会从过程中删除。除了 nodelete 选项,还有 nodlopen 等其它选项。
为什么这个 so 会增加 -znodelete 选项?
从开发 so 的人员那里理解到,其并没有手动增加这个选项,他的 so 是用 go 语言开发的,应用 go build -buildmode=c-shared 编译的 c 语言的 so。
于是从网上搜寻相干问题,发现 go 语言生成的 so 中,目前不反对 dlclose,应用的形式就是增加 -znodelete 选项。(https://github.com/golang/go/…)
目前(2022 年 10 月 24 日),go 语言反对 dlclose 在 golang 的 github 中仍然是一个 open 状体的 bug:https://github.com/golang/go/…
参考资料
https://stackoverflow.com/que…
https://www.coder.work/articl…
https://docs.oracle.com/cd/E1…