Как повторно реализовать (или обернуть) функцию системного вызова в Linux?

Предположим, я хочу полностью взять на себя системный вызов open(), возможно, чтобы обернуть фактический системный вызов и выполнить некоторую регистрацию. Один из способов это использование LD_PRELOAD для загрузки (созданной пользователем) общей библиотеки объектов, которая принимает точку входа open().

Созданная пользователем подпрограмма open() затем получает указатель на функцию glibc open(), dlsym() изменяя ее и вызывая ее.

Однако предложенное выше решение является динамическим. Предположим, я хочу статически связать свою собственную оболочку open(). Как бы я это сделал? Я предполагаю, что механизм тот же, но я также предполагаю, что будет конфликт символов между определенным пользователем open() и libc open().

Пожалуйста, поделитесь любыми другими методами для достижения той же цели.


person Stefano Borini    schedule 07.09.2010    source источник
comment
Как насчет того, чтобы просто вставить функцию-оболочку/макрос в свой код?   -  person Seamus Connor    schedule 08.09.2010
comment
@Seamus: я предпочитаю не использовать макросы. У меня нет проблем. Я прошу просто увеличить знания SO и изучить какой-нибудь новый трюк.   -  person Stefano Borini    schedule 08.09.2010


Ответы (2)


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

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

Любая неопределенная ссылка на __real_symbol будет преобразована в symbol.

Поэтому вам просто нужно использовать префикс __wrap_ для вашей функции-оболочки и __real_, когда вы хотите вызвать настоящую функцию. Простой пример:

malloc_wrapper.c:

#include <stdio.h>
void *__real_malloc (size_t);

/* This function wraps the real malloc */
void * __wrap_malloc (size_t size)
{
    void *lptr = __real_malloc(size);
    printf("Malloc: %lu bytes @%p\n", size, lptr);
    return lptr;
}

Тестовое приложение testapp.c:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    free(malloc(1024)); // malloc will resolve to __wrap_malloc
    return 0;
}

Затем скомпилируйте приложение:

gcc -c malloc_wrapper.c
gcc -c testapp.c
gcc -Wl,-wrap,malloc testapp.o malloc_wrapper.o -o testapp

Вывод результирующего приложения будет:

$ ./testapp
Malloc: 1024 bytes @0x20d8010
person Giuseppe Cardone    schedule 07.09.2010
comment
Похоже, что функция, которая вызывает malloc, не может быть динамически связана. Например, я написал tools.c, который содержит функцию Perform_alloc(), которая вызывает malloc. Тогда, если я сначала создам libtools.so и динамически свяжу его с помощью -ltools, -Wl,-wrap,malloc не будет работать. - person xanpeng; 05.09.2012
comment
Как указано в stackoverflow.com/questions/3826108/ требуется префикс определения функции с префиксом extern "C" при использовании этого кода в программе C++. - person MKroehnert; 26.08.2014
comment
Должна ли функция называться __wrap_malloc? Или можно по другому назвать? Я имею в виду, что при переносе системных вызовов мы должны называть функции так же, как и фактический вызов? - person Munib; 03.06.2017
comment
@return0: как показывает man ld, символы должны иметь префиксы __wrap_ и __real_. - person Giuseppe Cardone; 07.06.2017

Символы разрешаются компоновщиком в том порядке, в котором вы перечисляете их в командной строке, поэтому, если вы указали свою библиотеку перед стандартной библиотекой, у вас будет точность. Для gcc вам нужно указать

gcc <BLAH> -nodefaultlibs <BLAH BLAH> -lYOUR_LIB <OTHER_LIBS>

Таким образом, ваши библиотеки будут искать и находить первыми.

person Paul Rubel    schedule 07.09.2010