当前位置: 首页 > 面试题库 >

剥离linux共享库

屠泰平
2023-03-14
问题内容

最近,我们被要求提供其中一个库的Linux版本,之前我们是在Linux下开发的,并已针对Windows发行,而在Windows上部署库通常要容易得多。我们遇到的问题是将导出的符号剥离为仅暴露界面中的符号。想要这样做的三个很好的理由

  • 为了保护我们技术的专有方面,以免通过导出的符号被暴露。
  • 防止用户遇到符号名称冲突的问题。
  • 为了加快库的加载速度(至少有人告诉我)。

然后举一个简单的例子:

测试文件

#include <cmath>

float private_function(float f)
{
    return std::abs(f);
}

extern "C" float public_function(float f)
{
    return private_function(f);
}

用(g ++ 4.3.2,ld 2.18.93.20081009)编译

g++ -shared -o libtest.so test.cpp -s

并检查符号

nm -DC libtest.so

         w _Jv_RegisterClasses
0000047c T private_function(float)
000004ba W std::abs(float)
0000200c A __bss_start
         w __cxa_finalize
         w __gmon_start__
0000200c A _edata
00002014 A _end
00000508 T _fini
00000358 T _init
0000049b T public_function

显然不足。因此,接下来我们将公共功能声明为

extern "C" float __attribute__ ((visibility ("default"))) 
    public_function(float f)

并与

g++ -shared -o libtest.so test.cpp -s -fvisibility=hidden

这使

         w _Jv_RegisterClasses
0000047a W std::abs(float)
0000200c A __bss_start
         w __cxa_finalize
         w __gmon_start__
0000200c A _edata
00002014 A _end
000004c8 T _fini
00000320 T _init
0000045b T public_function

很好,除了std :: abs被暴露。更大的问题是,当我们开始链接控件之外的其他(静态)库时, 从这些库中使用的所有符号都会被导出
。另外,当我们开始使用STL容器时:

#include <vector>
struct private_struct
{
    float f;
};

void other_private_function()
{
    std::vector<private_struct> v;
}

我们最终从C ++库中获得了许多其他导出

00000b30 W __gnu_cxx::new_allocator<private_struct>::deallocate(private_struct*, unsigned int)
00000abe W __gnu_cxx::new_allocator<private_struct>::new_allocator()
00000a90 W __gnu_cxx::new_allocator<private_struct>::~new_allocator()
00000ac4 W std::allocator<private_struct>::allocator()
00000a96 W std::allocator<private_struct>::~allocator()
00000ad8 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_Vector_impl::_Vector_impl()
00000aaa W std::_Vector_base<private_struct, std::allocator<private_struct> >::_Vector_impl::~_Vector_impl()
00000b44 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_M_deallocate(private_struct*, unsigned int)
00000a68 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_M_get_Tp_allocator()
00000b08 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_Vector_base()
00000b6e W std::_Vector_base<private_struct, std::allocator<private_struct> >::~_Vector_base()
00000b1c W std::vector<private_struct, std::allocator<private_struct> >::vector()
00000bb2 W std::vector<private_struct, std::allocator<private_struct> >::~vector()

注意:启用优化后,您需要确保向量已实际使用,因此编译器不会将未使用的符号进行优化。

我相信我的同事已经设法构建了一个临时解决方案,该方案涉及版本文件并修改了似乎有效的STL标头(!),但我想问一下:

有没有一种干净的方法可以从Linux共享库中剥离所有不必要的符号(即那些不是公开库功能的一部分的符号)? 我已经为g
++和ld尝试了很多选项,但收效甚微,因此,我宁愿选择已知有效的答案,而不是相信的答案。

特别是:

  • 不导出(封闭源)静态库中的符号。
  • 标准库中的符号不​​会导出。
  • 目标文件中的非公共符号不会导出。

我们的导出接口是C。


问题答案:

因此,我们目前的解决方案如下:

测试文件

#include <cmath>
#include <vector>
#include <typeinfo>

struct private_struct
{
    float f;
};

float private_function(float f)
{
    return std::abs(f);
}

void other_private_function()
{
    std::vector<private_struct> f(1);
}

extern "C" void __attribute__ ((visibility ("default"))) public_function2()
{
    other_private_function();
}

extern "C" float __attribute__ ((visibility ("default"))) public_function1(float f)
{
    return private_function(f);
}

出口版本

LIBTEST 
{
global:
    public*;
local:
    *;
};

用编译

g++ -shared test.cpp -o libtest.so -fvisibility=hidden -fvisibility-inlines-hidden -s -Wl,--version-script=exports.version

00000000 A LIBTEST
         w _Jv_RegisterClasses
         U _Unwind_Resume
         U std::__throw_bad_alloc()
         U operator delete(void*)
         U operator new(unsigned int)
         w __cxa_finalize
         w __gmon_start__
         U __gxx_personality_v0
000005db T public_function1
00000676 T public_function2

这与我们正在寻找的相当接近。但是有一些陷阱:

  • 我们必须确保在内部代码中不使用“ exported”前缀(在这个简单示例中为“ public”,但显然在我们的情况下更有用)。
  • 许多符号名称仍最终出现在字符串表中,该字符串表似乎取决于RTTI,-fno-rtti在我的简单测试中使它们消失了,但这是一个相当核心的解决方案。

我很高兴接受任何人提出的更好的解决方案!



 类似资料:
  • 问题内容: 两个共享库liba.so和libb.so。liba.so使用libb.so。所有c文件都使用-fPIC编译。链接使用- shared。当我们在liba.so上调用dlopen时,它无法在libb.so中找到符号…我们得到“未定义符号”错误。我们可以dlopen libb.so没有错误。我们知道liba正在找到libb,因为我们没有得到文件未找到错误。删除libb.so时,出现文件未找到

  • 问题内容: 寻找匹配和替换的正则表达式序列(最好是PHP,但没关系)以更改此规则(开始和结束只是需要保留的随机文本)。 在: 到这个OUT: 谢谢。 问题答案: 您是否只是想删除评论?怎么样 或稍好一点(由发问者本人建议): 但是请记住,HTML 不是 正规的,因此当有人向其抛出奇怪的边缘情况时,使用正则表达式进行解析将使您陷入痛苦的世界。

  • 问题内容: 我正在尝试建立一个共享库。让我们说libabc.so。它使用另一个.so文件,例如lib123.so(/ usr / local / lib中的一个lib)。现在我在我的应用程序中使用共享的liblibabc.so。说我的应用程序。我想知道我应该如何链接这些二进制文件?我不想直接将我的应用程序与lib123.so链接。my- app应该仅与libabc.so链接。我怎样才能做到这一点?

  • 问题内容: 这是使用g ++ 进行动态共享库编译的后续版本。 我正在尝试在Linux上的C++中创建一个共享的类库。当我尝试使用库中定义的类时,我的问题开始了。我链接到的第二篇教程展示了如何加载用于创建库中定义的类的对象的符号,但是没有_使用_ 这些对象来完成任何工作。 有谁知道用于创建共享C ++类库的更完整的教程,该教程还显示了如何在单独的可执行文件中 使用 这些类?一个非常简单的教程,显示了

  • 问题内容: 我写了一个共享对象,然后说说了,把它的头文件放进了。 这是另一个使用,比如说的程序,然后像这样编译它: 然后我像这样运行: 所以我设置了,然后就可以了。但是,如果我,并把我的话,再次它没有工作,为什么? 与放入有什么区别? 问题答案: 如果没有导出,则声明的LD_LIBRARY_PATH仅在脚本(.bashrc)中有效。通过导出,它应该可以工作,但是像这样设置LD_LIBRARY_PA

  • 问题内容: 我在PowerPoint演示文稿中有一些链接,由于某种原因,当单击这些链接时,它将向URL添加一个返回参数。好吧,该返回参数导致我的Joomla网站的MVC模式变得混乱。 那么,什么是使用PHP删除此返回参数的有效方法呢? 示例:http: //mydomain.com/index.php?id = 115&Itemid = 283&return = aHR0cDovL2NvbW11b