c – -finstrument-functions不适用于动态加载的g共享对象(.so)

c – -finstrument-functions不适用于动态加载的g共享对象(.so),第1张

概述这些天我在Ubuntu上用g共享对象(.so)文件测试-finstrument-functions.我发现了一个奇怪的行为 – 只有在静态链接库时,-finstrument-functions似乎才有效.如果我用dlopen / dlsym等链接到库,代码的功能仍然有效,但它不会调用__cyg_profile *函数. 以下是一些快速重现问题的代码: MyLib.h #ifndef __MYLIB 这些天我在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 __cplusplusextern "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));}#endifvoID __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).

一旦你这样做,你的实现将是列表中的第一个,它将胜过libc.so.6中的那个,你将看到它生成的输出.

总结

以上是内存溢出为你收集整理的c – -finstrument-functions不适用于动态加载的g共享对象(.so)全部内容,希望文章能够帮你解决c – -finstrument-functions不适用于动态加载的g共享对象(.so)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1240728.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存