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

Мой вопрос заключается в следующем:

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

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

РЕДАКТИРОВАТЬ: я хочу эту информацию за пределами программы (т.е. с использованием таких утилит, как objdump собирать информацию)

5 ответов

Решение

Библиотеки загружаются 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, который устанавливает переменную среды отладки ld.so (на самом деле LD_TRACE_LOADED_OBJECTS=1 в случае rtld glibc) и запускает программу. Вы даже можете сделать это самостоятельно без использования скрипта, например, с помощью bash, легко меняющего переменные окружения для одного запуска:

 LD_TRACE_LOADED_OBJECTS=1 /bin/echo

ld.so увидит эту переменную и разрешит все необходимые библиотеки и распечатает их адреса загрузки. Но с этой переменной, ld.so фактически не запустит программу (не уверен насчет статических конструкторов программы или библиотек). Если функция ASLR отключена, адрес загрузки будет в большинстве случаев одинаковым. В современных Linux-системах часто включен ASLR, поэтому для его отключения используйте 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.

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

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

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

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

Если вы просто хотите получить адрес функции, не задавая имя в жестком виде, вы можете dlopen() Основная программа:

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

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

Я рекомендую, чтобы в вашей среде был путь 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

Другие вопросы по тегам