Проверка общих библиотек для загрузчиков не по умолчанию

ldd хороший простой способ проверить разделяемые библиотеки, которые использует или будет использовать данный исполняемый файл. Однако это не всегда работает, как ожидалось. Например, посмотрите следующий фрагмент оболочки, который демонстрирует, как "не удается" найти "зависимость" libreadline в двоичном файле python

Я пробовал много других дистрибутивов, но я копирую из 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!

Однако этот метод работает только тогда, когда библиотека эффективно загружена, например, он не находит /usr/lib64/libtcl8.4.so пока процесс python не запустит что-то вроде from Tkinter import *

Итак, у меня есть два вопроса:

  1. Я считаю проблема с ldd в том, что он предполагает использование стандартного загрузчика, в то время как очень вероятно, что python использует свой собственный специальный загрузчик (чтобы вам не приходилось повторно связывать исполняемый файл каждый раз, когда вы устанавливаете новый модуль python, который не является чистым python, но имеет некоторый / C++/ Фортран код). Это правильно?

  2. Ясно, что если исполняемый файл использует свой собственный загрузчик, то нет очевидного ответа на вопрос "как найти все возможные библиотеки, которые этот исполняемый файл может загрузить": это зависит от того, что делает загрузчик. Но есть ли способ узнать, какие библиотеки могут быть загружены 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.

2 ответа

Решение

Python, Perl и другие интерпретируемые языки загружают вещи динамически, используя dlopen(), (Это не то же самое, что замена стандартного загрузчика; они все еще используют это, и на самом деле dlopen() подключается к стандартному загрузчику в системах на базе ELF.)

Нет стандартного реестра для загружаемых модулей. Python использует свои собственные правила, чтобы определить, откуда можно загружать модули расширения (смотрите sys.path), включая те, которые связаны общими объектами. Perl использует разные правила. Apache использует еще другие правила и т. Д.

Итак, подведем итоги ответов на ваши вопросы:

  1. не совсем

  2. нет

Как примечание, возможный способ выполнить то, что я хотел в вопросе 2, состоял бы в следующем:

  • создать пустое окружение

  • перекомпилировать там Python, вручную добавляя все, что отсутствует, по одному

В зависимости от ваших целей, это может или не может быть хорошим решением (и на самом деле оказывается, что это не так уж плохо для моих целей - как это ни странно звучит из вопроса)

Используйте 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
Другие вопросы по тегам