【问题标题】:Why does the program which is compiled against the installed glibc not run normally?为什么针对已安装的 glibc 编译的程序不能正常运行?
【发布时间】:2021-06-16 11:37:30
【问题描述】:

提前致谢。

我的开发环境:

$ cat /proc/version
Linux version 5.4.0-66-generic (buildd@lgw01-amd64-016) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #74~18.04.2-Ubuntu SMP Fri Feb 5 11:17:31 UTC 2021

$ ld --version
GNU ld (GNU Binutils for Ubuntu) 2.30
Copyright (C) 2018 Free Software Foundation, Inc.

$ getconf GNU_LIBC_VERSION 
glibc 2.27

$ #my glibc source version is 2.32.9000-development
$ cat ./version.h
/* This file just defines the current version number of libc.  */
#define RELEASE "development"
#define VERSION "2.32.9000"

由于某些原因,我需要对 glibc 进行修改和测试。我按照本站(https://sourceware.org/glibc/wiki/Testing/Builds#Compile_against_glibc_in_an_installed_location)的步骤修改glibc,编写测试程序。

  1. 编译 glibc.(配置和制作)
  2. 安装 glibc.(make install to a directory)
  3. ...上述网站中的其他步骤。

我成功修改了一些pthread函数并通过了测试(我写的测试程序可以针对install glibc编译并成功运行)。 ldd 程序。

$ ldd ./exec/1-1.out 
    linux-vdso.so.1 (0x00007ffcbf367000)
    libpthread.so.0 => /home/cjl-target/gnu/install/lib64/libpthread.so.0 (0x00007fcadcea9000)
    libc.so.6 => /home/cjl-target/gnu/install/lib64/libc.so.6 (0x00007fcadcaed000)
    /home/cjl-target/gnu/install/lib64/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fcadd2ca000)

如上图,程序所依赖的共享库都指向glibc的安装路径。

但是当我编译消息队列的测试程序(test mq_unlink)并运行它时,失败如下:

./exec/1-1.out: symbol lookup error: /lib/x86_64-linux-gnu/libpthread.so.0: undefined symbol: __libc_vfork, version GLIBC_PRIVATE

检查程序所依赖的库:

$ ldd ./exec/1-1.out 
    linux-vdso.so.1 (0x00007ffce3f72000)
    librt.so.1 => /home/cjl-target/gnu/install/lib64/librt.so.1 (0x00007f0a389a2000)
    libc.so.6 => /home/cjl-target/gnu/install/lib64/libc.so.6 (0x00007f0a385e6000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f0a383c7000)
    /home/cjl-target/gnu/install/lib64/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007f0a38dac000)

如上图,共享库 libpthread.so.0 指向系统库。为什么?

我的编译脚本是(来自上面的网站):

# dobuild.sh
SYSROOT=/home/xxx/xxx/xxx #the glibc's installation path
(set -x; \
gcc \
  -L${SYSROOT}/usr/lib64 \
  -I${SYSROOT}/usr/include \
  --sysroot=${SYSROOT} \
  -Wl,-rpath=${SYSROOT}/lib64 \
  -Wl,--dynamic-linker=${SYSROOT}/lib64/ld-linux-x86-64.so.2 \
  -Wall $*
)

当我编译 pthread 的测试程序时:./dobuild 1-1.c -pthread -Wall

当我编译mq的测试程序时:./dobuild 1-1.c -lrt -Wall

另外,在mq_unlink的测试程序中调用pthread_create,编译./dobuild 1-1.c -lrt -pthread时,ldd结果显示所有依赖库都指向已安装的glibc。

我已经尝试了多种变体,但似乎都不起作用。有什么想法吗?

【问题讨论】:

  • "另外..../dobuild 1-1.c -lrt -pthread,ldd结果显示所有依赖库都指向安装的glibc。" -- 生成的二进制文件是否有效?
  • @EmployedRussian 是的,工作成功!感谢您的评论

标签: gcc linker shared-libraries elf glibc


【解决方案1】:

首先,您应该停止使用ldd——在主机上存在多个 GLIBC 的情况下,ldd 更有可能误导而不是阐明。

如果您想查看真正加载了哪些库,请改为:

LD_TRACE_LOADED_OBJECTS=1 ./exec/1-1.out

其次,您几乎不应该在 shell 脚本中使用 $*。请改用"$@"(注意:引号很重要)。看到这个answer

第三,你观察到的行为很容易解释。要理解它,您需要知道DT_RPATHDT_RUNPATH 之间的区别,描述here

您可以验证您的二进制文件当前正在使用RUNPATH,如下所示:

readelf -d 1-1.out | grep 'R.*PATH'

您可以通过将-Wl,--disable-new-dtags 添加到链接命令(这将导致二进制文件改为使用RPATH)来验证一切是否按预期开始工作。

总结一下:

  • RUNPATH 影响对二进制文件本身的搜索,但对二进制文件所依赖的任何库。
  • RPATH 影响二进制它所依赖的所有库的搜索路径。
  • RUNPATH,预期libpthread.so.0 被发现当二进制文件直接依赖它时,但不是当对libpthread 的依赖是间接(通过librt)。
  • 使用RPATH,无论依赖是直接还是间接,都会找到预期的libpthread.so.0

更新:

如果我想使用DT_RUNPATH,如何设置librt的库运行路径?

您需要将librt.so-rpath=${SYSROOT}/lib64 关联起来。

您可以编辑rt/Makefile,或使用:

make LDFLAGS-rt.so='-Wl,--enable-new-dtags,-z,nodelete,-rpath=${SYSROOT}/lib64'

您需要对可能对 GLIBC 的其他部分带来传递依赖的任何其他库执行相同的操作。我不知道执行此操作的一般方法,但设置 LDFLAGS-lib.so='-Wl,-rpath=${SYSROOT}/lib64' 并重建所有内容可能会奏效。

【讨论】:

  • 非常感谢您的回答。我用你上面提到的方法解决了这个问题,但是我还有几个问题想问你。我对 DT_RPATH 和 DT_RUNPATH 有了初步的了解,但是 ld.so 手册页提到“不推荐使用 DT_RPATH”。如果我想使用 DT_RUNPATH,如何设置 librt 的库运行路径?如果是这样,当 librt 依赖于 libpthread 时,就会成功搜索到 libpthread。 我的英语不是很好,如果冒犯了我很抱歉
  • 非常感谢!请接受我最诚挚的谢意。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-18
  • 2019-07-06
  • 1970-01-01
相关资源
最近更新 更多