减少第三方库的导出符号
Reduce exported symbols of a third party library
我有工作正常的代码,但是如果我 link 我的项目到第三方库 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.so
和 libabc.so
(!!) 导出 png_destroy_write_struct
它实际上导出所有的 libpng API (我假设它是静态的 link 到?)。我假设这是问题所在?我不希望 openCV see 任何 libabc.so
导出...我该怎么做?
我尝试使用 objcopy --prefix-symbols abc_ libabc.so
但不知何故它没有帮助,现在崩溃发生在 abc_png_destroy_write_struct
。
I assume this is the problem?
是:很有可能:libabc.so
已静态链接(可能是不同版本的)libpng
,并引入了符号冲突。
I do no want openCV to see whatever libabc.so exports... How can I do this?
你不能。您必须联系 libabc.so
开发人员,并告诉他们 隐藏 libpng
符号。
唯一的其他选项(对于单进程执行)是动态加载 libabc.so
。
这可以通过 dlopen("liabc.so.", RTLD_LOCAL)
完成,即使那样也可能不起作用(具体取决于 libabc.so
的链接方式)——它可能会导致 libabc.so
绑定到您的版本libpng
,然后崩溃。
在 Linux 上,您还可以使用 dlmopen(LM_ID_NEWLM, "libabc.so", ...)
,它将 完全 将 libabc.so
与您的代码的其余部分隔离开来,并且 可能 如果 libabc.so
被链接以包含其所有依赖项(或者您可以将它们明确地引入新的加载程序命名空间)。
最后,正如 Eljay 在这里评论的那样,您可以使用进程间通信并拥有完全独立的进程负载 libabc.so
。这将比直接使用 libabc.so
性能差很多,但总比没有好。
我会尝试 strip
。详情见此:https://linux.die.net/man/1/strip
添加到 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
我有工作正常的代码,但是如果我 link 我的项目到第三方库 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.so
和 libabc.so
(!!) 导出 png_destroy_write_struct
它实际上导出所有的 libpng API (我假设它是静态的 link 到?)。我假设这是问题所在?我不希望 openCV see 任何 libabc.so
导出...我该怎么做?
我尝试使用 objcopy --prefix-symbols abc_ libabc.so
但不知何故它没有帮助,现在崩溃发生在 abc_png_destroy_write_struct
。
I assume this is the problem?
是:很有可能:libabc.so
已静态链接(可能是不同版本的)libpng
,并引入了符号冲突。
I do no want openCV to see whatever libabc.so exports... How can I do this?
你不能。您必须联系 libabc.so
开发人员,并告诉他们 隐藏 libpng
符号。
唯一的其他选项(对于单进程执行)是动态加载 libabc.so
。
这可以通过 dlopen("liabc.so.", RTLD_LOCAL)
完成,即使那样也可能不起作用(具体取决于 libabc.so
的链接方式)——它可能会导致 libabc.so
绑定到您的版本libpng
,然后崩溃。
在 Linux 上,您还可以使用 dlmopen(LM_ID_NEWLM, "libabc.so", ...)
,它将 完全 将 libabc.so
与您的代码的其余部分隔离开来,并且 可能 如果 libabc.so
被链接以包含其所有依赖项(或者您可以将它们明确地引入新的加载程序命名空间)。
最后,正如 Eljay 在这里评论的那样,您可以使用进程间通信并拥有完全独立的进程负载 libabc.so
。这将比直接使用 libabc.so
性能差很多,但总比没有好。
我会尝试 strip
。详情见此:https://linux.die.net/man/1/strip
添加到 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