这些天我在Ubuntu上用g共享对象(.so)文件测试-finstrument-functions.我发现了一个奇怪的行为 – 只有在静态链接库时,-finstrument-functions似乎才有效.如果我用dlopen / dlsym等链接到库,代码的功能仍然有效,但它不会调用__cyg_profile *函数.
MyLib.h
#ifndef __MYLIB_H__ #define __MYLIB_H__ class MyLib { public: void sayHello(); }; #endif
MyLib.cpp
#include "MyLib.h" #include <iostream> using namespace std; void MyLib::sayHello() { cout<<"Hello"<<endl; }
MyLibStub.cpp(.so的C接口)
#include "MyLib.h" extern "C" void LoadMyLib () { MyLib().sayHello(); }
Trace.cpp
#include <stdio.h> #ifdef __cplusplus extern "C" { 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)); } #endif void __cyg_profile_func_enter(void* this_fn,void* call_site) { printf("entering %p\n",(int*)this_fn); } void __cyg_profile_func_exit(void* this_fn,void* call_site) { printf("exiting %p\n",(int*)this_fn); }
MainStatic.cpp
#include <iostream> using namespace std; extern "C" void LoadMyLib (); int main() { LoadMyLib(); return 0; }
MainDynamic.cpp
#include <iostream> #include <dlfcn.h> const char* pszLibName = "libMyLib.so.0.0"; const char* pszFuncName = "LoadMyLib"; int main() { void* pLibHandle = dlopen(pszLibName,RTLD_NOW); if(!pLibHandle) { return 1; } void (*pFuncLoad)() = 0; //Resolve the function in MyLibStub.cpp pFuncLoad = (void (*)())dlsym(pLibHandle,pszFuncName); if(!pFuncLoad) { return 1; } pFuncLoad(); dlclose(pLibHandle); return 0; }
并使用以下命令进行编译(在Ubuntu 11.10下):
06006
用./MainStatic调用时
它给出了类似的东西:
06007
然而,当用./MainDynamic调用时
它只给出一个“你好”.
06008
解决方法
此行为是预期的.
为了理解它,首先需要知道动态加载器使用链表按照加载不同ELF图像的顺序搜索符号.在该列表的头部是主要的可执行文件本身,然后是直接链接到它的所有库.当你dlopen()一些库时,它会被附加到列表的尾部.
因此,当您刚加载的库中的代码调用__cyg_profile_func_enter时,加载程序将在列表中搜索该函数的第一个定义.第一个定义恰好是默认值,由libc.so.6提供,它靠近列表的末尾,但在你的dlopen()ed库之前.
你可以通过运行来观察所有这些:
LD_DEBUG=symbols,bindings ./MainDynamic
并在输出中查找__cyg_profile_func_enter.
那么,为了看到你的仪器你需要做什么?你必须在libc.so.6之前的某个地方获得自己的__cyg_profile_func_enter.一种方法是将其链接到您的主要可执行文件.或者将它链接到一个直接链接到您的可执行文件的共享库(即不是dlopen()d).