У компоновщика GNU есть опция --wrap <symbol>
, которая позволяет вам делать подобные вещи.
Если вы связываетесь с --wrap write
, ссылки на write
будут перенаправлены на __wrap_write
(который выреализовать), а ссылки на __real_write
будут перенаправлены на исходный write
(так что вы можете вызвать его изнутри вашей реализации оболочки).
Вот сложное тестовое приложение, использующее write()
- я делаюэтапы компиляции и компоновки выполняются отдельно, потому что я хочу снова использовать hello.o
через минуту:
$ cat hello.c
#include <unistd.h>
int main(void)
{
write(0, "Hello, world!\n", 14);
return 0;
}
$ gcc -Wall -c hello.c
$ gcc -o test1 hello.o
$ ./test1
Hello, world!
$
Вот реализация __wrap_write()
, которая вызывает __real_write()
.(Обратите внимание, что мы хотим, чтобы прототип для __real_write
соответствовал оригиналу. Я явно добавил соответствующий прототип, но другой возможный вариант - это #define write __real_write
до #include <unistd.h>
.)
$ cat wrapper.c
#include <unistd.h>
extern ssize_t __real_write(int fd, const void *buf, size_t n);
ssize_t __wrap_write(int fd, const void *buf, size_t n)
{
__real_write(fd, "[wrapped] ", 10);
return __real_write(fd, buf, n);
}
$ gcc -Wall -c wrapper.c
$
Теперь свяжите hello.o
, который мы сделали ранее, с wrapper.o
, передав соответствующие флаги компоновщику.(Мы можем передавать произвольные опции через gcc
компоновщику, используя слегка нечетный синтаксис -Wl,option
.)
$ gcc -o test2 -Wl,--wrap -Wl,write hello.o wrapper.o
$ ./test2
[wrapped] Hello, world!
$