【发布时间】:2019-11-05 09:44:02
【问题描述】:
我有一个从 C 项目编译的 .o 文件,该项目引用了一个名为 init_static_pools 的函数。我使用objdump -t 来显示它的符号依赖信息:
00000000 UND 00000000 init_static_pools
根据thread,UND 只是说“我需要其他人来为我提供该功能”。
所以我将这个.o 文件链接到一个.elf 文件,其中包含init_static_pools 的定义。 objdump -t 表明该符号在此文件中确实:
00004dcf g F .text 00000048 init_static_pools
根据这个thread,g 和F 标志意味着它是一个全局函数。我想这意味着这个函数可以静态链接。
我尝试使用以下命令行链接.o 文件和.elf 文件:
/usr/bin/c++ -m32 -rdynamic unittest1.o -o unittest1 target.elf lib/libgtest.a lib/libgtest_main.a -lpthread
我收到以下错误:
unittest1.cc:(.text+0x2d): 对 `init_static_pools' 的未定义引用
函数就在.so文件中,为什么不能链接?
这可能与动态链接和静态链接之间的不同符号解析机制有关吗?因为我使用objdump -f 并看到target.elf 是一个动态对象。如下图:
target.elf:文件格式elf32-i386
架构:i386,标志 0x00000150:
HAS_SYMS、动态、D_PAGED
起始地址0x00001144
添加 1 - 2019 年 11 月 6 日上午 9:17
根据 @EmployedRussian 的评论,我尝试了readelf。
对于target.elf,它只包含一行:
486: 00004dcf 72 FUNC 全局默认值 13 init_static_pools
对于unittest1.o,它包含两行内容:
0000002d 0000fb04 R_386_PLT32 00000000 init_static_pools
和
251: 00000000 0 NOTYPE GLOBAL DEFAULT UND init_static_pools
为了完成,它们的标题是:
target.elf:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x1144
Start of program headers: 52 (bytes into file)
Start of section headers: 246936 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 9
Size of section headers: 40 (bytes)
Number of section headers: 43
Section header string table index: 42
unittest1.o:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 36988 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 262
Section header string table index: 261
到目前为止,我还不能说出链接失败的根本原因。幸运的是,我刚刚在 the Ian Lance Taylor 的链接器上找到了 series。希望能启发我。但我想这需要一些时间。
添加 2 - 2019 年 11 月 6 日上午 10:33
根据@EmployedRussian 的回复,我尝试了以下命令:
nm target.elf | grep init_static_pools
nm -D target.elf | grep init_static_pools
正如@EmployedRussian 所怀疑的那样,第二个命令行没有输出。这意味着 target.elf 没有在其动态符号表中导出 init_static_pools,这使得该符号不符合从 target.elf 外部链接的条件。
下面是一些与target.elf链接相关的标志:
-Wl,-T zephyr/linker.cmd (this is quite long, but it seems to be mostly layout info)
-Wl,-Map=target_prebuilt.map
-Wl,--whole-archive
-Wl,--gc-sections
-Wl,--build-id=none
-Wl,--sort-common=descending
-Wl,--sort-section=alignment
-ldl
-lm
或者我也应该检查编译标志?
我找到了--export-all-symbols、--export-dynamic、--gc-keep-exported 选项,我正在尝试它们。
似乎--export-all-symbols 被忽略了。我猜它是为 DLL 设计的。
我把--export-dynamic和--gc-keep-exported放在一起,构建就可以通过了。
但是nm -D 仍然显示以下消息:
target.elf : 没有符号
添加 3 - 2019 年 11 月 6 日上午 11:16
一篇关于动态符号表(.dynsym)和符号表(.symtab)的文章。 https://blogs.oracle.com/solaris/inside-elf-symbol-tables-v2
引用:
事实上,在共享库和动态链接出现之前, 运行时不需要它。有一个单一的、不可分配的 符号表(合理地命名为“symtab”)。当动态链接是 加入系统后,原设计者面临一个选择: symtab allocable,或提供第二个较小的可分配副本。这 运行时需要的符号只是总数的一小部分,所以第二个 符号表在运行进程中保存虚拟内存。这是个 重要的考虑。因此,发明了第二个符号表 动态链接,因此命名为“dynsym”。
所以,我认为.dynsym 用于运行时动态链接。但我想我希望我的unittest1.o 和target.elf在构建时静态链接。
所以它让我想到了这个问题:我可以静态链接到.ELF 文件吗? 在Windows 上,我通常静态链接到.lib 文件而不是.DLL 文件。这里的.ELF 文件看起来更像.DLL。顺便说一句,我的构建过程还会生成一个libtarget.a 文件。我应该用它代替target.elf吗?
不幸的是,我在libtarget.a上尝试了nm -t和readelf -s,它们都没有显示init_static_pools的存在。
顺便说一句,如果您对我的问题有所了解,请随时提出一些提示。谢谢!
【问题讨论】:
-
你不应该永远在
ELF系统上使用objdump:它将ELF映射到古代构造(它是在COFF时代编写的)。相反,请始终使用readelf,它会告诉您实际发生了什么。 -
@EmployedRussian 感谢您的提示。我今天将尝试阅读 ELF。
-
@EmployedRussian btw 我记得我在某处读到 readelf 是在不使用 bfd 库的情况下开发的,而 objdump 则使用它。原因是为了比较什么的。
标签: linker linker-errors ld static-linking dynamic-linking