Gcc 为什么针对已安装的glibc编译的程序不能正常运行?

Gcc 为什么针对已安装的glibc编译的程序不能正常运行?,gcc,linker,shared-libraries,elf,glibc,Gcc,Linker,Shared Libraries,Elf,Glibc,提前谢谢 我的开发环境: $ 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 Copyri

提前谢谢

我的开发环境:

$ 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。我按照本网站()的步骤修改glibc并编写测试程序

  • 编译glibc(confgure和make)
  • 安装glibc。(将安装设为目录)
  • …上述网站中的其他步骤
  • 我成功地修改了一些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指向系统库。为什么?

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

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

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

    此外,令人困惑的是,当调用mq_unlink的测试程序中创建的pthread_时,编译它
    /dobuild 1-1.c-lrt-pthread
    ,ldd结果显示所有依赖库都指向已安装的glibc。


    我尝试过多种不同的方法,但似乎都不管用。有什么想法吗?

    首先,您应该停止使用
    ldd
    ——在主机上存在多个glibc的情况下,
    ldd
    更可能误导而不是照亮

    如果要查看实际加载的库,请执行以下操作:

    LD_TRACE_LOADED_OBJECTS=1 ./exec/1-1.out
    
    其次,您几乎不应该在shell脚本中使用
    $*
    。请改用“$@”(注意:引号很重要)。看这个

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

    您可以验证二进制文件当前是否正在使用运行路径,如下所示:

    readelf -d 1-1.out | grep 'R.*PATH'
    
    您可以通过向link命令添加
    -Wl,--disable new dtags
    (这将导致二进制文件改用
    RPATH
    )来验证一切是否按预期开始工作

    总结如下:

    • RUNPATH
      影响对二进制文件本身的搜索,但不影响对二进制文件所依赖的任何库的搜索
    • RPATH
      影响二进制文件及其所依赖的所有库的搜索路径
    • 使用
      运行路径
      ,仅当二进制文件直接依赖于它时,才会找到预期的
      libpthread.so.0
      ,但当对
      libpthread
      的依赖是间接的(通过
      librt
      )时,则不会找到该文件
    • 使用
      RPATH
      ,无论依赖关系是直接的还是间接的,都会找到预期的
      libpthread.so.0
    更新:

    如果我想使用DT_运行路径,如何为librt设置库运行路径

    您需要使用
    -rpath=${SYSROOT}/lib64
    链接
    librt.so

    您可以编辑
    rt/Makefile
    ,或使用以下内容生成:

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

    对于可能对GLIBC的其他部分产生可传递依赖性的任何其他库,您都需要这样做。我不知道有什么通用的方法可以做到这一点,但是设置
    LDFLAGS lib.so='-Wl,-rpath=${SYSROOT}/lib64'
    并重建一切可能会奏效。

    首先,您应该停止使用
    ldd
    ——在主机上存在多个glibc的情况下,
    ldd
    更可能误导而不是照亮

    如果要查看实际加载的库,请执行以下操作:

    LD_TRACE_LOADED_OBJECTS=1 ./exec/1-1.out
    
    其次,您几乎不应该在shell脚本中使用
    $*
    。请改用“$@”(注意:引号很重要)。看这个

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

    您可以验证二进制文件当前是否正在使用运行路径,如下所示:

    readelf -d 1-1.out | grep 'R.*PATH'
    
    您可以通过向link命令添加
    -Wl,--disable new dtags
    (这将导致二进制文件改用
    RPATH
    )来验证一切是否按预期开始工作

    总结如下:

    • RUNPATH
      影响对二进制文件本身的搜索,但不影响对二进制文件所依赖的任何库的搜索
    • RPATH
      影响二进制文件及其所依赖的所有库的搜索路径
    • 使用
      运行路径
      ,仅当二进制文件直接依赖于它时,才会找到预期的
      libpthread.so.0
      ,但当对
      libpthread
      的依赖是间接的(通过
      librt
      )时,则不会找到该文件
    • 使用
      RPATH
      ,无论依赖关系是直接的还是间接的,都会找到预期的
      libpthread.so.0
    更新:

    如果我想使用DT_运行路径,如何为librt设置库运行路径

    您需要使用
    -rpath=${SYSROOT}/lib64
    链接
    librt.so

    您可以编辑
    rt/Makefile
    ,或使用以下内容生成:

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

    对于可能对GLIBC的其他部分产生可传递依赖性的任何其他库,您都需要这样做。我不知道有什么通用的方法可以做到这一点,但是通过设置
    LDFLAGS lib.so='-Wl,-rpath=${SYSROOT}/lib64'
    ,然后重建所有的东西就可以了。

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