gpt4 book ai didi

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

转载 作者:IT王子 更新时间:2023-10-29 00:33:14 28 4
gpt4 key购买 nike

最近我在 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 接口(interface))

#include "MyLib.h"

extern "C" void LoadMyLib ()
{
MyLib().sayHello();
}

跟踪.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);
}

主静态.cpp

#include <iostream>
using namespace std;

extern "C" void LoadMyLib ();

int main()
{
LoadMyLib();
return 0;
}

主动态.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

这里有谁知道为什么静态链接库和动态链接库之间有这样的区别?是否有任何解决方案可以使其即使在动态加载时也能正常工作?提前致谢。

最佳答案

此行为是预期的。

为了理解它,您首先需要知道动态加载器使用链表搜索符号,按照加载不同 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 one)。

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

关于c++ - -finstrument-functions 不适用于动态加载的 g++ 共享对象 (.so),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9863610/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com