Ada*_*wen 33 c++ linux gcc strip shared-libraries
我们最近被要求发布我们的一个库的Linux版本,以前我们在Linux下开发并发布用于Windows,其中部署库通常要容易得多.我们遇到的问题是将导出的符号剥离到只有暴露界面中的符号.想要这样做有三个很好的理由
举一个简单的例子:
TEST.CPP
#include <cmath>
float private_function(float f)
{
return std::abs(f);
}
extern "C" float public_function(float f)
{
return private_function(f);
}
Run Code Online (Sandbox Code Playgroud)
用(g ++ 4.3.2,ld 2.18.93.20081009)编译
g++ -shared -o libtest.so test.cpp -s
Run Code Online (Sandbox Code Playgroud)
用符号检查符号
nm -DC libtest.so
Run Code Online (Sandbox Code Playgroud)
给
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
Run Code Online (Sandbox Code Playgroud)
显然不足.接下来我们重新宣布公共职能为
extern "C" float __attribute__ ((visibility ("default")))
public_function(float f)
Run Code Online (Sandbox Code Playgroud)
并编译
g++ -shared -o libtest.so test.cpp -s -fvisibility=hidden
Run Code Online (Sandbox Code Playgroud)
这使
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
Run Code Online (Sandbox Code Playgroud)
哪个好,除了暴露了std :: abs.更有问题的是当我们开始链接到我们控制之外的其他(静态)库时,我们从这些库中使用的所有符号都会被导出.另外,当我们开始使用STL容器时:
#include <vector>
struct private_struct
{
float f;
};
void other_private_function()
{
std::vector<private_struct> v;
}
Run Code Online (Sandbox Code Playgroud)
我们最终会从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()
Run Code Online (Sandbox Code Playgroud)
注意:通过优化,您需要确保实际使用向量,因此编译器不会优化未使用的符号.
我相信我的同事已设法构建一个涉及版本文件和修改似乎有效的STL标题(!)的临时解决方案,但我想问:
是否有一种干净的方法可以从linux共享库中删除所有不必要的符号(IE不属于公开的库功能)?我已经为g ++和ld尝试了很多选项但收效甚微,所以我更喜欢那些已知可行而不是相信的答案.
特别是:
我们的导出界面是C.
我知道关于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);
}
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);
}
Run Code Online (Sandbox Code Playgroud)
exports.version
LIBTEST
{
global:
public*;
local:
*;
};
Run Code Online (Sandbox Code Playgroud)
用.编译
g++ -shared test.cpp -o libtest.so -fvisibility=hidden -fvisibility-inlines-hidden -s -Wl,--version-script=exports.version
Run Code Online (Sandbox Code Playgroud)
给
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
Run Code Online (Sandbox Code Playgroud)
这与我们正在寻找的相当接近.但有一些陷阱:
我很高兴接受任何人提出的更好的解决方案!
您应使用-fvisibility-inlines-hidden扩充对默认可见性属性和-fvisibility = hidden的使用.
您还应该忘记尝试隐藏stdlib导出,请参阅此GCC错误原因.
此外,如果您在特定标头中包含所有公共符号,则可以将它们包装在内#pragma GCC visibility push(default)而#pragma GCC visibility pop不是使用属性.虽然如果您要创建跨平台库,请查看控制共享库的导出符号,以获得统一Windows DLL和Linux DSO导出策略的技术.
如果您将私有部分包装在匿名命名空间中,则在符号表中既不可见std::abs也不private_function可见:
namespace{
#include<cmath>
float private_function(float f)
{
return std::abs(f);
}
}
extern "C" float public_function(float f)
{
return private_function(f);
}
Run Code Online (Sandbox Code Playgroud)
编译(g++ 4.3.3):
g++ -shared -o libtest.so test.cpp -s
检查:
# nm -DC libtest.so
w _Jv_RegisterClasses
0000200c A __bss_start
w __cxa_finalize
w __gmon_start__
0000200c A _edata
00002014 A _end
000004a8 T _fini
000002f4 T _init
00000445 T public_function
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
20509 次 |
| 最近记录: |