Взаимодействие функций в Linux без dlsym

В настоящее время я работаю над проектом, в котором мне нужно отслеживать использование нескольких системных вызовов и низкоуровневых функций, таких как mmap, brk, sbrk. До сих пор я делал это, используя интерпозицию функций: я пишу функцию-оболочку с тем же именем, что и функция, которую я заменяю (например, mmap), и я загружаю ее в программу, устанавливая переменную окружения LD_PRELOAD. Я вызываю настоящую функцию через указатель, который загружаю с помощью dlsym.

К сожалению, одна из функций, которую я хочу обернуть, sbrk, используется внутри dlsym, поэтому программа вылетает, когда я пытаюсь загрузить символ. sbrk не является системным вызовом в Linux, поэтому я не могу просто использовать syscall для его косвенного вызова.

Итак, мой вопрос: как я могу вызвать библиотечную функцию из функции-оболочки с тем же именем без использования dlsym? Есть ли какой-нибудь трюк с компилятором (с использованием gcc), который позволяет мне ссылаться на исходную функцию?


person Jay Conrod    schedule 15.06.2009    source источник


Ответы (4)


см. вариант ld --wrap symbol. Со страницы руководства:

--wrap symbol Использовать функцию-оболочку для символа. Любая неопределенная ссылка на символ будет преобразована в "__wrap_symbol". Любая неопределенная ссылка на "__real_symbol" будет преобразована в символ.

Это можно использовать для предоставления оболочки для системной функции. Функция-оболочка должна называться "__wrap_symbol". Если он хочет вызвать системную функцию, он должен вызвать «__real_symbol».

Вот тривиальный пример:

void *
__wrap_malloc (size_t c)
{
    printf ("malloc called with %zu\n", c);
    return __real_malloc (c);
}

Если вы свяжете другой код с этим файлом, используя --wrap malloc, то все вызовы "malloc" вместо этого будут вызывать функцию "__wrap_malloc". Вызов "__real_malloc" в
"__wrap_malloc" вызовет настоящую функцию "malloc".

Вы также можете добавить функцию "__real_malloc", чтобы ссылки без опции --wrap работали успешно. Если вы сделаете это, вы не должны помещать определение "__real_malloc" в тот же файл, что и "__wrap_malloc"; если вы это сделаете, ассемблер может разрешить вызов до того, как компоновщик успеет обернуть его в «malloc».

Другой вариант - посмотреть исходный код ltrace, он более или менее делает то же самое :-P.

Хотя есть идея. Вы можете сделать так, чтобы ваша библиотека LD_PRELOADed изменила записи PLT, чтобы они указывали на ваш код. Технически функция sbrk() все еще может быть вызвана из вашего кода изначально.

person Evan Teran    schedule 15.06.2009
comment
Отлично. Я никогда не слышал об опции --wrap, но это именно то, что мне нужно. Спасибо. - person Jay Conrod; 16.06.2009
comment
Чтобы уточнить, нужно ли передавать флаги --wrap при компоновке исполняемого файла или при компоновке библиотеки LD_PRELOAD, содержащей обертки? Кроме того, не могли бы вы предоставить дополнительную информацию об изменении записей PLT исполняемого файла? - person Jay Conrod; 16.06.2009
comment
Разработанный вариант использования заключается в том, чтобы связать целевое приложение с --wrap. Возможно, получится заставить его работать и для случая LD_PRELOAD, я не уверен, надо будет проверить. - person Evan Teran; 16.06.2009

Вы можете ненавязчиво исследовать вызов функции, используя такие инструменты, как:

  • gdb
  • трассировка
  • системный тап

Эти инструменты позволяют программе монитора информировать вас о вызове функции и позволяют запрашивать аргументы.

Основные отличия:

  • gdb интерактивный, но мощный
  • ltrace прост в использовании, но вы можете распечатать только имя функции
  • systemtap не интерактивен, но может быть очень быстрым и мощным.
person Alex Brown    schedule 15.06.2009

Если вы используете хост-систему с glibc, у libc есть какая-то внутренняя часть для динамического компоновщика времени выполнения, который я использовал некоторое время назад. Если я правильно помню, я думаю, что это называется «__libc_dlsym». (Для проверки "$ readelf -s /usr/lib/libc.a | grep dlsym" должно помочь.) Объявите ее как внешне связанную функцию с теми же аргументами и возвращаемым значением, что и у dlsym, и используйте ее для переноса самой dlsym.

person Community    schedule 14.08.2009

truss не работает в вашей системе? Он отлично работает для таких вещей здесь, в Solaris.

person Patrick Schlüter    schedule 21.06.2011
comment
Это звучит точно так же, как strace в Linux. Это прекрасно работает, если вам нужно только получить список сделанных звонков. В этом проекте мне нужно было добавить некоторую функциональность оберткам, и я думаю, что интерпозиция — единственный способ сделать это. - person Jay Conrod; 22.06.2011