2012-04-20 8 views
7

ldd es una buena manera simple de comprobar las bibliotecas compartidas que un ejecutable dado está o va a utilizar. Sin embargo, no siempre funciona como se esperaba. Por ejemplo, ver el siguiente fragmento de concha que demuestra la forma en que "no" a conocer el libreadline "dependencia" en la pitón binariacomprobación de bibliotecas compartidas para cargadores no predeterminados

He intentado muchas otras distribuciones, pero estoy copiando de 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 

Consulte lo que hace ldd en el valor predeterminado python (de los repositorios oficiales).

$ 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 
$ 

No se encontró nada sobre readline. Ahora sé por el uso interactivo que este binario sí tiene funcionalidad real, así que no intentemos ver de dónde viene.

$ 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 

Comienza una sesión interactiva de Python en el fondo (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 

Bingo! ¡Aquí está readline!

Sin embargo, esta técnica sólo funciona cuando la biblioteca se carga de manera eficaz, así que por ejemplo no encuentra /usr/lib64/libtcl8.4.so hasta que el proceso de Python no funcionar algo así como from Tkinter import *

Así que tengo dos preguntas:

  1. Creo que el problema con ldd es que asume el uso del cargador estándar, mientras que es muy probable que python esté usando su propio cargador especial (para que no tenga que volver a vincular el ejecutable cada vez que instale un nuevo módulo python que no es pura pitón, pero tiene algo de c/C++/fortran código). ¿Es esto correcto?

  2. Claramente, si un ejecutable usa su propio cargador, no hay una respuesta obvia a la pregunta "cómo encontrar todas las bibliotecas posibles que este archivo ejecutable puede cargar": depende de lo que haga el cargador. Pero, ¿hay alguna forma de averiguar qué bibliotecas puede cargar Python?

PS: relacionadas con 1. Si usted está aterrizando en esta pregunta que ya debe saber lo siguiente, pero si no lo hacen usted debe: ver lo sencillo que es completamente estropear ldd salida (mezclarlo solamente en parte es un poco más difícil):

$ 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. 

Respuesta

5

Python, Perl y otros lenguajes interpretados hacer las cosas de carga dinámicamente utilizando dlopen(). (Esto no es lo mismo que reemplazar el cargador estándar, todavía lo usan, y de hecho dlopen() es un gancho en el cargador estándar en sistemas basados ​​en ELF.)

No hay un registro estándar para módulos cargables. Python usa sus propias reglas para determinar desde dónde se pueden cargar los módulos de extensión (consulte sys.path), incluidos los que tienen objetos compartidos asociados. Perl usa diferentes reglas. Apache usa reglas aún diferentes, etc.

Entonces, para resumir las respuestas a sus preguntas:

  1. no exactamente

  2. sin

+0

Ok, gracias, edité ligeramente su respuesta y la acepté. – Davide

0

Como nota al margen, una posible manera de lograr lo que quería en cuestión 2 sería:

  • crear un entorno enjaulado vacío

  • pitón recompilación allí, añadiendo manualmente cualquier cosa que falta, uno por uno

Dependiendo de sus objetivos, esto podría o no podría ser una buena solución (y en realidad resulta no ser tan malo para lo que son mis objetivos, por extraño que pueda parecer en la pregunta)

Cuestiones relacionadas