什么使 ELF 库中的符号成为对象或普通符号?

What makes a symbol in an ELF library an object or normal one?

我有一个应用程序正在通过 dlopen,特别是 dlopen(name, RTLD_LAZY|RTLD_DEEPBIND) 加载一些插件。有一些插件(以二进制形式提供)可以正常加载,但我尝试构建的插件无法加载并出现错误:

/opt/app/plugins/plugin.so: undefined symbol: Log_Modules

所有插件都引用该符号,并在此过程中加载提供它的库。但是 objdump -D 打印的条目不同。在加载它的插件中说

00000000      DO *UND*       00000000              Log_Modules

在定义它的库中它说

000130dc g    DO .data       00000004  Base        Log_Modules

而在我构建的模块中它说

00000000      D  *UND*       00000000              Log_Modules

objdump的手册页只是说flag的意思是

The symbol is the name of a function (F) or a file (f) or an object (O) or just a normal symbol (a space).

但我没有看到任何关于对象和普通符号之间区别的提示。所以

what is the difference

符号 table .st_info 包含 STT_OBJECT 而不是 STT_FUNC

what makes the symbol one or the other at the C or C++ language or linker level

C级别,编译器会在发出汇编代码时用@function标记函数标签,而汇编器会在发出符号table时添加STT_FUNC标志。

is it indeed supposed to make the symbol not resolve?

没有。您的问题很可能与此无关。

一般来说,objdump 错误的 查看 ELF 文件的工具(它映射到 BFD 数据模型,在过去 20 多年里已经过时).请改用 readelf

大胆猜测:您的 plugin.so 定义了符号,但 没有 导出符号。使用

nm -D plugin.so | grep ' Log_Modules$'
nm    plugin.so | grep ' Log_Modules$'

如果 Log_Modules 出现在第二个命令输出中,而不是第一个,那么我的猜测是正确的。

what is the difference

O标志对应STT_OBJECT标志,表示一个对象,即变量。

what makes the symbol one or the other at the C or C++ language or linker level

显然,linker 仅在它实际看到定义时才使用 STT_OBJECT 标志标记符号,即当定义它的库作为依赖项提供时。单独的外部声明没有被标记。

is it indeed supposed to make the symbol not resolve?

解析符号时,linker 会查看明确列出的依赖项,以及使用 RTLD_GLOBAL 加载的库,其中包括主要可执行文件的依赖项。因此,当主要可执行文件已经碰巧 link 定义库时,插件将不用 link 明确地对其进行处理,但是如果它本身加载了 dlopen (没有 RTLD_GLOBAL), 它不会。

缺少标志本身不是问题,但它暗示了缺少库引用的实际问题。