gcc没有将.o中的符号链接到应用程序中

Posted

技术标签:

【中文标题】gcc没有将.o中的符号链接到应用程序中【英文标题】:gcc not linking symbols from .o into application 【发布时间】:2014-10-25 11:12:35 【问题描述】:

我正在尝试将 c++ .o 文件链接到应用程序(也是 c++)。这是构建行:

g++ -o ../objs/armv5sfLinux3.2gcc4.6.2.EV3/Touch_publisher ../objs/armv5sfLinux3.2gcc4.6.2.EV3/Touch_publisher.o ../objs/armv5sfLinux3.2gcc4.6.2.EV3/EV3_Touch .o ../objs/armv5sfLinux3.2gcc4.6.2.EV3/EV3_TouchPlugin.o ../objs/armv5sfLinux3.2gcc4.6.2.EV3/EV3_TouchSupport.o ../ev3/ev3dev.o -L/host-rootfs/home /rip/nfs/ev3dev/ndds.5.1.0/lib/armv5sfLinux3.2gcc4.6.2.EV3 -lnddscppz -lnddscz -lnddscorez -ldl -lnsl -lm -lpthread -lrt -lstdc++

有问题的 .o 是 ../ev3/ev3dev.o 文件。构建后,我得到了 Touch_publisher 应用程序,但 nm 报告:

root@arundel:~/rti_510/Touch# nm ../objs/armv5sfLinux3.2gcc4.6.2.EV3/Touch_publisher | grep ev3 | grep " U "
         U _ZN6ev3dev12touch_sensorC1ESs
         U _ZNK6ev3dev12touch_sensor7pressedEv
         U _ZNK6ev3dev6sensor9type_nameEv

如果我在 ev3dev.o 上执行 nm,对于缺少的符号,我会得到例如,

root@arundel:~/rti_510/Touch# nm ../ev3/ev3dev.o | grep _ZN6ev3dev12touch_sensorC1ESs
0000ee5c T _ZN6ev3dev12touch_sensorC1ESs
root@arundel:~/rti_510/Touch# 

所以有一个符号。从上面我不知道的细节是什么? “T”表示它是一个外部符号...

我是否在命令行上遗漏了一些深奥的标志? ev3dev.o 文件的构建使用:

BUILD:
        gcc -std=c++11 -shared -fpic -march=armv5t -mfloat-abi=soft -mlong-calls -o ev3dev.o ev3dev.cpp

或者也许还有其他步骤?我试过 '-Wl,-whole-archive,../ev3/ev3dev.o,-no-whole-archive' 但仍然得到那些讨厌的 U 符号。

我没有启用 -O# 优化。

我已经阅读了 20 个左右类似的问题(“链接对象中缺少符号”)

谢谢

附录:objdump而不是nm的结果:

root@arundel:/host-rootfs/home/rip/nfs/ev3dev/rti_510/Touch# objdump -T Touch_publisher | grep \*UND\* | grep ev3dev   
00000000      DF *UND*  00000000              _ZNK6ev3dev12touch_sensor7pressedEv
00000000      DF *UND*  00000000              _ZNK6ev3dev6sensor9type_nameEv
00000000      DF *UND*  00000000              _ZN6ev3dev12touch_sensorC1ESs
root@arundel:/host-rootfs/home/rip/nfs/ev3dev/rti_510/Touch# objdump -t ../ev3/ev3dev.o | grep ev3dev | grep _ZNK6ev3dev12touch
0000f040 g     F .text  00000058              _ZNK6ev3dev12touch_sensor7pressedEv
root@arundel:/host-rootfs/home/rip/nfs/ev3dev/rti_510/Touch# objdump -t ../ev3/ev3dev.o | grep ev3dev | grep _ZNK6ev3dev6sensor9type
0000dd10 g     F .text  00000690              _ZNK6ev3dev6sensor9type_nameEv
root@arundel:/host-rootfs/home/rip/nfs/ev3dev/rti_510/Touch# objdump -t ../ev3/ev3dev.o | grep ev3dev | grep _ZN6ev3dev12touch      
0000ee5c g     F .text  000001e4              _ZN6ev3dev12touch_sensorC1ESs
0000ee5c g     F .text  000001e4              _ZN6ev3dev12touch_sensorC2ESs
root@arundel:/host-rootfs/home/rip/nfs/ev3dev/rti_510/Touch# 

【问题讨论】:

它可能是特定于操作系统的。为什么需要将目标文件链接到现有应用程序?你想做什么还不清楚。你想要运行时dynamic linking吗?在 Posix 和 Linux 上,使用 dlopen(3)。也许您在链接时需要-rdynamic 标志。也许您缺少一些库! 我在 Ubuntu 上交叉编译,在 Qemu for Armv5sf 下。我将 ev3dev.o 文件与所有其他 .o 文件一次性链接到应用程序中(而不是“链接到 /existing/ 应用程序”)。我会尝试 -rdynamic... nop。仍然得到未解决的外部问题。 缺少一些库会很有趣,除了最终应用程序中缺少符号的库在命令行上。 检查fileobjdump每个*.o文件 这些符号是只出现一次还是出现多次(除了“U”之外的其他字母)? 【参考方案1】:

ev3dev.o 文件是使用以下方法构建的:

构建:gcc -std=c++11 -shared ... -o ev3dev.o ev3dev.cpp

那是你的问题,就在那里:你构建了一个共享库并将其错误命名为ev3dev.o

链接共享库的规则是,当您链接它们时,它们包含在主可执行文件中,所以难怪ev3dev.o 不包含在Touch_publisher 中。

解决方案:如果您希望ev3dev.o 成为普通(可重定位)对象文件,适合链接到主可执行文件,则将-shared 替换为-c

【讨论】:

非常出色——我认为这很简单,比如编译器标志。我没有意识到这种行为(不是针对共享库的静态链接)。谢谢!

以上是关于gcc没有将.o中的符号链接到应用程序中的主要内容,如果未能解决你的问题,请参考以下文章

GCC链接器:在指定部分移动符号

图片+代码:GCC 链接过程中的重定位过程分析.md

图片+代码:GCC 链接过程中的重定位过程分析.md

命名空间中的内联函数在 gcc 上的链接期间生成重复的符号

GCC中的弱符号与强符号

如何强制gcc链接未使用的静态库