c – 为什么这个库dlopen秩序很重要?

我有一个库CandData这样(相关)$nm libCandData.so:

             U _ZN10CandHandle13SetCandRecordEP10CandRecord
             U _ZN10CandHandle7SetLockEv
000000011610 T _ZNK10CandRecord13GetCandHeaderEv
             U _ZTI10CandHandle

和一个库Candidate这样$nm libCandidate.so:

00000001f018 T _ZN10CandHandle13SetCandRecordEP10CandRecord
00000001f270 T _ZN10CandHandle7SetLockEv
             U _ZNK10CandRecord13GetCandHeaderEv
000000241500 V _ZTI10CandHandle

因此,它们具有循环依赖性.我可以通过延迟加载Candidate加载这些,
一切顺利的顺序:

dlopen("libCandidate.so", RTLD_LAZY | RTLD_GLOBAL);
dlopen("libCandData.so",  RTLD_NOW | RTLD_GLOBAL);

但是首先尝试延迟加载CandData:

dlopen("libCandData.so",  RTLD_LAZY | RTLD_GLOBAL);
dlopen("libCandidate.so", RTLD_NOW | RTLD_GLOBAL);

导致dlopen报告:

dlopen Error: libCandData.so: undefined symbol: _ZTI10CandHandle

我不明白为什么这个命令很重要?根据我的理解,V意味着
该符号是弱链接但具有默认定义,因此可以看到可能不需要立即解决.但是两个库都具有U-> T依赖性.

为什么一个订单有效,而另一个订单无效?

最佳答案

What I don’t understand is why this order matters?

顺序很重要,因为虽然未解析的函数引用可以延迟解析,但数据引用不能(并且_ZTI10CandHandle不是函数).

您应该查看重定位(使用readelf -Wr),而不是查看nm输出.您将观察到符号_ZTI10CandHandle的libCandidate.so中的重定位类型与符号_ZN10CandHandle7SetLockEv的libCandData.so中的重定位类型不同.

点赞