根据answer,我使用建筑工具链中的标志-fvisibility=hidden
和命令 strip 隐藏了共享库的大多数内部符号。但是我发现一些用作标准C ++容器元素的符号无法隐藏。
例如,
/* example1.cpp */
#include <stdio.h>
#define MY_EXPORTS __attribute__((visibility("default")))
extern "C" {
MY_EXPORTS void* create();
MY_EXPORTS void dosth(void*, int i);
MY_EXPORTS void release(void*);
}
class Point {
public:
int x;
int y;
Point() {
x = -1;
y = -1;
}
Point(int x_, int y_) {
x = x_;
y = y_;
}
int X() const {return x;}
int Y() const {return y;}
};
class ABC {
Point pts[2];
public:
ABC() {
Point pt0(0,0), pt1(1,1);
pts[0] = pt0;
pts[1] = pt1;
}
int getx(int i) { return pts[i].x; }
int gety(int i) { return pts[i].y; }
};
MY_EXPORTS void* create()
{
return new ABC();
}
MY_EXPORTS void dosth(void* handle, int i)
{
ABC* p = (ABC*)handle;
printf("%d,%d\n", p->getx(i), p->gety(i));
}
MY_EXPORTS void release(void* handle)
{
ABC* p = (ABC*)handle;
delete p;
}
像这样编译 example1.cpp
$ g++ -fPIC -shared -fvisibility=hidden ../example1.cpp -o libexample.so
$ strip -R .comment -R .note libexample.so
命令nm -D libexample.so | grep Point
不返回任何内容。
然后我用std::vector
,
/* example2.cpp */
#include <stdio.h>
#include <vector>
#define MY_EXPORTS __attribute__((visibility("default")))
extern "C" {
MY_EXPORTS void* create();
MY_EXPORTS void dosth(void*, int i);
MY_EXPORTS void release(void*);
}
using std::vector;
class Point {
public:
int x;
int y;
Point() {
x = -1;
y = -1;
}
Point(int x_, int y_) {
x = x_;
y = y_;
}
int X() const {return x;}
int Y() const {return y;}
};
class ABC {
vector<Point> pts;
public:
ABC() {
pts.push_back(Point(0,0));
pts.push_back(Point(1,1));
}
int getx(int i) { return pts[i].x; }
int gety(int i) { return pts[i].y; }
};
MY_EXPORTS void* create()
{
return new ABC();
}
MY_EXPORTS void dosth(void* handle, int i)
{
ABC* p = (ABC*)handle;
printf("%d,%d\n", p->getx(i), p->gety(i));
}
MY_EXPORTS void release(void* handle)
{
ABC* p = (ABC*)handle;
delete p;
}
我编译 example2.cpp 就像这样
$ g++ -fPIC -shared -fvisibility=hidden ../example2.cpp -o libexample.so
$ strip -R .comment -R .note libexample.so
命令nm -D libexample.so | grep Point
打印出类似这样的内容
000000000000311c W _ZN9__gnu_cxx13new_allocatorI5PointE10deallocateEPS1_m
00000000000030be W _ZN9__gnu_cxx13new_allocatorI5PointE7destroyEPS1_
0000000000003236 W _ZN9__gnu_cxx13new_allocatorI5PointE8allocateEmPKv
0000000000002aba W _ZN9__gnu_cxx13new_allocatorI5PointE9constructEPS1_RKS1_
...
0000000000002dd2 W _ZNSt6vectorI5PointSaIS0_EE3endEv
0000000000002fde W _ZNSt6vectorI5PointSaIS0_EE5beginEv
0000000000002942 W _ZNSt6vectorI5PointSaIS0_EE9push_backERKS0_
似乎因为 STL 的分配器和向量是由模板实现的。但为什么这些信息无法隐藏?
我的编译器是 gcc-4.6 ,os是 LMDE MATE Edition 。
答案 0 :(得分:2)
这些是由STL模板机制创建的函数。这些名称的可见性受sTL的控制,因此您的代码不会影响它们是否可见。
目前尚不清楚您是想减少符号数量,还是实际上想要隐藏共享库中的特定名称 - 例如,如果您有class MySecretObject
,则要隐藏的不同于符号表包含数以千计的名字,这让我很烦恼。
您可能会创建一个隐藏实际名称的包装类型,但不管怎样,如果您真的想要隐藏对象的存在,您需要修改STL以不暴露它。当然,这也意味着您需要使用该特殊名称[尽管有时巧妙地使用宏可以避免这种情况]。
没有简单/推荐的方法来避免STL导出某些符号。那将会发生。如果使用包装器类型,您可以控制它们的名称,但它实际上并不会更改导出的名称的数量或类型,只是更改的名称。
如果您解释一下您对“我只想导出那些我想要导出的内容”的关注,我会很乐意扩展答案。
编辑:
我相信通过将对象包装在另一个类中来“隐藏”一个名称会起作用:
class HidePoint
{
public:
Point p;
};
现在,您当然会公开HidePoint
,但如果您将其称为A
或W
或类似的内容,那么它就会被隐藏。
可替换地:
#define Point SomeOtherUniqueName
将隐藏名称。