Linux - 动态和静态加载时调用相同的函数

时间:2016-11-08 16:03:21

标签: c++ linux cmake shared-libraries dlopen

我有一个c ++项目,它编译成.so文件(使用g ++ 5编译)。 在另一个项目中(在同一个解决方案下),我有一个测试链接到这个项目(CMake的命令target_link_libraries(...))。

我编译项目,并将输出.so文件复制到" /tmp/proj.so"。

除了将测试链接到项目之外,我还使用dlopen动态加载" /tmp/proj.so" ;,它具有创建的全局函数create_foo一个新的foo对象。

我试图实现的目标是进行一项测试,将同一项目的两个版本与另一个项目进行比较,以便我知道我不会通过更改项目中的内容来破坏任何内容。 / p>

使用dlopen打开后,我致电dlsym查找create_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.so文件! 当我运行程序时,我得到了:

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

所以我在两次调用中得到5,而不是我希望的f1.bar()==5f2->bar() == 10

我确定dll正在加载并且动态中的create_foo被调用(我可以在调试器的模块列表中看到它,如果我尝试dlsym(&#34; NOT_create_foo&#34;)它会失败,另一种方式也会失败,即将create_foo函数名更改为某些内容但不更改/tmp/proj.so./。

当我在代码中添加了printf(&#34;静态链接&#34;)时,编译它并离开/tmp/proj.so"文件不变(意味着它没有这个printf)我看到这是打印两次。

那我在这里做错了什么?

我正在研究的真实项目很大,正在使用CMake。我可能遗漏了一些我认为不相关的重要细节,如果你认为我应该看看某处,请发表评论,我会编辑答案。

2 个答案:

答案 0 :(得分:0)

我害怕你想要达到你想要的效果。就编译器而言,对象具有相同的类型,因此它将生成对相同实现的调用。在链接时,将解析在可执行文件中定义的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

答案 1 :(得分:0)

dlopen手册页没有这么说,但是here,它说

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联机帮助页:

   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视为与已为测试可执行文件本身加载的库相同的库。您应该能够通过比较返回的句柄来测试它。