robert song wrote: > Hello, everyone. I used -finstrument-functions option to trace some > program, and I found that address past to __cyg_profile_func_{enter, > exit} is not so precise. > > The example is as below. > > foo.c : > int foo() > { > return 1; > } > int bar() > { > return 2; > } > > main.c : > #include <stdio.h> > extern int foo(), bar(); > void *ptr = foo; > > int main(int argc, char *argv[]) > { > foo(); > bar(); > return 0 ; > } > > tracer.c : > #define _GNU_SOURCE > #include <stdio.h> > > void __cyg_profile_func_enter(void *this_fn, void *call_site) > __attribute__((no_instrument_function)); > void __cyg_profile_func_exit(void *this_fn, void *call_site) > __attribute__((no_instrument_function)); > > void __cyg_profile_func_enter(void *this_fn, void *call_site) > { > printf("addr:%lx\n", this_fn); > } > > void __cyg_profile_func_exit(void *this_fn, void *call_site) > { > printf("addr:%lx\n", this_fn); > } > > $ cc -fPIC -finstrument-functions -g -shared -o foo.so foo.c > $ cc -finstrument-functions -g -o main main.c tracer.c foo.so -Wl,-rpath `pwd` > > The addresses past to __cyg_profile_func_{enter,exit} are as below: > addr:8048514 <- main > addr:8048418 <- foo > addr:8048418 <- foo > addr:37b4b7 <- bar > addr:37b4b7 <- bar > addr:8048514 <- main > > $ readelf -s main | grep foo > 7: 08048418 75 FUNC GLOBAL DEFAULT UND foo > 69: 08048418 75 FUNC GLOBAL DEFAULT UND foo > > As you can see, foo is undefined symbol but has the value of > 0x08048418, and I think the relocated address (0x37b46c) of foo > should be more reasonable, just like bar() function. > > Now I don't have a good method to deal with the problem, Can anyone > give me some advise to do the trick in __cyg_profile_func_enter() to > get the correct address ? The shared library loader is trying to make the code as efficient as possible. When you take the address of a symbol in main, the loader is forced to fix up the reloc with a pointer into the PLT. This happens because at the time the fixup is made, the symbol foo has not been resolved: it'll only be resolved later when the first call to foo happens. So, we have to use the PLT address because we don't yet know where foo is. Because of C's rule that the address of a function must be unique, every subsequent reference to that symbol will return the PLT address, including the one used in the call to __cyg_profile_func_enter(). You can get around this by compiling main with -fpic and not globally initializing ptr. void *ptr; int main (int argc, char *argv[]) { ptr = foo; cc -fpic -finstrument-functions -g -o main main.c tracer.c foo.so -Wl,-rpath `pwd` $ ./main addr:40073c addr:110634 addr:110634 addr:11066b addr:11066b addr:40073c Andrew.