什么使 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).
但我没有看到任何关于对象和普通符号之间区别的提示。所以
- 有什么区别,
- 是什么使符号在 C 或 C++ 语言或链接器级别成为一个或另一个,并且
- 是否确实应该使符号无法解析?
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
), 它不会。
缺少标志本身不是问题,但它暗示了缺少库引用的实际问题。
我有一个应用程序正在通过 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).
但我没有看到任何关于对象和普通符号之间区别的提示。所以
- 有什么区别,
- 是什么使符号在 C 或 C++ 语言或链接器级别成为一个或另一个,并且
- 是否确实应该使符号无法解析?
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
), 它不会。
缺少标志本身不是问题,但它暗示了缺少库引用的实际问题。