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

前端之家收集整理的这篇文章主要介绍了c – -finstrument-functions不适用于动态加载的g共享对象(.so)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这些天我在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).

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

原文链接:https://www.f2er.com/c/118958.html

猜你在找的C&C++相关文章