为何Clang/lld无法找到__dlopen、__dlclose和__dlsym符号?
问题描述
我正在编译一个面向旧版Linux系统的C/C++项目,为获取目标系统的旧版库,复制了目标系统的根文件系统。由于GCC库路径是硬编码的,无法直接针对旧版libc交叉编译,因此选择Clang + lld,但链接阶段出现以下错误:
[ 71%] Linking CXX executable single_lidar_listener Ubuntu clang version 14.0.0-1ubuntu1.1 Target: arm-unknown-linux-gnueabihf Thread model: posix InstalledDir: /usr/bin Found candidate GCC installation: /home/abertulli/box-root-inst/usr/lib/gcc/arm-linux-gnueabihf/6 Found candidate GCC installation: /home/abertulli/box-root-inst/usr/lib/gcc/arm-linux-gnueabihf/6.3.0 Selected GCC installation: /home/abertulli/box-root-inst/usr/lib/gcc/arm-linux-gnueabihf/6.3.0 Candidate multilib: .;@m32 Selected multilib: .;@m32 "/usr/bin/ld.lld" --sysroot=/home/abertulli/box-root-inst -pie -EL -z relro -X --hash-style=gnu --build-id --eh-frame-hdr -m armelf_linux_eabi -dynamic-linker /lib/ld-linux-armhf.so.3 -o single_lidar_listener /home/abertulli/box-root-inst/usr/lib/arm-linux-gnueabihf/Scrt1.o /home/abertulli/box-root-inst/usr/lib/arm-linux-gnueabihf/crti.o /home/abertulli/box-root-inst/usr/lib/gcc/arm-linux-gnueabihf/6.3.0/crtbeginS.o -L/home/abertulli/box-root-inst/usr/lib/gcc/arm-linux-gnueabihf/6.3.0 -L/home/abertulli/box-root-inst/usr/lib/gcc/arm-linux-gnueabihf/6.3.0/../../../../lib -L/home/abertulli/box-root-inst/lib/arm-linux-gnueabihf -L/home/abertulli/box-root-inst/lib/../lib -L/home/abertulli/box-root-inst/usr/lib/arm-linux-gnueabihf -L/home/abertulli/box-root-inst/usr/lib/../lib -L/home/abertulli/box-root-inst/lib -L/home/abertulli/box-root-inst/usr/lib CMakeFiles/single_lidar_listener.dir/single_lidar.cpp.o CMakeFiles/single_lidar_listener.dir/sick_scan_xd_api_wrapper.c.o libtoojpeg.a -ldl -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /home/abertulli/box-root-inst/usr/lib/gcc/arm-linux-gnueabihf/6.3.0/crtendS.o /home/abertulli/box-root-inst/usr/lib/arm-linux-gnueabihf/crtn.o ld.lld: error: undefined symbol: __dlopen >>> referenced by dlopen.o:(dlopen) in archive /home/abertulli/box-root-inst/usr/lib/arm-linux-gnueabihf/libdl.a ld.lld: error: undefined symbol: __dlclose >>> referenced by dlclose.o:(.text+0x0) in archive /home/abertulli/box-root-inst/usr/lib/arm-linux-gnueabihf/libdl.a ld.lld: error: undefined symbol: __dlsym >>> referenced by dlsym.o:(dlsym) in archive /home/abertulli/box-root-inst/usr/lib/arm-linux-gnueabihf/libdl.a clang: error: linker command failed with exit code 1 (use -v to see invocation) make[2]: *** [CMakeFiles/single_lidar_listener.dir/build.make:114: single_lidar_listener] Error 1 make[1]: *** [CMakeFiles/Makefile2:113: CMakeFiles/single_lidar_listener.dir/all] Error 2 make: *** [Makefile:91: all] Error 2
分析目标根文件系统中的libc.a后,确认__dlopen、__dlclose、__dlsym符号确实存在,但Clang/lld无法找到。已设置sysroot,且GCC安装路径正确(基于目标根文件系统)。附上我的toolchain文件:
# the name of the target operating system set(CMAKE_SYSTEM_NAME Linux) include(CMakePrintHelpers) cmake_print_variables(CMAKE_DL_LIBS) # where is the target environment located set(root_fs_dir /home/abertulli/box-root-inst) set(CMAKE_FIND_ROOT_PATH ${root_fs_dir}) set(CMAKE_SYSROOT ${root_fs_dir}) # which compilers to use for C and C++ set(CMAKE_C_COMPILER "clang") set(CMAKE_CXX_COMPILER "clang++") set(CMAKE_LINKER "ld.lld") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld -v") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --gcc-toolchain=${CMAKE_SYSROOT}/usr") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --gcc-toolchain=${CMAKE_SYSROOT}/usr") set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) # to avoid trying to link and execute test programs set(CMAKE_C_COMPILER_TARGET arm-unknown-linux-gnueabihf) set(CMAKE_CXX_COMPILER_TARGET arm-unknown-linux-gnueabihf) # adjust the default behavior of the FIND_XXX() commands: # search programs in the host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # search headers and libraries in the target environment set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
解决方案分析
- 调整链接库顺序:从链接命令可见,
-ldl位于-lc之前,但libdl.a中的符号依赖libc.a的实现。lld按顺序解析库,先处理-ldl时无法找到依赖符号,需将-ldl移至-lc之后。可通过修改CMake的target_link_libraries顺序,或直接在CMAKE_EXE_LINKER_FLAGS中调整库的位置。 - 修正GCC工具链路径:
--gcc-toolchain参数应指向完整的交叉编译工具链根目录,而非/usr子目录。将toolchain文件中的--gcc-toolchain=${CMAKE_SYSROOT}/usr改为--gcc-toolchain=${root_fs_dir},确保Clang能正确识别完整工具链组件。 - 强制链接库成员:临时方案可添加
-Wl,--no-as-needed到链接flags中,强制lld包含libdl.a的所有成员,避免因符号未被提前引用而被忽略,但优先推荐调整库顺序。 - 验证库版本兼容性:用
arm-linux-gnueabihf-nm工具检查libc.a中的符号名称是否与libdl.a的引用完全匹配(注意下划线数量差异,部分旧版本可能为_dlopen而非__dlopen),同时确认libdl.a与libc.a为同一版本编译,避免版本不匹配导致的符号问题。
内容的提问来源于stack exchange,提问作者Alessandro Bertulli
相关产品推荐
相关产品推荐

