减少导出的第三方库符号

时间:2019-11-24 20:05:30

标签: c++ opencv shared-libraries dynamic-linking dynamic-loading

我的代码可以正常工作,但是如果我将项目链接到第三方库libabc.so(源不可用),那么突然我会遇到分段错误。

我的主电源看起来像这样

#include <opencv2/imgcodecs.hpp>
#include "Abc.h"

int main(int argc, char **argv)
{
    Abc dummyAbc;
    auto img = cv::imread("dummy.png");
    cv::imwrite("123.png", img);
    return 0;
}

CMakeList.txt如下

cmake_minimum_required(VERSION 3.1)
set(CMAKE_C_STANDARD 11)
find_package(OpenCV COMPONENTS core highgui imgcodecs)
include_directories(${OpenCV_INCLUDE_DIR})

add_executable(my_project Main.cpp)
target_link_libraries(my_project ${OpenCV_LIBRARIES} abc)

这可以很好地编译,但是在运行时会出现段错误。如果我删除了行

Abc dummyAbc;

然后一切正常(也就是说,丢失文件或opencv不会有问题)。

如果我检查段错误的堆栈,则会看到:

Thread 1 "my_project" received signal SIGSEGV, Segmentation fault.
0x00007fdea96836b3 in png_destroy_write_struct () from /usr/local/lib/libabc.so

png_destroy_write_struct正在调用cv::imwrite

libpng.solibabc.so(!!)都导出png_destroy_write_struct,实际上导出了所有libpng API(我假设它是静态链接到的)。我假设是问题所在?我不想让openCV 看到 libabc.so的任何输出...我该怎么做?

我尝试使用objcopy --prefix-symbols abc_ libabc.so,但由于某种原因它没有帮助,现在崩溃发生在abc_png_destroy_write_struct

3 个答案:

答案 0 :(得分:3)

  

我认为这是问题所在吗?

是:很有可能:libabc.so静态链接了libpng(可能是其不同版本),并引入了符号冲突。

  

我不希望openCV看到任何libabc.so导出...我该怎么做?

不能。您必须联系libabc.so开发人员,并告诉他们隐藏 libpng符号。

唯一的其他选择(用于单进程执行)是动态加载libabc.so

这可以通过dlopen("liabc.so.", RTLD_LOCAL)完成,甚至可能无法正常工作(具体取决于libabc.so的链接方式),这可能会导致libabc.so绑定到您的{ {1}},然后崩溃。

在Linux上,您还可以使用libpng,它将与其他代码完全隔离dlmopen(LM_ID_NEWLM, "libabc.so", ...),并且可以 libabc.so被链接为包括其所有依赖项(或者您可以将它们显式引入新的加载器命名空间中。)

最后,正如Eljay在这里评论的那样,您可以使用进程间通信,并且具有完全独立的进程负载libabc.so。与直接使用libabc.so相比,这样做的性能会差很多,但总比没有好。

答案 1 :(得分:1)

要添加到EmployedRussian的答案中,即使用基于dlmopen的方法将libabc.so与其余代码隔离:在这种情况下,避免与dlsym和函数指针混淆,您可以自动生成包装器通过Implib.so获取所需的库函数:

$ cat mysymbols.txt
foo
bar
$ cat mycallback.c
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C"
#endif

// Dlopen callback that loads library to dedicated namespace
void *mycallback() {
  void *h = dlmopen(LM_ID_NEWLM, "libabc.so", RTLD_LAZY | RTLD_DEEPBIND);
  if (h)
    return h;
  fprintf(stderr, "dlmopen failed: %s\n", dlerror());
  exit(1);
}

$ implib-gen.py --dlopen-callback=mycallback --symbol-list=mysymbols.txt libabc.so
$ ... # Link your app with libabc.tramp.S, libabc.init.c and mycallback.c

答案 2 :(得分:-1)

我会尝试strip。详情请参见:https://linux.die.net/man/1/strip