剥离linux共享库 [英] Stripping linux shared libraries

查看:237
本文介绍了剥离linux共享库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们最近被要求提供一个Linux版本的我们的库之一,以前我们在Linux下开发,并且为Windows部署,部署库通常更容易。我们遇到的问题是将导出的符号剥离到暴露的接口中的那些。




  • 通过导出的符号保护我们的技术的专利方面。

  • 防止用户遇到冲突的符号名称有问题。

  • 加快图书馆的加载速度(至少我被告知)。



以一个简单的例子:



test.cpp

  #include< cmath> 

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

externCfloat 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

显然不足。接下来我们重新声明公共函数为

  externCfloat __attribute__(visibility(default)))
public_function(float f)

并使用

编译
$ b b

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

它提供

  w _Jv_RegisterClasses 
0000047a W std :: abs
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()

注意:优化后,您需要确保向量实际上是使用的,所以编译器不优化未使用的符号。



我相信我的同事已经设法构建一个ad-hoc解决方案涉及版本文件和修改STL头(!)似乎工作,但我想问:



有一个干净的方式来剥离所有不必要的符号不是暴露的库功能的一部分)从linux共享库?我尝试了很多选项,g ++和ld与一点成功,所以我更喜欢的答案,已知的工作,而不是相信



特别是:





  • 未导出来自标准库的符号。

  • 不导出来自对象文件的非公共符号。 >


我们的导出界面是C。



我知道其他类似的问题on SO:





,但是答案很少。



test.cpp

  #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);
}

externCvoid __attribute__((visibility(default)))public_function2()
{
other_private_function
}

externCfloat __attribute__((visibility(default)))public_function1(float f)
{
return private_function
}

exports.version

  LIBTEST 
{
全球:
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操作符delete(void *)
U运算符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



我很乐意接受任何更好的解决方案与!


We've recently been asked to ship a Linux version of one of our libraries, previously we've developed under Linux and shipped for Windows where deploying libraries is generally a lot easier. The problem we've hit upon is in stripping the exported symbols down to only those in the exposed interface. There are three good reasons for wanting to do this

  • To protect the proprietary aspects of our technology from exposure through the exported symbols.
  • To prevent users having problems with conflicting symbol names.
  • To speed up the loading of the library (at least so I'm told).

Taking a simple example then:

test.cpp

#include <cmath>

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

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

compiled with (g++ 4.3.2, ld 2.18.93.20081009)

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

and inspecting the symbols with

nm -DC libtest.so

gives

         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

obviously inadequate. So next we redeclare the public function as

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

and compile with

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

which gives

         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

which is good, except that std::abs is exposed. More problematic is when we start linking in other (static) libraries outside of our control, all of the symbols we use from those libraries get exported. In addition, when we start using STL containers:

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

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

we end up with many additional exports from the C++ library

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()

NB: With optimisations on you'll need to make sure the vector is actually used so the compiler doesn't optimise the unused symbols out.

I believe my colleague has managed to construct an ad-hoc solution involving version files and modifying the STL headers (!) that appears to work, but I would like to ask:

Is there a clean way to strip all unnecessary symbols (IE ones that are not part of the exposed library functionality) from a linux shared library? I've tried quite a lot of options to both g++ and ld with little success so I'd prefer answers that are known to work rather than believed to.

In particular:

  • Symbols from (closed-source) static libraries are not exported.
  • Symbols from the standard library are not exported.
  • Non-public symbols from the object files are not exported.

Our exported interface is C.

I'm aware of the other similar questions on SO:

but have had little success with the answers.

解决方案

So the solution we have for now is as follows:

test.cpp

#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);
}

exports.version

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

compiled with

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

gives

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

Which is fairly close to what we're looking for. There are a few gotchas though:

  • We have to ensure we don't use the "exported" prefix (in this simple example "public", but obviously something more useful in our case) in the internal code.
  • Many symbol names still end up in the string table, which appears to be down to RTTI, -fno-rtti makes them go away in my simple tests, but is a rather nuclear solution.

I'm happy to accept any better solutions anyone comes up with!

这篇关于剥离linux共享库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆