编译和链接 .so 后的运行时 "symbol lookup error"

Runtime "symbol lookup error" after compilation and linking of .so

首先,我已经搜索了很多这个问题,但没有找到具有相同情况的问题。

我正在构建一个 32 位插件作为 64 位机器上的共享对象并使用 cpp-redis。 cpp-redis 构建良好,我使用 cmake 工具链强制 32 位,在构建期间检查 .o 文件并确认它们是 32 位。

我编译并link编辑了我的非常基本的程序(由一个主要源文件和一个用于与我的主机应用程序通信的额外库组成,因为这是一个插件)。

在 运行 将插件加载到主机应用程序后,我看到了:

symbol lookup error: plugins/samp-redis.so: undefined symbol: _ZN9cpp_redis16redis_subscriberC1ERKSt10shared_ptrINS_7network10io_serviceEE

我很困惑,因为我已经将 cpp-redis 目录添加到带有 -L 的 linker 路径和带有 -l 的库中,这是我的 comp/link 行:

(SDK_DIR 是我的主机应用程序 sdk,非常小且最少的一组 .c/h 文件)

g++ -fpermissive -fPIC -m32 -std=c++11 -c -O3 -w -D LINUX -I$(SDK_DIR) -I$(SDK_DIR)/amx -I/usr/local/include/cpp_redis (source .cpp files...)
g++ -v -Wall -O2 -m32 -fshort-wchar -s -shared -L/usr/local/lib/ -lcpp_redis -o $(OUTFILE) *.o

运行正常,没有错误,我 运行 link 阶段用 -v 检查标志是否正确进入,一切看起来都很好。

(为了可读性添加了一些换行符)

Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure
         -v
         --with-pkgversion='Debian 4.9.2-10'
         --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs
         --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++
         --prefix=/usr
         --program-suffix=-4.9
         --enable-shared
         --enable-linker-build-id
         --libexecdir=/usr/lib
         --without-included-gettext
         --enable-threads=posix
         --with-gxx-include-dir=/usr/include/c++/4.9
         --libdir=/usr/lib
         --enable-nls
         --with-sysroot=/
         --enable-clocale=gnu
         --enable-libstdcxx-debug
         --enable-libstdcxx-time=yes
         --enable-gnu-unique-object
         --disable-vtable-verify
         --enable-plugin
         --with-system-zlib
         --disable-browser-plugin
         --enable-java-awt=gtk
         --enable-gtk-cairo
         --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64/jre
         --enable-java-home
         --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64
         --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-amd64
         --with-arch-directory=amd64
         --with-ecj-jar=/usr/share/java/eclipse-ecj.jar
         --enable-objc-gc
         --enable-multiarch
         --with-arch-32=i586
         --with-abi=m64
         --with-multilib-list=m32,m64,mx32
         --enable-multilib
         --with-tune=generic
         --enable-checking=release
         --build=x86_64-linux-gnu
         --host=x86_64-linux-gnu
         --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.9.2 (Debian 4.9.2-10) 
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.9/
    :/usr/lib/gcc/x86_64-linux-gnu/4.9/
    :/usr/lib/gcc/x86_64-linux-gnu/
    :/usr/lib/gcc/x86_64-linux-gnu/4.9/
    :/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.9/32/
    :/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../lib32/
    :/lib/../lib32/
    :/usr/lib/../lib32/
    :/usr/lib/gcc/x86_64-linux-gnu/4.9/
    :/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../
    :/lib/
    :/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-Wall' '-O2' '-m32' '-fshort-wchar' '-s' '-shared' '-L/usr/local/lib/' '-o' 'samp-redis.so' '-shared-libgcc' '-mtune=generic' '-march=i586'
 /usr/lib/gcc/x86_64-linux-gnu/4.9/collect2
     -plugin /usr/lib/gcc/x86_64-linux-gnu/4.9/liblto_plugin.so
     -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper
     -plugin-opt=-fresolution=/tmp/cc0Lo5po.res
     -plugin-opt=-pass-through=-lgcc_s
     -plugin-opt=-pass-through=-lc
     -plugin-opt=-pass-through=-lgcc_s
     --sysroot=/
     --build-id
     --eh-frame-hdr
     -m elf_i386
     --hash-style=gnu
     -shared
     -o samp-redis.so
     -s /usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../lib32/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.9/32/crtbeginS.o
     -L/usr/local/lib/
     -L/usr/lib/gcc/x86_64-linux-gnu/4.9/32
     -L/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../lib32
     -L/lib/../lib32
     -L/usr/lib/../lib32
     -L/usr/lib/gcc/x86_64-linux-gnu/4.9
     -L/usr/lib/gcc/x86_64-linux-gnu/4.9/../../..
     -lcpp_redis amxplugin2.o amxplugin.o main.o
     -lstdc++
     -lm
     -lgcc_s
     -lc
     -lgcc_s /usr/lib/gcc/x86_64-linux-gnu/4.9/32/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../lib32/crtn.o

我是误会了 linking 阶段还是静态 linking?自从我使用 C++ 以来已经有一段时间了...这些天我都在 Python 和 Go!


编辑:

使用 -W,--no-undefined 编译会产生以下输出:

Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure
     -v
     --with-pkgversion='Debian 4.9.2-10'
     --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs
     --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++
     --prefix=/usr
     --program-suffix=-4.9
     --enable-shared
     --enable-linker-build-id
     --libexecdir=/usr/lib
     --without-included-gettext
     --enable-threads=posix
     --with-gxx-include-dir=/usr/include/c++/4.9
     --libdir=/usr/lib
     --enable-nls
     --with-sysroot=/
     --enable-clocale=gnu
     --enable-libstdcxx-debug
     --enable-libstdcxx-time=yes
     --enable-gnu-unique-object
     --disable-vtable-verify
     --enable-plugin
     --with-system-zlib
     --disable-browser-plugin
     --enable-java-awt=gtk
     --enable-gtk-cairo
     --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64/jre
     --enable-java-home
     --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64
     --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-amd64
     --with-arch-directory=amd64
     --with-ecj-jar=/usr/share/java/eclipse-ecj.jar
     --enable-objc-gc
     --enable-multiarch
     --with-arch-32=i586
     --with-abi=m64
     --with-multilib-list=m32,m64,mx32
     --enable-multilib
     --with-tune=generic
     --enable-checking=release
     --build=x86_64-linux-gnu
     --host=x86_64-linux-gnu
     --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.9.2 (Debian 4.9.2-10)
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.9/
    :/usr/lib/gcc/x86_64-linux-gnu/4.9/
    :/usr/lib/gcc/x86_64-linux-gnu/
    :/usr/lib/gcc/x86_64-linux-gnu/4.9/
    :/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.9/32/
    :/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../lib32/
    :/lib/../lib32/
    :/usr/lib/../lib32/
    :/usr/lib/gcc/x86_64-linux-gnu/4.9/
    :/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../
    :/lib/
    :/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-Wall' '-O2' '-m32' '-fshort-wchar' '-s' '-shared' '-L/usr/local/lib/' '-o' 'samp-redis.so' '-shared-libgcc' '-mtune=generic' '-march=i586'
 /usr/lib/gcc/x86_64-linux-gnu/4.9/collect2
     -plugin /usr/lib/gcc/x86_64-linux-gnu/4.9/liblto_plugin.so
     -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper
     -plugin-opt=-fresolution=/tmp/ccOq8qY8.res
     -plugin-opt=-pass-through=-lgcc_s
     -plugin-opt=-pass-through=-lc
     -plugin-opt=-pass-through=-lgcc_s
     --sysroot=/
     --build-id
     --eh-frame-hdr
     -m elf_i386
     --hash-style=gnu
     -shared
     -o samp-redis.so
     -s /usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../lib32/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.9/32/crtbeginS.o
     -L/usr/local/lib/
     -L/usr/lib/gcc/x86_64-linux-gnu/4.9/32
     -L/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../lib32
     -L/lib/../lib32
     -L/usr/lib/../lib32
     -L/usr/lib/gcc/x86_64-linux-gnu/4.9
     -L/usr/lib/gcc/x86_64-linux-gnu/4.9/../../..
     -Bstatic
     --no-undefined
     -lcpp_redis amxplugin.o amxplugin2.o main.o
     -lstdc++
     -lm
     -lgcc_s
     -lc
     -lgcc_s /usr/lib/gcc/x86_64-linux-gnu/4.9/32/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../lib32/crtn.o
/usr/bin/ld: cannot find
     -lgcc_s
/usr/bin/ld: cannot find
     -lgcc_s
collect2: error: ld returned 1 exit status
makefile:15: recipe for target 'build' failed
make: *** [build] Error 1

显然它找不到 gcc_s 那是什么? s=静态?

我尝试搜索 gcc 库:

$ find /usr/ -name libgcc*
/usr/lib/gcc/x86_64-linux-gnu/4.9/libgcc_s.so
/usr/lib/gcc/x86_64-linux-gnu/4.9/libgcc_eh.a
/usr/lib/gcc/x86_64-linux-gnu/4.9/x32/libgcc_s.so
/usr/lib/gcc/x86_64-linux-gnu/4.9/x32/libgcc_eh.a
/usr/lib/gcc/x86_64-linux-gnu/4.9/x32/libgcc.a
/usr/lib/gcc/x86_64-linux-gnu/4.9/libgcc.a
/usr/lib/gcc/x86_64-linux-gnu/4.9/32/libgcc_s.so
/usr/lib/gcc/x86_64-linux-gnu/4.9/32/libgcc_eh.a
/usr/lib/gcc/x86_64-linux-gnu/4.9/32/libgcc.a
/usr/lib/gcc/x86_64-linux-gnu/4.9/libgcc_s_32.so
/usr/lib/gcc/x86_64-linux-gnu/4.9/libgcc_s_x32.so
/usr/lib/gcc/x86_64-linux-gnu/4.8/libgcc_s.so
/usr/lib/gcc/x86_64-linux-gnu/4.8/libgcc_eh.a
/usr/lib/gcc/x86_64-linux-gnu/4.8/libgcc.a
/usr/lib/x86_64-linux-gnu/libgccpp.so.1
/usr/lib/x86_64-linux-gnu/libgccpp.so.1.0.3

然而执行 ldconfig 搜索显示名为 libgcc.so.1:

的文件
$ sudo /sbin/ldconfig -p | grep libgcc
    libgccpp.so.1 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libgccpp.so.1
    libgcc_s.so.1 (libc6,x32) => /usr/libx32/libgcc_s.so.1
    libgcc_s.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libgcc_s.so.1
    libgcc_s.so.1 (libc6) => /usr/lib32/libgcc_s.so.1

会不会是这个原因?

用谷歌搜索错误会得到一些结果,所以我会继续挖掘...

即使您将 cpp_redis 构建为静态库以使其 link 能够与共享库一起使用,它也必须使用 -fPIC 标志进行编译,即代码必须是可重定位的。看起来在你的情况下 linker 在 linking 共享库时默默地忽略不兼容的代码。您可以通过 运行 nm 使用您的 .so 文件检查来自 cpp_redis 的符号是否已解析到您的插件中。

根据您的更新,您应该 link 您的插件 -W,--no-undefined 而不是 cpp_redis。它很可能会失败,因为主机程序中的符号会丢失。但是您可以检查 cpp_redis 中的符号是否被列为缺失。