- 主. 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 类是一项复杂的工作)。
1条答案
按热度按时间2exbekwf1#
我手边没有
g++-4.8
,但是如果您使用g++-4.8
和g++-11
编译下面的代码,然后运行nm foo.o | grep Function
,您将得到 different mangled name。使用
g++-11
可以得到:如果两个编译器之间的函数名不同,那么这个函数就不兼容ABI,并且您不能执行您想要的操作。
通过将函数标记为
extern "C"
,编译器隐藏了这种ABI不兼容性,但是如果您对编译器撒谎(迟早),它会发现您。(If函数名是相同的,GCC开发人员犯了一个错误。)
类的 Package 是一个复杂的工作)在插件接口
太糟糕了,如果需求是针对不同的编译器(
gcc-4.x
和gcc-11.x
* 在所有实际用途上都是 * 不同的编译器),那么就没有捷径了--您 * 必须 * 确保ABI兼容性,而实现这一点的唯一可靠方法是只通过接口传输C
struct
。