Reputation: 10529
to clarify, my question refers to wrapping/intercepting calls from one function/symbol to another function/symbol when the caller and the callee are defined in the same compilation unit with the GCC compiler and linker.
I have a situation resembling the following:
/* foo.c */
void foo(void)
{
/* ... some stuff */
bar();
}
void bar(void)
{
/* ... some other stuff */
}
I would like to wrap calls to these functions, and I can do that (to a point) with ld's --wrap
option (and then I implement __wrap_foo and __wrap_bar which in turn call __real_foo and __real_bar as expected by the result of ld's --wrap
option).
gcc -Wl,--wrap=foo -Wl,--wrap=bar ...
The problem I'm having is that this only takes effect for references to foo and bar from outside of this compilation unit (and resolved at link time). That is, calls to foo and bar from other functions within foo.c do not get wrapped.
I tried using objcopy --redefine-sym, but that only renames the symbols and their references.
I would like to replace calls to foo
and bar
(within foo.o) to __wrap_foo
and __wrap_bar
(just as they get resolved in other object files by the linker's --wrap
option) BEFORE I pass the *.o files to the linker's --wrap
options, and without having to modify foo.c's source code.
That way, the wrapping/interception takes place for all calls to foo
and bar
, and not just the ones taking place outside of foo.o.
Is this possible?
Upvotes: 48
Views: 39160
Reputation: 11
Although this thread was initiated over 11 years ago, I wanted to share a solution for anyone who might encounter a similar issue. I've wrote a tool that can wrap all symbols, regardless of whether they are undefined in the current compilation unit or not.
The tool is doing it utilizing the LIEF Python module (https://github.com/lief-project/LIEF), and modifying symbols and relocations in the object files.
Here the link to the Github Repo: https://github.com/wafgo/WrapMaster/tree/master
Upvotes: 1
Reputation: 53
With linker
$ /usr/bin/ld --version
GNU ld (GNU Binutils for Ubuntu) 2.30
I was able to solve the problem using the defsym
option:
--defsym SYMBOL=EXPRESSION Define a symbol`
Instead of
gcc -Wl,--wrap=foo -Wl,--wrap=bar ...
try
gcc -Wl,--defsym,foo=__wrap_foo -Wl,--defsym,bar=__wrap_bar ...
I did not also try to define __real_*
symbols.
Upvotes: 0
Reputation: 51
I have tried the solution from @PeterHuewe and it works but it doesn't allow to call the original function from the wrapper. To allow this my solution is the following:
foo.c
#include <stdio.h>
void foo(){
printf("This is real foo\n");
}
int main(){
printf("main\n");
foo();
}
foo_hook.c
#include <stdio.h>
void real_foo();
int foo(){
printf("HOOK: BEFORE\n");
real_foo();
printf("HOOK: AFTER\n");
}
Makefile
all: link
link: hook
gcc -o wo_hook foo.o
gcc -o w_hook foo_hooked.o foo_hook.o
hook: build_o
objcopy \
foo.o \
--add-symbol real_foo=.text:$(shell objdump -t foo.o | grep foo | grep .text | cut -d' ' -f 1),function,global \
--globalize-symbol=foo \
--weaken-symbol=foo \
foo_hooked.o
build_o:
gcc -c foo.c foo_hook.c
clean:
-rm w_hook wo_hook *.o
Example
virtualuser@virtualhost:~/tmp/link_time_hook$ make
gcc -c foo.c foo_hook.c
objcopy foo.o \
--add-symbol real_foo=.text:0000000000000000,function,global \
--globalize-symbol=foo \
--weaken-symbol=foo \
foo_hooked.o
gcc -o wo_hook foo.o
gcc -o w_hook foo_hooked.o foo_hook.o
virtualuser@virtualhost:~/tmp/link_time_hook$ ls
Makefile foo.c foo.o foo_hook.c foo_hook.o foo_hooked.o w_hook wo_hook
virtualuser@virtualhost:~/tmp/link_time_hook$ ./w_hook
main
HOOK: BEFORE
This is real foo
HOOK: AFTER
virtualuser@virtualhost:~/tmp/link_time_hook$
virtualuser@virtualhost:~/tmp/link_time_hook$ ./wo_hook
main
This is real foo
virtualuser@virtualhost:~/tmp/link_time_hook$
Upvotes: 5
Reputation:
You can use __attribute__((weak))
before the implementation of the callee in order to let someone reimplement it without GCC yelling about multiple definitons.
For example suppose you want to mock the world
function in the following hello.c code unit. You can prepend the attribute in order to be able to override it.
#include "hello.h"
#include <stdio.h>
__attribute__((weak))
void world(void)
{
printf("world from lib\n");
}
void hello(void)
{
printf("hello\n");
world();
}
And you can then override it in another unit file. Very useful for unit testing/mocking:
#include <stdio.h>
#include "hello.h"
/* overrides */
void world(void)
{
printf("world from main.c"\n);
}
void main(void)
{
hello();
return 0;
}
Upvotes: 10
Reputation: 246
You have to weaken and globalize the symbol using objcopy.
-W symbolname
--weaken-symbol=symbolname
Make symbol symbolname weak. This option may be given more than once.
--globalize-symbol=symbolname
Give symbol symbolname global scoping so that it is visible outside of the file in which it is defined. This option may be given more than once.
This worked for me
bar.c:
#include <stdio.h>
int foo(){
printf("Wrap-FU\n");
}
foo.c:
#include <stdio.h>
void foo(){
printf("foo\n");
}
int main(){
printf("main\n");
foo();
}
Compile it
$ gcc -c foo.c bar.c
Weaken the foo symbol and make it global, so it's available for linker again.
$ objcopy foo.o --globalize-symbol=foo --weaken-symbol=foo foo2.o
Now you can link your new obj with the wrap from bar.c
$ gcc -o nowrap foo.o #for reference
$ gcc -o wrapme foo2.o bar.o
Test
$ ./nowrap
main
foo
And the wrapped one:
$ ./wrapme
main
Wrap-FU
Upvotes: 23
Reputation: 1847
#include <stdio.h>
#include <stdlib.h>
//gcc -ggdb -o test test.c -Wl,-wrap,malloc
void* __real_malloc(size_t bytes);
int main()
{
int *p = NULL;
int i = 0;
p = malloc(100*sizeof(int));
for (i=0; i < 100; i++)
p[i] = i;
free(p);
return 0;
}
void* __wrap_malloc(size_t bytes)
{
return __real_malloc(bytes);
}
And then just compile this code and debug. When you call the reall malloc, the function called will __wrap_malloc and __real_malloc will call malloc.
I think this is the way to intercept the calls.
Basically its the --wrap option provided by ld.
Upvotes: 7
Reputation: 213799
This appears to be working as documented:
--wrap=symbol
Use a wrapper function for symbol.
Any undefined reference to symbol will be resolved to "__wrap_symbol". ...
Note the undefined above. When the linker processes foo.o
, the bar()
is not undefined, so the linker does not wrap it. I am not sure why it's done that way, but there probably is a use case that requires this.
Upvotes: 6
Reputation: 49
You can achieve what you want if you use --undefined
with --wrap
-u SYMBOL, --undefined SYMBOL
Start with undefined reference to SYMBOL
Upvotes: 4