Pregunta

According to the answer, I had hidden the most internal symbols of a shared library by using the flag -fvisibility=hidden and the command strip from the building toolchain. But I'd found some symbols, which are used as a standard C++ container's elements, cannot be hidden.

For example,

/* 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;
}

Compiled example1.cpp like this

$ g++ -fPIC -shared -fvisibility=hidden ../example1.cpp -o libexample.so 
$ strip -R .comment -R .note libexample.so

And the command nm -D libexample.so | grep Point return nothing.

Then I replace the C array with the 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;
}

And I compiled example2.cpp like this

$ g++ -fPIC -shared -fvisibility=hidden ../example2.cpp -o libexample.so 
$ strip -R .comment -R .note libexample.so

And the command nm -D libexample.so | grep Point print something like this

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_

It seems because the allocator and the vector of STL are implemented by template. But why this information cannot be hidden?

My compiler is gcc-4.6, os is LMDE MATE Edition.

¿Fue útil?

Solución

Those are functions created by STL templating mechanisms. The visibility of those names is under control of sTL, so your code can't affect whether they are visible.

It's not clear if you simply want to reduce the amount of symbols, or you actually want to hide a specific name from your shared library - for example if you have class MySecretObject, that you want to hide is different from the symbol table contains thousands of names and it annoys me.

You could, possibly, create a wrapper type that hides the actual name, but in some way or another, if you really want to hide the existence of an object, you need to modify the STL to not expose it. Of course, it also means that you will need to use that special name [although sometimes clever use of macros can avoid this].

There is no simple/recommended way to avoid some symbols being exported by the STL. That's going to happen. You can control what their names are if you use a wrapper type, but it's not really going to change the number or types of names exported, just the exact name being exposed.

I'll happily expand on the answer if you explain what your concern is for "I just want to only export those that I want to export".

Edit:

I believe it will work to "hide" a name by wrapping the object in another class:

class HidePoint
{
  public:
    Point p;
};

Now, you will of course expose HidePoint, but if you call it A or W or something like that, then it's hidden.

Alternatively:

#define Point SomeOtherUniqueName

will make the name be hidden.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top