【问题标题】:Reduce exported symbols of a third party library减少第三方库的导出符号
【发布时间】:2019-11-24 20:05:30
【问题描述】:

我的代码可以正常工作,但如果我将我的项目链接到第三方库 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_structcv::imwrite 调用。

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

我尝试使用objcopy --prefix-symbols abc_ libabc.so,但不知何故没有帮助,现在崩溃发生在abc_png_destroy_write_struct

【问题讨论】:

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


    【解决方案1】:

    我认为这是问题所在?

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

    我不想让 openCV 看到 libabc.so 导出的任何内容...我该怎么做?

    你不能。您必须联系 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 性能差很多,但总比没有好。

    【讨论】:

    • 感谢您的回答。是否有可能以某种方式围绕libabc.so 创建我的包装器,以便我手动隐藏/公开一些方法(例如,只有“abc.h”中的方法)并链接到这个新包装器?
    • @AlWld “有可能……”。没有。
    • 这是可能的,但它涉及在进程外运行它并使用进程间通信。
    • 为什么不提other answer中提到的手动修改.dynsym
    • @yugr 另一个答案 (stackoverflow.com/questions/36273404/…) 仅在您可以重新链接 .so 时适用。修改.so本身很可能导致哈希表不一致,导致ld-linux崩溃。
    【解决方案2】:

    要添加到 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
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • strip 对动态符号表什么都不做
      猜你喜欢
      • 1970-01-01
      • 2020-02-16
      • 1970-01-01
      • 1970-01-01
      • 2019-10-28
      • 1970-01-01
      • 2012-10-01
      • 2016-11-11
      • 1970-01-01
      相关资源
      最近更新 更多