gcc STL类在接口上的转换对象,通过dlopen动态加载

dxxyhpgq  于 2023-01-17  发布在  其他
关注(0)|答案(1)|浏览(125)
    • 主. cpp**
#include "string"
#include "unordered_map"
#include "iostream"

#include "dlfcn.h"

typedef void x(std::unordered_map<std::string, std::string> &);

int main(int argc, char **argv)
{
    auto handle = dlopen("./test3.so", RTLD_NOW);

    if(!handle)
    {
        std::cout << dlerror() << std::endl;
        return -1;
    }

    x *x;
    *(void **)&x = dlsym(handle, "x");

    // std::unordered_map<std::string, std::string> result{{"y", "Hello, cpp"}}; //ok
    std::unordered_map<std::string, std::string> result;    //failed if not dynamic link test3.so

    x(result);
    std::cout << result["x"] << std::endl;

    dlclose(handle);
    return 0;
}
    • 测试3.cpp**
#include "unordered_map"
#include "string"
#ifdef __cplusplus
extern "C"
{
#endif
    void x(std::unordered_map<std::string, std::string> &result)
    {
        result["x"] = "Hello, world";
    }
#ifdef __cplusplus
}
#endif

如果main.cpp使用gcc-11构建,而test3.cpp使用gcc-4.8构建,则程序将崩溃。
一个二个一个一个
如果main.cpp在链接表中包含www.example.com,则程序将正常运行。test3.so in linking list, the program would run normaly.

g++ -g -fpic -shared test3.cpp -o test3.so  //g++ version is 4.8
g++ -g main.cpp -Wl,-rpath,'$ORIGIN' -ldl test3.so    //g++ version is 11
[zrar@CentOS7 cpp]$ ./a.out 
Hello, world
[zrar@CentOS7 cpp]$ ldd ./a.out 
        linux-vdso.so.1 (0x00007ffea6bb9000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007fd670b7f000)
        test3.so => /home/zrar/Documents/cpp/test3.so (0x00007fd670975000)
        libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fd67066d000)
        libm.so.6 => /lib64/libm.so.6 (0x00007fd67036b000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fd670155000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fd66fda9000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fd670d83000)
[zrar@CentOS7 cpp]$ ldd test3.so
        linux-vdso.so.1 (0x00007ffc91596000)
        libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fc484378000)
        libm.so.6 => /lib64/libm.so.6 (0x00007fc484076000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fc483e60000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fc483ab4000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fc48488a000)

在我的需求中,我想在插件接口中动态加载一个插件(可能是用其他版本的gcc构建的)和直接转换STL对象(主机和插件都是用cpp编写的,用c风格 Package 类是一项复杂的工作)。

2exbekwf

2exbekwf1#

我手边没有g++-4.8,但是如果您使用g++-4.8g++-11编译下面的代码,然后运行nm foo.o | grep Function,您将得到 different mangled name。

#include <unordered_map>
#include <string>
void Function(std::unordered_map<std::string, std::string>& result) {}

使用g++-11可以得到:

0000000000000000 T _Z8FunctionRSt13unordered_mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4hashIS5_ESt8equal_toIS5_ESaISt4pairIKS5_S5_EEE

如果两个编译器之间的函数名不同,那么这个函数就不兼容ABI,并且您不能执行您想要的操作。
通过将函数标记为extern "C",编译器隐藏了这种ABI不兼容性,但是如果您对编译器撒谎(迟早),它会发现您。
(If函数名是相同的,GCC开发人员犯了一个错误。)
类的 Package 是一个复杂的工作)在插件接口
太糟糕了,如果需求是针对不同的编译器(gcc-4.xgcc-11.x * 在所有实际用途上都是 * 不同的编译器),那么就没有捷径了--您 * 必须 * 确保ABI兼容性,而实现这一点的唯一可靠方法是只通过接口传输Cstruct

相关问题