【问题标题】:checking shared libraries for non default loaders检查非默认加载程序的共享库
【发布时间】:2012-05-02 10:46:15
【问题描述】:

ldd 是检查给定可执行文件正在或将要使用的共享库的好方法。但是,它并不总是按预期工作。例如,请参阅以下 shell sn-p,它演示了如何“失败”在 python 二进制文件中找到 libreadline“依赖项”

我尝试了许多其他发行版,但我是从 Tikanga 复制的

$ lsb_release -a
LSB Version:    :core-4.0-amd64:core-4.0-ia32:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-ia32:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-ia32:printing-4.0-noarch
Distributor ID: RedHatEnterpriseServer
Description:    Red Hat Enterprise Linux Server release 5.6 (Tikanga)
Release:        5.6
Codename:       Tikanga

查看ldd 对默认安装的python 的作用(来自官方存储库)。

$ which python
/usr/bin/python
$ ldd `which python`
    libpython2.4.so.1.0 => /usr/lib64/libpython2.4.so.1.0 (0x00000030e6200000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00000030e0e00000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00000030e0a00000)
    libutil.so.1 => /lib64/libutil.so.1 (0x00000030ee800000)
    libm.so.6 => /lib64/libm.so.6 (0x00000030e0600000)
    libc.so.6 => /lib64/libc.so.6 (0x00000030e0200000)
    /lib64/ld-linux-x86-64.so.2 (0x00000030dfe00000)
$ ldd `which python` | grep readline
$

没有找到关于 readline 的信息。现在我从交互式使用中确实知道这个二进制文件确实具有实时功能,所以让我们不要尝试查看它的来源。

$ python &
[1] 21003
$ Python 2.4.3 (#1, Dec 10 2010, 17:24:35) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-50)] on linux2
Type "help", "copyright", "credits" or "license" for more information.

[1]+  Stopped                 python

在后台启动交互式 python 会话 (pid 21003)

$ lsof -p 21003
COMMAND   PID    USER   FD   TYPE DEVICE     SIZE    NODE NAME
python  21003 ddvento  cwd    DIR   0,33    16384  164304 /glade/home/ddvento/loader-test
python  21003 ddvento  rtd    DIR    8,3     4096       2 /
python  21003 ddvento  txt    REG    8,3     8304 6813419 /usr/bin/python
python  21003 ddvento  mem    REG    8,3   143600 8699326 /lib64/ld-2.5.so
python  21003 ddvento  mem    REG    8,3  1722304 8699327 /lib64/libc-2.5.so
python  21003 ddvento  mem    REG    8,3   615136 8699490 /lib64/libm-2.5.so
python  21003 ddvento  mem    REG    8,3    23360 8699458 /lib64/libdl-2.5.so
python  21003 ddvento  mem    REG    8,3   145824 8699445 /lib64/libpthread-2.5.so
python  21003 ddvento  mem    REG    8,3   247544 6821551 /usr/lib64/libreadline.so.5.1
python  21003 ddvento  mem    REG    8,3    15840 8699446 /lib64/libtermcap.so.2.0.8
python  21003 ddvento  mem    REG    8,3  1244792 6833317 /usr/lib64/libpython2.4.so.1.0
python  21003 ddvento  mem    REG    8,3    18152 8699626 /lib64/libutil-2.5.so
python  21003 ddvento  mem    REG    8,3 56446448 6832889 /usr/lib/locale/locale-archive
python  21003 ddvento  mem    REG    8,3    21808 6965997 /usr/lib64/python2.4/lib-dynload/readline.so
python  21003 ddvento  mem    REG    8,3    25464 6901074 /usr/lib64/gconv/gconv-modules.cache
python  21003 ddvento    0u   CHR  136,1                3 /dev/pts/1
python  21003 ddvento    1u   CHR  136,1                3 /dev/pts/1
python  21003 ddvento    2u   CHR  136,1                3 /dev/pts/1
$ lsof -p 21003 | grep readline
python  21003 ddvento  mem    REG    8,3   247544 6821551 /usr/lib64/libreadline.so.5.1
python  21003 ddvento  mem    REG    8,3    21808 6965997 /usr/lib64/python2.4/lib-dynload/readline.so

宾果!这里是readline!

但是,这种技术仅在库被有效加载时才有效,例如,直到 python 进程不运行类似 from Tkinter import * 的东西时,它才会找到 /usr/lib64/libtcl8.4.so

所以我有两个问题:

  1. 我认为ldd 的问题在于它假定使用标准加载器,而 python 很可能使用它自己的特殊加载器(这样您就不必每次都重新链接可执行文件)安装一个新的 python 模块,它不是纯 python,但有一些 c/c++/fortran 代码)。这是正确的吗?

  2. 1234563但是有没有办法找出python可以加载哪些库?

PS:与 1 相关。如果您正在回答这个问题,您应该已经知道以下内容,但如果不知道,您应该:看看完全搞砸 ldd 输出是多么简单(只是部分搞砸是有点困难):

$ cat hello.c 
#include <stdio.h>

int main() {
  printf("Hello world.\n");
  return 0;
}

$ gcc -static hello.c -o loader
$ gcc -Wl,--dynamic-linker,./loader hello.c -o hello
$ ./hello 
Hello world.
$ ldd ./hello
Hello world.

【问题讨论】:

  • 您能解释一下您的 Hello World 是如何愚弄ldd 的吗?这里是菜鸟。
  • 我在尝试运行hello 时遇到了段错误,尽管loader 运行良好。 lddnot a dynamic executable 代表loader(预期),而hello 给我ldd ./hello linux-vdso.so.1 (0x00007ffe0f5a0000) libc.so.6 =&gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6257aca000) ./loader =&gt; /lib64/ld-linux-x86-64.so.2 (0x00007f62580bd000)。顺便说一句,这是 ubuntu 18.04

标签: linux shared-libraries ldd


【解决方案1】:

Python、Perl 和其他解释型语言确实使用dlopen() 动态加载内容。 (这与替换标准加载器不同;他们仍在使用它,事实上dlopen() 是基于 ELF 系统上标准加载器的挂钩。)

可加载模块没有标准注册表。 Python 使用自己的规则来确定可以从哪里加载扩展模块(查看sys.path),包括那些具有关联共享对象的模块。 Perl 使用不同的规则。 Apache 仍然使用不同的规则等。

所以总结一下你的问题的答案:

  1. 不完全是

  2. 没有

【讨论】:

    【解决方案2】:

    作为旁注,实现我在问题 2 中想要的一种可能方法是:

    • 创建一个空的 chroot 环境

    • 在那里重新编译python,手动添加任何缺少的东西,一个接一个

    根据您的目标,这可能是一个好的解决方案,也可能不是(实际上对于我的目标来说并不算太糟糕 - 从问题中听起来可能很奇怪)

    【讨论】:

      【解决方案3】:

      使用 ldd -v 也可以转储库依赖项。这是一个例子:

      ave-ssh-test:tmp# ldd -v /sbin/coop.bin
              linux-vdso.so.1 =>  (0x00007fffd45f0000)
              libstdc++.so.6 => /lib64/libstdc++.so.6 (0x0000730cace67000)
      .
      .
      .
      Version information:
      
      /lib64/libstdc++.so.6:
                      ld-linux-x86-64.so.2 (GLIBC_2.3) => /lib64/ld-linux-x86-64.so.2
                      libm.so.6 (GLIBC_2.2.5) => /lib64/libm.so.6
                      libgcc_s.so.1 (GCC_4.2.0) => /lib64/libgcc_s.so.1
                      libgcc_s.so.1 (GCC_3.3) => /lib64/libgcc_s.so.1
                      libgcc_s.so.1 (GCC_3.0) => /lib64/libgcc_s.so.1
                      libc.so.6 (GLIBC_2.14) => /lib64/libc.so.6
                      libc.so.6 (GLIBC_2.4) => /lib64/libc.so.6
                      libc.so.6 (GLIBC_2.3) => /lib64/libc.so.6
                      libc.so.6 (GLIBC_2.3.2) => /lib64/libc.so.6
                      libc.so.6 (GLIBC_2.2.5) => /lib64/libc.so.6
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-08
        • 2020-03-12
        • 2017-03-30
        • 1970-01-01
        • 1970-01-01
        • 2019-02-10
        • 1970-01-01
        相关资源
        最近更新 更多