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

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

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

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

4 ответа

Решение

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

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

Это можно использовать для предоставления оболочки для системной функции. Функция обертки должна быть вызвана__wrap_symbolMsgstr "Если он хочет вызвать системную функцию, он должен вызвать"__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_mallocmsgstr "; если вы это сделаете, ассемблер может разрешить вызов до того, как у компоновщика появится возможность перевести его в" 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.

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