假设尚未加载针对共享库libshlib
链接的其他可执行文件。并假设libshlib
包含一个标有__attribute__(constructor)
的函数和一个标有__attribute__(destructor)
的函数。当启动与libshlib
链接的可执行文件时,将加载libshlib
,并且标记为__attribute(constructor)
的相应功能将完全运行一次。但是如果可以重新加载共享库,会发生什么?通过用户定义的信号,如SIGUSR1
?从我的测试来看,__attribute__(constructor)
似乎没有再次运行。这是正确的还是有标准的说法呢?
答案 0 :(得分:2)
我假设你有一个链接的程序通过(例如):
cc -o mypgm mypgm.o -lshlib
执行后,一旦ELF解释器加载了libshlib.so
并执行了构造函数,就永远不会再加载库。 旁注:要找到您的口译员,请执行以下操作:readelf -a mypgm | grep interpreter:
如果程序收到一个信号(例如SIGUSR1
),信号将由信号处理程序捕获(假设signal
或sigaction
已被调用以设置一个),或者采取默认操作(SIGUSR1
的[IIRC]程序终止)。这 not 导致重新加载库。
还有 no 其他操作可能导致重新加载库。程序退出时只会调用析构函数(例如main
返回或调用exit
)。
即使手动调用析构函数也没有效果,因为构造函数和析构函数是独立的。 (例如,构造函数可以执行able = malloc(...)
,析构函数可以执行free(able)
。但是,析构函数可以执行free(baker)
。)。调用析构函数不会重置"构造函数。
获得"重新加载"效果,库需要通过dlopen/dlsym/dlclose
动态加载/卸载。也就是说,链接命令将是:
cc -o mypgm mypgm.o
然后,mypgm
将[在某个时刻]调用dlopen("libshlib.so")
(并且将调用构造函数)。当[和 if ] mypgm
调用dlclose
时,libshlib.so
将被卸载(并且析构函数被调用)。
如果mypgm
然后调用dlopen("libshlib.so")
第二时间,则将再次调用。
<强>更新强>
请注意,调用
dlclose
不会必须卸载库或调用析构函数。
我刚检查了[glibc
]中的代码。该库有一个refcount。如果引用dlclose
后引用计数为1,则 将被卸载,libshlib.so
上面dlopen
应该是这种情况[因为没有其他人碰到它起来]。
换句话说,强迫&#34;期望&#34;没有其他行为应通过libshlib
引用-lshlib
。不是该计划或任何其他.so
。这奠定了基础。
请注意,如果libshlib.so
需要glibc
,但该计划也是如此,卸载libshlib
会降低glibc
引用计数,但glibc
将保留,因为它的引用计数[仍然]> 0。
在某些情况下,库无法卸载(实际上,这些条件比可以卸载库时的条件更常见)。
同样,这取决于引用计数和[可能]某些状态。从静态&#34;加载库时链接(与dlopen
对比),引用计数获得额外的增量,因此不会被拉扯。
该代码还处理构造函数在其自己的库上调用dlopen
的情况。
对于给定的libA
,如果需要libB
,则B&#39}的引用计数会被A的加载/卸载升级/降级。
如果未卸载库,则无法定义析构函数是否运行,以及后续dlopen是否将再次运行构造函数
dlopen
以这种方式使用libshlib
的重点是保证 dlopen
的加载和dlclose
的卸载[以及构造函数/析构函数]。如果没有静态引用或循环依赖,这将为真,这是起始标准。
更新#2:
部分关于&#34;因为没有其他人碰到它&#34;太简单了。
不要将散文与实质内容混为一谈。
如上所述:如果没有对它的静态引用或循环依赖,则将为真。
这意味着仅执行dlopen/dlclose
shlib
shlib
的可执行文件/对象是dlsym
中的符号。
而且,这只是通过shlib
。否则,它是一个静态引用(即在对象的符号表中作为UNDEF)]。
而且,shlib
拖入的 no 共享库是指DF_1_NODELETE
[循环依赖]中定义的符号。
查看符号解析期间设置DF_1_NODELETE的所有位置。
是的,我看了。
dlopen
仅在 中设置以下位置。它们都不适用于这种情况[或大多数dlopen
场景]。
RTLD_NODELETE
的标记参数有dlopen
,我们可以避免。DF_1_NODELETE
]相关,则会设置LOCAL
GLOBAL
)WEAK
,STB_GNU_UNIQUE
,malloc
等)
dlopen/dlclose
失败。此代码甚至不执行此处的情况。而且,除了OP的用法之外,{{1}}有正当理由可以像我设置/描述的那样工作。
请在此处查看我的回答:Is it possible to perform munmap based on information in /proc/self/maps?
在那里,OP需要一个可以运行数月/年的不间断程序(例如,高可靠性,任务关键型应用程序)。如果[通过包管理器等]安装了其中一个共享库的更新版本,则程序必须动态地,动态地,而不需要重新执行,能够加载新版本。