2012-03-25 16 views
6

我在Ubuntu這些天測試-finstrument函數使用g ++共享對象(的.so)文件。我發現了一個奇怪的行爲,即只有在靜態鏈接庫時,函數似乎才起作用。如果我鏈接到使用dlopen/dlsym進行等庫,代碼的功能仍然有效,但它不會調用__cyg_profile *功能。-finstrument函數不與動態加載克++共享對象工作(。所以)

這裏有一些碼來快速重現該問題:

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(C接口連接到的.so)

#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下):

g++ -g -finstrument-functions -Wall -Wl,-soname,libMyLib.so.0 -shared -fPIC -rdynamic MyLib.cpp MyLibStub.cpp Trace.cpp -o libMyLib.so.0.0 
ln -s libMyLib.so.0.0 libMyLib.so.0 
ln -s libMyLib.so.0.0 libMyLib.so 
g++ MainStatic.cpp -g -Wall -lMyLib -L./ -o MainStatic 
g++ MainDynamic.cpp -g -Wall -ldl -o MainDynamic 

./MainStatic

稱爲它給像:

entering 0xb777693f 
entering 0xb777689b 
exiting 0xb777689b 
exiting 0xb777693f 
entering 0xb7776998 
entering 0xb777680c 
Hello 
exiting 0xb777680c 
exiting 0xb7776998 

然而,當與./MainDynamic

稱它只是提供了一個 「你好」。

Hello 

這裏沒有任何人知道爲什麼有靜態和動態鏈接庫之間的這種差異?即使動態加載,是否有任何解決方案可以使其工作?提前致謝。

+0

你對這個有什麼建議嗎:http://stackoverflow.com/questions/36910918/how-to-compile-a-cpp-and-then-link-it-to-a-shared-library – cross 2016-04-28 10:55:32

回答

4

這是正常現象。

爲了理解它,首先需要知道動態加載器使用鏈接列表搜索符號,順序是加載了不同的ELF圖像。該列表的頭部是主要的可執行文件本身,隨後是直接鏈接到它的所有庫。當你dlopen()一些圖書館,它被添加到列表中的

所以,當你剛裝電話__cyg_profile_func_enter在庫中的代碼,加載程序搜索列表中該函數的第一個定義。第一個定義恰好是由libc.so提供的默認定義。6,它接近列表的末尾,但是之前您的dlopen()編輯庫。

您可以通過運行觀察了這一切:

LD_DEBUG=symbols,bindings ./MainDynamic 

,並尋找在輸出__cyg_profile_func_enter

那麼,爲了看到您的儀器,您需要做些什麼?你得到你自己的__cyg_profile_func_enter某處之前libc.so.6之一。一種方法是將其鏈接到主要的可執行文件中。或將其鏈接到共享庫,即直接鏈接到您的可執行文件(即而不是dlopen() d一個)。

一旦你這樣做了,你的實現將是列表中的第一個,它將勝過libc.so.6中的第一個,你會看到它產生的輸出。

+0

任何解決方案爲此:http://stackoverflow.com/questions/36910918/how-to-compile-a-cpp-and-then-link-it-to-a-shared-library和這個:http:// stackoverflow .COM /問題/ 36896140 /時間,跟蹤的功能通話功能於C-使用-etrace – cross 2016-04-28 10:56:03