Вставка функции в Linux без dlsym
В настоящее время я работаю над проектом, в котором мне нужно отслеживать использование нескольких системных вызовов и низкоуровневых функций, таких как mmap
, brk
, sbrk
, До сих пор я делал это с помощью вставки функции: я пишу функцию-оболочку с тем же именем, что и функция, которую я заменяю (mmap
например), и я загружаю его в программу, установив LD_PRELOAD
переменная окружения. Я вызываю реальную функцию через указатель, который загружаю dlsym
,
К сожалению, одна из функций, которую я хочу обернуть, sbrk
, используется внутри dlsym
, поэтому программа вылетает, когда я пытаюсь загрузить символ. sbrk
это не системный вызов в Linux, поэтому я не могу просто использовать syscall
называть это косвенно.
Итак, мой вопрос, как я могу вызвать библиотечную функцию из одноименной функции-оболочки без использования dlsym
? Есть ли какой-нибудь трюк с компилятором (использующий gcc), который позволяет мне ссылаться на оригинальную функцию?
4 ответа
См. вариант ld --wrap symbol
, Со страницы руководства:
--wrap symbol Использовать функцию-обертку для символа. Любая неопределенная ссылка на символ будет разрешена как "
__wrap_symbol
Msgstr "Любая неопределенная ссылка на"__real_symbol
"будет разрешен к символу.Это можно использовать для предоставления оболочки для системной функции. Функция обертки должна быть вызвана
__wrap_symbol
Msgstr "Если он хочет вызвать системную функцию, он должен вызвать"__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
msgstr "; если вы это сделаете, ассемблер может разрешить вызов до того, как у компоновщика появится возможность перевести его в" malloc ".
Другой вариант, возможно, посмотреть на источник для ltrace, он более или менее делает то же самое:-P.
Вот идея, хотя. Вы могли бы иметь LD_PRELOAD
'ed библиотека изменяет записи PLT, чтобы они указывали на ваш код. Это ты технически то sbrk()
функция по-прежнему вызывается из вашего кода наивно.
Вы можете ненавязчиво изучить вызов функции, используя такие инструменты, как:
- GDB
- ltrace
- Systemtap
Эти инструменты позволяют программе монитора сообщать вам, когда вызывается функция, и позволяют запрашивать аргументы.
Основными отличиями являются:
- GDB является интерактивным, но мощным
- ltrace прост в использовании, но вы можете только напечатать имя функции
- Systemtap не интерактивен, но он может быть очень быстрым и мощным.
Если вы используете хост-систему с glibc, у libc есть некоторый внутренний бэкэнд динамического компоновщика времени выполнения, который я использовал некоторое время назад. Если я правильно помню, я думаю, что это называется __libc_dlsym. (Чтобы проверить, "$ readelf -s /usr/lib/libc.a | grep dlsym" должен помочь.) Объявите ее как внешне связанную функцию с теми же аргументами и возвращаемым значением, что и у dlsym, и используйте ее для переноса самого dlsym.
Есть ли truss
не работает в вашей системе? Это прекрасно работает для такого рода вещей здесь, на Solaris.