如果我将它用作STL容器的元素,为什么我不能隐藏某些符号的名称?

时间:2014-01-26 09:11:49

标签: c++ gcc stl export c++-standard-library

根据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

替换C数组
/* 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

1 个答案:

答案 0 :(得分:2)

这些是由STL模板机制创建的函数。这些名称的可见性受sTL的控制,因此您的代码不会影响它们是否可见。

目前尚不清楚您是想减少符号数量,还是实际上想要隐藏共享库中的特定名称 - 例如,如果您有class MySecretObject,则要隐藏的不同于符号表包含数以千计的名字,这让我很烦恼。

您可能会创建一个隐藏实际名称的包装类型,但不管怎样,如果您真的想要隐藏对象的存在,您需要修改STL以不暴露它。当然,这也意味着您需要使用该特殊名称[尽管有时巧妙地使用宏可以避免这种情况]。

没有简单/推荐的方法来避免STL导出某些符号。那将会发生。如果使用包装器类型,您可以控制它们的名称,但它实际上并不会更改导出的名称的数量或类型,只是更改的名称。

如果您解释一下您对“我只想导出那些我想要导出的内容”的关注,我会很乐意扩展答案。

编辑:

我相信通过将对象包装在另一个类中来“隐藏”一个名称会起作用:

class HidePoint
{
  public:
    Point p;
};

现在,您当然会公开HidePoint,但如果您将其称为AW或类似的内容,那么它就会被隐藏。

可替换地:

#define Point SomeOtherUniqueName

将隐藏名称。