【问题标题】:How do you link correctly in C to stop symbols being stripped?如何在 C 中正确链接以阻止符号被剥离?
【发布时间】:2011-10-02 02:12:26
【问题描述】:

我在正确链接 C 中的库时遇到了一些问题。

我确信这是我不完全理解的那些神秘的 C 链接规则之一,但我无法弄清楚。

我有 libn,我将其编译成静态库 libn.a

nm libn 显示:

doug@ninja:~/projects/libnw/build$ nm ../../libn/build/libn.a |grep nIndex
00000034 T nIndex
00000000 D nIndex_
00000026 T nIndex_finalize
00000013 T nIndex_init
00000000 T nIndex_map

我也有 libnw,它依赖于 libn。 libnw 上的 nm 显示:

doug@ninja:~/projects/libnw/build$ nm libnw.a |grep Index
         U nIndex

但是,当我编译一个针对 libnw 和 libn 的编程链接时,我得到:

doug@ninja:~/projects/libnw/build$ make
[ 70%] Built target nw
[ 80%] Built target test-template
Scanning dependencies of target test-Core
[ 85%] Building C object tests/nw/mvc/Core/CMakeFiles/test-Core.dir/Tests.c.o
[ 90%] Building C object tests/nw/mvc/Core/CMakeFiles/test-Core.dir/test.c.o
Linking C executable test-Core
../../../../libnw.a(Impl.c.o): In function `nwCore__Impl_init':
/home/doug/projects/libnw/src/nw/mvc/Core/Impl.c:76: undefined reference to `nIndex'
collect2: ld returned 1 exit status
make[2]: *** [tests/nw/mvc/Core/test-Core] Error 1
make[1]: *** [tests/nw/mvc/Core/CMakeFiles/test-Core.dir/all] Error 2
make: *** [all] Error 2

原因,很清楚。当 Tests.c --> Tests.c.o 时,它不会选择 nIndex 作为它需要保留的符号:

doug@ninja:~/projects/libnw/build$ nm tests/nw/mvc/Core/CMakeFiles/test-Core.dir/Tests.c.o 
         U MyController
000005a4 T Tests
00000000 D Tests_
00000125 T Tests_can_attach_controller
00000080 T Tests_can_create_core
000003d3 T Tests_can_handle_native_event
000001c8 T Tests_can_set_controller
00000322 T Tests_can_update
00000000 t Tests_core_factory
0000056c T Tests_finalize
000005c0 T Tests_getType
0000048c T Tests_init
         U nFactory
         U nTest
         U nType_nalloc
         U nType_nfree
         U nwCore
         U nwDummyContext_getType
         U nwDummyEvents_getType
         U nwDummyRender_getType
         U nwIContext_getType
         U nwIEvents_getType
         U nwIRender_getType

(注意测试对象文件中完全没有 U nIndex)。

所以,我可以通过在我的测试脚本中添加对 nIndex() 的调用来轻松解决此问题,但这并不能解决基本问题:

程序依赖于 liba 依赖于 libb,liba 缺少需要解析的 libb 中的符号,但程序没有对这些符号的引用,因此它们似乎被剥离了。

我做错了什么?

(是的,我正在使用 cmake 进行构建,具体取决于 libn 和 libnw 的静态构建版本)。

编辑:

现在使用链接器行:

/usr/bin/gcc  -std=c99 -g   CMakeFiles/test-Core.dir/Tests.c.o \
      CMakeFiles/test-Core.dir/test.c.o \
      CMakeFiles/test-Core.dir/helpers/MyController.c.o \
      CMakeFiles/test-Core.dir/helpers/MyModel.c.o \
      -o test-Core -rdynamic \
      /home/doug/projects/tapspin-android/source/deps/libn/build/libn.a \
      ../../../../libnw.a 

【问题讨论】:

  • 这应该用您正在使用的特定 c 编译器或链接器进行标记,因为这不是语言的特性,而是程序的特性。
  • (1) 你得到一个名为“Tests.c.o”的文件很奇怪。通常(例如使用 gcc),您会像这样编译:gcc -c Tests.c,这将生成一个名为“Tests.o”的目标文件。 (2) 我在您的问题中没有看到 C99 特有的内容;据我所知,这同样适用于 C90。 (3) 你问题第一行的~ 字符有什么意义吗?
  • 我添加了 c99 作为标签,因为我正在使用 c99 std 进行编译,但我不确定这是否相关。 ~ 根本不相关(为了清楚起见,现在删除了),正如我提到的,我正在使用 cmake,它会生成详细的目标文件路径 (Tests.c.o),如所述。

标签: c gcc


【解决方案1】:

我没有看到你的链接线,所以我很难确定,但这似乎是一个订购问题

如果libb需要的所有符号都在liba中,那么你应该先列出libb,这样它们就被列为symbol-to-be-resolved,当libb是访问他们将得到解决。这不是剥离本身,它只是不包括(即,它是遗漏而不是主动移除,我是在分裂头发吗?也许)

另外,有时如果存在循环依赖(liba 需要来自libb 的一些符号,libb 需要来自liba 的一些符号),则必须多次列出这些库 (这不是cmake 的答案,因为我不使用cmake,但多年来一直使用链接器,这是一个常见错误)。

请注意,与库中的符号不​​同,目标文件中的所有符号都是链接的

首先尝试最简单的解决方法是交换两个库的顺序

【讨论】:

  • 啊,你说的太对了~交换库的顺序是我需要做的。
【解决方案2】:

既然是链接顺序的问题,也可以通过使用来解决

--开始组

--端组

GCC: what are the --start-group and --end-group command line options?

只要我们谈论的是静态库/存档文件,它就可以工作。

【讨论】:

  • 按正确顺序放置使用的库通常是最简单的解决方案。当没有正确的顺序时(例如,每个库都使用其他库中的一些符号),这些标志真的会派上用场。
  • 你是对的,但遗憾的是,我多次看到不同的编译器/链接器版本的行为不同,并且某些排序错误(以前提交的)可能仅在更新编译器/链接器后才会出现。跨度>
  • 确实,很难说不正确的顺序是否会成为问题。您的解决方案更安全。
【解决方案3】:

要查找依赖库的正确顺序,可以使用以下 *nix 命令管道:

lorder libA.a libB.a ... | tsort

如果有人收到有关循环引用的错误,那么尽管使用 --start-group 和 --end-group 的上述 GCC 组合会起作用,或者只是再次列出有问题的库,但确实应该修复库,因此它们没有循环依赖关系。

【讨论】:

    猜你喜欢
    • 2016-06-06
    • 2021-02-01
    • 2011-02-15
    • 2012-05-30
    • 1970-01-01
    • 2013-04-10
    • 1970-01-01
    • 2010-09-18
    • 2013-09-23
    相关资源
    最近更新 更多