Linux-та же функция, вызываемая при динамической и статической загрузке

У меня есть проект c++, который компилируется в a .so file (компиляция с использованием g++5).
В другом проекте (под тем же решением) у меня есть тест, который ссылается на этот проект (Команда CMake target_link_libraries (…)).

Я компилирую проект и копирую выходные данные .поэтому файл скажем » / tmp / proj.so».

В дополнение к связыванию теста с проектом, я также использую dlopenдля динамической загрузки » /tmp / proj.so», которая имеет глобальную функциюcreate_foo, создающую новый fooобъект.

Цель, которую я пытаюсь достичь, состоит в том, чтобы провести тест, который сравнивает две версии одного и того же проекта друг с другом, чтобы я знал, что ничего не нарушаю, изменяя материал в проекте.

После открытия с dlopenпомощью I call dlsymto findcreate_foo, а затем вызвать его.
create_foo isчто-то вроде:

extern "C" bool create_foo(foo** instance){
    *instance = new foo();
    return true;
}

Таким образом, в моем тесте у меня есть что-то вроде (Я удалил несвязанный код, как нулевые проверки):

#include <dlfcn.h>
#include "foo.h"

int main()
{
    foo f1;
    void* handle = dlopen("/tmp/proj.so", RTLD_NOW);
    bool(*create_foo_func)(foo**);
    create_foo_func = (bool(*)(foo**))dlsym(handle, "create_foo");

    foo* f2;
    (*create_foo_func)(&f2);

    assert(f1.bar() == 10);
    assert(f2->bar() == 10);
}

Оба утверждения в порядке.
Поэтому следующее , что я сделал, было изменение foo::barна return 5Вместо 10того, скомпилировал проект, но я не изменил /tmp/proj.Итак файл!
И когда я запустил программу, я получил:

f1.bar() == 5
f2->bar() == 5 //I would expect this to be 10 since I did not change it

Так что я получаю 5в обоих звонках, в отличие от того, что я надеялся, что это f1.bar()==5и f2->bar() == 10.

Я знаю точно, что библиотека DLL загружается и create_foo в динамическом так называется (Я вижу это в модуле список отладчика, если я попытаюсь функция dlsym(«NOT_create_foo») она будет выполнена, а также иным образом не.е меняется create_foo название функции на что-то, но не изменяя в /tmp/прогн.так).

Когда я добавил printf («static linkage») в код, скомпилировал его и оставил /tmp/proj.так » файл без изменений (то есть у него нет этого printf) я вижу, что это печатается дважды.

Так что же я здесь делаю не так?

Реальный проект, над которым я работаю, большой и использует CMake. Я, возможно, упустил важные детали, которые я не думал, актуальны, если вы думаете, что я должен смотреть где-то, пожалуйста, комментарий, и я буду редактировать с ответом.

2 ответа

  1. Я боюсь, что вы хотите быть в состоянии достичь того, что вы хотите. Что касается компилятора, объекты имеют тот же тип, поэтому он будет генерировать вызов той же реализации. Во время ссылки будет разрешен foo:: bar, определенный в исполняемом файле.

          $ g++ main.cc -c
          $ objdump -rd
          ...
          44:   e8 00 00 00 00          callq  49 <main+0x49>
          45: R_X86_64_PC32       _ZN3foo3barEv-0x4
          ...
          6e:   e8 00 00 00 00          callq  73 <main+0x73>
          6f: R_X86_64_PC32       _ZN3foo3barEv-0x4
    
  2. На справочной странице dlopen об этом не говорится, но здесь говорится

    Only a single copy of an object file is brought into the address space, even if dlopen() is invoked multiple times in reference to the file, and even if different pathnames are used to reference the file.
    

    и Linux dlopen manpage:

       If the same library is loaded again with dlopen(), the same file handle is returned. 
       The dl library maintains reference counts for library handles, so a dynamic library 
       is not deallocated until dlclose() has been called on it as many times as dlopen() 
       has succeeded on it.
    

    Таким образом, похоже, что dlopen обрабатывает /tmp/proj.soту же библиотеку, что и уже загруженная для самого тестового исполняемого файла. Это можно проверить, сравнив возвращаемые дескрипторы.