【问题标题】:Undefined reference when linking a .o file to a .elf file将 .o 文件链接到 .elf 文件时未定义的引用
【发布时间】:2019-11-05 09:44:02
【问题描述】:

我有一个从 C 项目编译的 .o 文件,该项目引用了一个名为 init_static_pools 的函数。我使用objdump -t 来显示它的符号依赖信息:

00000000 UND 00000000 init_static_pools

根据threadUND 只是说“我需要其他人来为我提供该功能”。

所以我将这个.o 文件链接到一个.elf 文件,其中包含init_static_pools 的定义。 objdump -t 表明该符号在此文件中确实

00004dcf g F .text 00000048 init_static_pools

根据这个threadgF 标志意味着它是一个全局函数。我想这意味着这个函数可以静态链接

我尝试使用以下命令行链接.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.otarget.elf在构建时静态链接

所以它让我想到了这个问题:我可以静态链接到.ELF 文件吗? 在Windows 上,我通常静态链接到.lib 文件而不是.DLL 文件。这里的.ELF 文件看起来更像.DLL。顺便说一句,我的构建过程还会生成一个libtarget.a 文件。我应该用它代替target.elf吗?

不幸的是,我在libtarget.a上尝试了nm -treadelf -s,它们都没有显示init_static_pools的存在。

顺便说一句,如果您对我的问题有所了解,请随时提出一些提示。谢谢!

【问题讨论】:

  • 你不应该永远ELF系统上使用objdump:它将ELF映射到古代构造(它是在COFF时代编写的)。相反,请始终使用readelf,它会告诉您实际发生了什么。
  • @EmployedRussian 感谢您的提示。我今天将尝试阅读 ELF。
  • @EmployedRussian btw 我记得我在某处读到 readelf 是在不使用 bfd 库的情况下开发的,而 objdump 则使用它。原因是为了比较什么的。

标签: linker linker-errors ld static-linking dynamic-linking


【解决方案1】:

对于target.elf,它只包含1行说:
486: 00004dcf 72 FUNC GLOBAL DEFAULT 13 init_static_pools

不幸的是,这仍然不足以确定发生了什么。

要确定,请运行以下两个命令:

nm    target.elf | grep init_static_pools
nm -D target.elf | grep init_static_pools

我怀疑第一个命令会产生输出,而第二个不会。

如果是这种情况,那么target.elf在其动态符号表中导出 init_static_pools,这使得符号不符合从 target.elf 外部链接的条件。 p>

至于你最终是如何没有导出这个符号的,我只能猜测(因为你没有提供用于链接它的链接命令)。您可能正在使用隐藏它的链接描述文件。

【讨论】:

  • 谢谢。你的嫌疑人是对的。我用一些链接标志更新了我的问题。
  • 我认为实际的答案在于linker.cmd 某处。也不清楚您是如何得到ET_DYN 对象的(鉴于您的链接行上缺少--shared)。
猜你喜欢
  • 2011-02-08
  • 1970-01-01
  • 2021-08-20
  • 1970-01-01
  • 2021-03-17
  • 1970-01-01
  • 2018-04-07
  • 1970-01-01
  • 2016-12-10
相关资源
最近更新 更多