library - gcc
¿Cuándo/Cómo carga Linux las bibliotecas compartidas en el espacio de direcciones? (5)
"Ve directamente a la fuente y pregunta al caballo ..."
Drepper - Cómo escribir bibliotecas compartidas
Debe leer la documentación para los escritores de la biblioteca Linux. Explica la mecánica de la carga con cierto detalle.
Mi pregunta es la siguiente:
¿Cuándo se especifica la dirección de los objetos compartidos en los programas? Durante la vinculación? ¿Cargando? Si quisiera encontrar la dirección de memoria del comando del system
dentro de libc
dentro de mi programa, podría encontrarla fácilmente en gdb
, pero ¿qué pasa si no quiero incluir el programa en un depurador?
¿Podría esta dirección cambiar de ejecución a ejecución? ¿Hay alguna otra herramienta de análisis estático que permita ver dónde se cargarán las bibliotecas o funciones en el espacio de memoria de este programa cuando se ejecute?
EDITAR: Quiero esta información fuera del programa (es decir, usando utilidades como objdump
para recopilar información)
El comando nm
, utilizado en libc.so
, le mostrará la ubicación del símbolo del system
en libc.so
Sin embargo, si ASLR está habilitado, la dirección libc.so
se carga en, y por lo tanto la dirección final del system
variará aleatoriamente cada vez que se ejecute su programa. Incluso sin ASLR, deberá determinar la dirección en la que libc.so
se carga y compensar la dirección del system
en esa cantidad.
Id recomiendo que su entorno tenga la ruta LD_LIBRARY_PATH. Esto define dónde se encuentran las bibliotecas compartidas. También es posible que deba buscar en /etc/ld.so.conf Consulte esta publicación http://www.google.com/url?sa=t&source=web&cd=3&ved=0CCQQFjAC&url=http%3A%2F%2Fubuntuforums.org%2Fshowthread.php%3Ft%3D324660&ei=KqJpTey7JofEsAPE9_imBA&usg=AFQjCNEIbGGrTHp4fufRuj4Yfc58RTHcag&sig2=_9tdlyadMbPc-FcOdCko-w
Las bibliotecas son cargadas por ld.so
(enlazador dinámico o enlazador en tiempo de ejecución alias rtld, ld-linux.so.2
o ld-linux.so.*
En el caso de Linux, parte de glibc). Se declara como "intérprete" (INTERP; .interp
section) de todos los binarios ELF vinculados dinámicamente. Entonces, cuando inicie el programa, Linux iniciará ld.so
(cargará en la memoria y saltará a su punto de entrada), luego ld.so
cargará su programa en la memoria, lo preparará y luego lo ejecutará. También puede iniciar un programa dinámico con
/lib/ld-linux.so.2 ./your_program your_prog_params
ld.so
hace un open
y mmap
real de todos los archivos ELF necesarios, tanto el archivo ELF de su programa como los archivos ELF de todas las bibliotecas necesarias. Además, llena las tablas GOT y PLT y resuelve las reubicaciones (escribe las direcciones de las funciones de las bibliotecas para llamar a los sitios, en muchos casos con llamadas indirectas).
La dirección de carga típica de alguna biblioteca puede obtenerse con la utilidad ldd
. En realidad, es un script bash, que establece una variable de entorno de depuración de ld.so (en realidad LD_TRACE_LOADED_OBJECTS=1
en el caso de glibc''s rtld) e inicia un programa. Incluso puede hacerlo usted mismo sin necesidad de la secuencia de comandos, por ejemplo, con bash fácil cambio de variables de entorno para una sola ejecución:
LD_TRACE_LOADED_OBJECTS=1 /bin/echo
El ld.so
verá esta variable y resolverá todas las bibliotecas necesarias e imprimirá las direcciones de carga de las mismas. Pero con este conjunto de variables, ld.so
realidad no iniciará un programa (no está seguro acerca de los constructores estáticos del programa o las bibliotecas). Si la función ASLR está desactivada, la dirección de carga será la misma la mayoría de las veces. Los Linux modernos a menudo tienen ASLR activado, por lo que para desactivarlo, use echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
.
Puede encontrar la compensación de la función del system
dentro de libc.so
con la utilidad nm
de binutils. Creo que deberías usar nm -D /lib/libc.so
u objdump -T /lib/libc.so
y grep output.
Si solo quiere la dirección de una función sin codificar el nombre, puede dlopen()
el programa principal:
void *self = dlopen(NULL, RTLD_NOW);
dlsym(self, "system"); // returns the pointer to the system() function
Si solo desea la dirección de una función cuyo nombre conoce en tiempo de compilación, simplemente use void *addr = &system;