Подтвердить что ты не робот

Когда/Как Linux загружает совместно используемые библиотеки в адресное пространство?

Мой вопрос следующий:

Когда указывается адрес общих объектов, указанных в программах? Во время ссылки? Загрузка? Если бы я захотел найти адрес памяти команды system внутри libc внутри моей программы, я мог бы легко найти ее в gdb, но что, если я не хочу приносить программу в отладчик?

Может ли этот адрес измениться после запуска? Есть ли другой инструмент статического анализа, который позволит просматривать, где библиотеки или функции будут загружаться в это пространство памяти программы при запуске?

EDIT: я хочу эту информацию за пределами программы (т.е. используя утилиты, такие как objdump для сбора информации)

4b9b3361

Ответ 1

Библиотеки загружаются ld.so (динамический компоновщик или компоновщик времени выполнения aka rtld, ld-linux.so.2 или ld-linux.so.* в случае Linux, часть glibc). Он объявлен как "интерпретатор" (INTERP; .interp) всех динамических связанных ELF-двоичных файлов. Итак, когда вы запускаете программу, Linux запустит ld.so (загрузите в память и перейдете к ее точке входа), затем ld.so загрузит вашу программу в память, подготовит ее и запустит. Вы также можете запустить динамическую программу с помощью

 /lib/ld-linux.so.2 ./your_program your_prog_params

ld.so содержит фактические open и mmap из всех необходимых файлов ELF, как ELF файл вашей программы, так и файлы ELF всех библиотек. Кроме того, он заполняет таблицы GOT и PLT и разрешает репозиционирование (он записывает адреса функций из библиотек для вызова сайтов, во многих случаях с косвенными вызовами).

Типичный адрес загрузки некоторой библиотеки, которую вы можете получить с помощью утилиты ldd. На самом деле это bash script, который устанавливает переменную среды отладки ld.so(фактически LD_TRACE_LOADED_OBJECTS=1 в случае glibc rtld) и запускает программу. Вы даже можете сделать это самостоятельно без потребностей script, например. с использованием bash легкой замены переменных среды для одиночного запуска:

 LD_TRACE_LOADED_OBJECTS=1 /bin/echo

ld.so увидит эту переменную и разрешит все необходимые библиотеки и распечатает адреса загрузки. Но с этим набором переменных ld.so фактически не запустит программу (не уверен в статических конструкторах программы или библиотек). Если функция echo 0 | sudo tee /proc/sys/kernel/randomize_va_space.

Вы можете найти смещение функции system внутри libc.so с помощью утилиты nm из binutils. Я думаю, вы должны использовать nm -D /lib/libc.so или objdump -T /lib/libc.so и grep-вывод.

Ответ 2

"Идите прямо к источнику и спросите лошадь..."

Drepper - Как писать общие библиотеки

Должна быть прочитана документация для библиотек библиотек Linux. Объясняет механику загрузки в деталях.

Ответ 3

Команда nm, используемая в libc.so, покажет вам расположение символа system в libc.so. Однако, если ASLR включен, адрес libc.so загружается, и, таким образом, конечный адрес system будет меняться случайным образом каждый раз, когда ваша программа будет запущена. Даже без ASLR вам нужно будет определить, что адрес libc.so загружается и смещает адрес system на эту сумму.

Ответ 4

Если вам просто нужен адрес функции, а не hardcoding имя, вы можете dlopen() основной программы:

void *self = dlopen(NULL, RTLD_NOW);
dlsym(self, "system"); // returns the pointer to the system() function

Если вам просто нужен адрес функции, имя которой вы знаете во время компиляции, просто используйте void *addr = &system;

Ответ 5

Id рекомендует, чтобы ваша среда имела путь LD_LIBRARY_PATH. Это определяет, где должны быть найдены общие библиотеки. Возможно, вам также придется посмотреть в /etc/ld.so.conf Посмотрите на это сообщение 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