How to use the __attribute__((visibility(“default”)))?

前端 未结 1 1245
盖世英雄少女心
盖世英雄少女心 2021-01-30 23:05

Reading Visibility in the GNU wiki, it is clear.

Taking this example from C++ Tutorials

// classes example
#include 
using namespace std         


        
相关标签:
1条回答
  • 2021-01-30 23:37

    Is it possible to customize which functions are exposed by modifying the compilation command above?

    No. Compilation option -fvisibility=[default|internal|hidden|protected] (and note it is not a linkage option) makes the compiler attribute the specified dynamic visibility type to all global symbols generated in the compilation unit except those that are specifically excluded by having a countervailing __attribute__((visibility(....))) applied in the source code. Which makes the answer to your other question:

    Is it possible to make area() public and set_values(int,int) local as shown in the first link without altering the code?

    also No.

    How would you change the source code to make Rectangle::area() dynamically visible while all other global symbols are hidden for dynamic linkage by -fvisibility=hidden? Here is a walk-through:

    Let's start with:

    rectangle.cpp (1)

    class Rectangle {
        int width, height;
      public:
        void set_values (int,int);
        int area() {return width*height;}
    
    };
    
    void Rectangle::set_values (int x, int y) {
      width = x;
      height = y;
    }
    

    and simply compile it to a PIC rectangle.o so:

    $ g++ -Wall -c -fPIC rectangle.cpp
    

    Then check the global symbol table:

    $ nm -C rectangle.o
    0000000000000000 T Rectangle::set_values(int, int)
    

    Note that Rectangle::area isn't there. It's not available for linkage at all, so the question of its dynamic visibility just does not arise.

    That is because it is defined inline in the class definition and never called in the compilation unit, so gcc need not even compile its definition. It vanishes from the object file.

    Rectangle::set_values, on the other hand, is not defined inline, so the compiler emits a global symbol and definition.

    To make Rectangle::area eligible for some visibility type, we first need to make it a global symbol by not defining it inline:

    rectangle.cpp (2)

    class Rectangle {
        int width, height;
      public:
        void set_values (int,int);
        int area();
    
    };
    
    int Rectangle::area() {return width*height;}
    
    void Rectangle::set_values (int x, int y) {
      width = x;
      height = y;
    }
    

    Recompile and again check the global symbol table:

    $ g++ -Wall -c -fPIC rectangle.cpp
    $ nm -C rectangle.o
    000000000000001a T Rectangle::set_values(int, int)
    0000000000000000 T Rectangle::area()
    

    Good. Now a global definition of Rectangle::area appears.

    Next let's make a shared library librectangle.so from rectangle.o:

    $ g++ -o librectangle.so --shared rectangle.o
    

    Here are the Rectangle::* symbols in its global symbol table:

    $ nm -C librectangle.so | grep 'Rectangle::'
    00000000000005d4 T Rectangle::set_values(int, int)
    00000000000005ba T Rectangle::area()
    

    And here are the Rectangle::* symbols in its dynamic symbol table:

    $ nm -CD librectangle.so | grep 'Rectangle::'
    00000000000005d4 T Rectangle::set_values(int, int)
    00000000000005ba T Rectangle::area()
    

    They're the same.

    Now let's hide those symbols for dynamic linkage. We need to recompile rectangle.cpp then relink the shared library:

    $ g++ -Wall -c -fPIC -fvisibility=hidden rectangle.cpp
    $ g++ -o librectangle.so --shared rectangle.o
    

    Here again are the Rectangle::* symbols now in the global symbol table:

    $ nm -C librectangle.so | grep 'Rectangle::'
    0000000000000574 t Rectangle::set_values(int, int)
    000000000000055a t Rectangle::area()
    

    They're the same as before.

    And here are the Rectangle::* symbols now in the dynamic symbol table:

    $ nm -CD librectangle.so | grep 'Rectangle::'; echo Done
    Done
    

    Now there are none, thanks to -fvisibility=hidden.

    Finally, let's make just Rectangle::area dynamically visible, keeping all the other global symbols dynamically hidden. We need to change the source code again:

    rectangle.cpp (3)

    class Rectangle {
        int width, height;
      public:
        void set_values (int,int);
        __attribute__((visibility("default"))) int area();
    
    };
    
    int Rectangle::area() {return width*height;}
    
    void Rectangle::set_values (int x, int y) {
      width = x;
      height = y;
    }
    

    Then recompile and relink:

    $ g++ -Wall -c -fPIC -fvisibility=hidden rectangle.cpp
    $ g++ -o librectangle.so --shared rectangle.o
    

    The global symbol table still shows:

    $ nm -C librectangle.so | grep 'Rectangle::'
    00000000000005a4 t Rectangle::set_values(int, int)
    000000000000058a T Rectangle::area()
    

    And the dynamic symbol table only shows:

    $ nm -CD librectangle.so | grep 'Rectangle::'
    000000000000058a T Rectangle::area()
    

    Rectangle::area is now the only symbol that the shared library exposes for dynamic linkage.

    And before you go...

    One thing more about:

    Is it possible to make area() public and set_values(int,int) local as shown in the first link without altering the code?

    Making a symbol hidden for dynamic linkage doesn't make it local. Dynamic visibility (default|internal|hidden|protected) is an attribute of global symbols only. For linkage purposes, local symbols don't exist. The only ways to make a symbol local that would otherwise be global are:-

    • In C or C++ source, qualify its definition with the static keyword
    • In C++ source, enclose its definition in an anonymous namespace

    Then the symbol does not appear in the global, or dynamic, symbol tables.

    0 讨论(0)
提交回复
热议问题