Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在动态库中隐藏符号而不修改源代码_C++_Symbols_Dynamic Library - Fatal编程技术网

C++ 在动态库中隐藏符号而不修改源代码

C++ 在动态库中隐藏符号而不修改源代码,c++,symbols,dynamic-library,C++,Symbols,Dynamic Library,我有一个封闭源代码的第三方共享库,我需要链接。不幸的是,第三方库的创建者没有限制导出哪些符号以及导出所有符号。第三方库在内部使用了我在代码中使用的流行库的不兼容版本,但导出了冲突符号(google的protobuf库)。当protobuffer库版本检查发现库的编译时版本和运行时版本不兼容时,这会导致运行时错误。我可以通过恢复到与第三方库中使用的版本相匹配的protobufs 2.3的旧版本来解决此问题。但是,protbuf 2.3存在性能问题,使其对我的应用程序不可用。我需要一种在代码中使用P

我有一个封闭源代码的第三方共享库,我需要链接。不幸的是,第三方库的创建者没有限制导出哪些符号以及导出所有符号。第三方库在内部使用了我在代码中使用的流行库的不兼容版本,但导出了冲突符号(google的protobuf库)。当protobuffer库版本检查发现库的编译时版本和运行时版本不兼容时,这会导致运行时错误。我可以通过恢复到与第三方库中使用的版本相匹配的protobufs 2.3的旧版本来解决此问题。但是,protbuf 2.3存在性能问题,使其对我的应用程序不可用。我需要一种在代码中使用Protobuf2.4的方法,并让第三方库使用它自己的内部v2.3

是否有一种方法可以生成新版本的第三方库,该库不从protobuf v 2.3库中导出符号,该库仅在给定so文件的情况下内部使用?如果我有消息来源,这将是一个更容易的问题。似乎像objcopy和strip这样的工具实际上无法修改动态符号表。到目前为止,我唯一的想法是创建我自己的垫片库,通过将调用重定向到第三方库(可能是用dlopen打开的?)只导出我需要的符号


有更好的解决方案吗?

更改传递给链接器的库的顺序可能会有所帮助。如果多个库输出相同的符号,则链接器应使用第一个库中的符号。但是,并不是所有的链接器都是这样的,所以请查看一下它的文档。

我找到了一个有效的解决方案。。。我创建了一个垫片库,它将调用重定向到第三方库,允许库外的代码看到protbuf v2.4符号,而第三方库内的代码看到protbuf v2.3符号。此解决方案基于此处发布的想法:

我不得不修改dlopen标志以包括RTLD|u LAZY | RTLD|u LOCAL | RTLD|u DEEPBIND。RTLD_LOCAL标志可防止第三方库中的符号在垫片库外被看到(防止符号泄漏)。RTLD_DEEPBIND强制从第三方库内部调用,以仅查看符号的内部版本(防止符号泄漏)

具体来说,这里是我的shim库的一个示例摘录

#include <stdio.h>
#include <stdint.h>
#include <dlfcn.h>
#include "libhdfs/hdfs.h"

//#define PRINT_DEBUG_STUFF

// Helper function to retrieve a function pointer to a function from libMapRClient
// while isolating the symbols used internally from those already linked externaly
// to workaround symbol collision problem with the current version of libMapRClient.
void* GetFunc(const char* name){
  #ifdef PRINT_DEBUG_STUFF
    printf("redirecting %s\n", name);
  #endif
  void *handle;
  char *error;

  handle = dlopen("/opt/mapr/lib/libMapRClient.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);

  if (!handle) {
    fputs(dlerror(), stderr);
    exit(1);
  }
  void* fp = dlsym(handle, name);
  if ((error = dlerror()) != 0) {
    fprintf(stderr, "%s\n", error);
    exit(1);
  }
  return fp;
}


hdfsFS hdfsConnect(const char* host, tPort port) {
  typedef hdfsFS (*FP) (const char* host, tPort port);
  static FP ext = 0;
  if (!ext) {
    ext = (FP)GetFunc("hdfsConnect");
  }
  return ext(host, port);
}


int hdfsCloseFile(hdfsFS fs, hdfsFile file) {
  typedef int (*FP) (hdfsFS fs, hdfsFile file);
  static FP ext = 0;
  if (!ext) {
    ext = (FP)GetFunc("hdfsCloseFile");
  }
  return ext(fs, file);
}
#包括
#包括
#包括
#包括“libhdfs/hdfs.h”
//#定义打印调试内容
//Helper函数,用于从libMapRClient检索指向函数的函数指针
//将内部使用的符号与外部已链接的符号隔离开来
//解决当前版本libMapRClient的符号冲突问题。
void*GetFunc(常量字符*名称){
#ifdef打印调试内容
printf(“重定向%s\n”,名称);
#恩迪夫
无效*手柄;
字符*错误;
handle=dlopen(“/opt/mapr/lib/libMapRClient.so”,RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
如果(!句柄){
fputs(dlerror(),stderr);
出口(1);
}
void*fp=dlsym(句柄、名称);
如果((error=dlerror())!=0){
fprintf(stderr,“%s\n”,错误);
出口(1);
}
返回fp;
}
hdfsFS hdfsConnect(常量字符*主机,tPort端口){
typedef hdfsFS(*FP)(常量字符*主机,tPort端口);
静态FP ext=0;
如果(!ext){
ext=(FP)GetFunc(“hdfsConnect”);
}
返回ext(主机、端口);
}
int hdfsCloseFile(hdfsFS,hdfsFile文件){
typedef int(*FP)(hdfsFS,hdfsFile文件);
静态FP ext=0;
如果(!ext){
ext=(FP)GetFunc(“hdfsCloseFile”);
}
返回ext(fs,文件);
}

。。。等其他公共API函数

感谢您的想法。。。我尝试过这个,但效果不太好,因为它强制所有呼叫站点使用相同版本的符号(从版本2.3或2.4)。但是,我需要在第三方库中调用该符号的v2.3,并在我的代码中调用该符号的v2.4。否则,库将检测不匹配的版本并中止。只有当“我的代码”加载库或第三方代码加载库时发生中止时,才能切换库链接顺序。因此,您需要一种部分链接。在第一阶段,将您的代码链接到v2.4,并将第三方库的代码独立链接到v2.3,在第二阶段,将结果链接到一起。也许有一些链接器选项允许第一阶段的不完整链接?你使用哪种操作系统?Linux(fedora,ubuntu)。。。我对价格合理的科学/分布式计算的偏好…;-)垫片是否基本上只是对主应用程序隐藏了dlopen/dlsym的缺点?这似乎没有必要。