-finstrument-functions не работает с динамически загружаемыми общими объектами g ++ (.so) - PullRequest
7 голосов
/ 26 марта 2012

Я сейчас тестирую -finstrument-функции с файлами общего объекта g. (.So) в Ubuntu. Я обнаружил странное поведение, что -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 (интерфейс 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".

Hello

Кто-нибудь здесь знает, почему существует такая разница между статически и динамически связанными библиотеками? Есть ли решение, чтобы оно работало даже при динамической загрузке? Заранее спасибо.

Ответы [ 2 ]

5 голосов
/ 27 марта 2012

Такое поведение ожидается.

Чтобы понять это, вам сначала нужно знать, что динамический загрузчик ищет символы, используя связанный список, в порядке загрузки различных ELF изображений. Во главе этого списка находится основной исполняемый файл, за которым следуют все библиотеки, непосредственно связанные с ним. Когда вы dlopen() используете какую-либо библиотеку, она добавляется к хвосту списка.

Поэтому, когда код в библиотеке, которую вы только что загрузили, вызывает __cyg_profile_func_enter, загрузчик ищет в списке первое определение этой функции. Это первое определение является определением по умолчанию, предоставленным libc.so.6, которое находится в конце списка, но до вашей dlopen() ed библиотеки.

Вы можете наблюдать все это, запустив:

LD_DEBUG=symbols,bindings ./MainDynamic

и ищет __cyg_profile_func_enter в выводе.

Итак, что вы должны сделать, чтобы увидеть свои приборы? У вас есть , чтобы получить свои __cyg_profile_func_enter где-то до тот из libc.so.6. Один из способов сделать это - связать его с основным исполняемым файлом. Или свяжите его с общей библиотекой, которая напрямую связана с вашим исполняемым файлом (т.е. не dlopen() d one).

Как только вы это сделаете, ваша реализация будет первой в списке, и она превзойдет ту, что в libc.so.6, и вы увидите результат, который она генерирует.

0 голосов
/ 26 декабря 2018

Вы можете

dlopen(pszLibName, RTLD_NOW | RTLD_DEEPBIND);

Тогда символы, определенные в библиотеке, будут предпочтительнее глобальных символов

...