Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use the __attribute__((visibility("default")))?

Reading Visibility in the GNU wiki, it is clear.

Taking this example from C++ Tutorials

// classes example #include <iostream> using namespace std;  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; } 

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

I wrote my makefile to get the .so

someproj.so : someproj.cpp     g++ --std=c++11 -O3 -fPIC -shared someproj.cpp -o someproj.so 

Modified to make all symbols hidden by adding -fvisibility=hidden

someproj.so : someproj.cpp     g++ --std=c++11 -O3 -fvisibility=hidden -fPIC -shared someproj.cpp -o someproj.so 

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

Currently using 4.7.2 version of gcc

like image 246
Tony Tannous Avatar asked Oct 09 '18 10:10

Tony Tannous


People also ask

What is __ attribute __ (( visibility default?

Summary. To summarize, __attribute__((visibility("default"))) is often used in a shared library, and expected to be compiled with -fvisibility=hidden (though it doesn't have to). Symbols with "default" visibility will always be public outside of the shared library itself.

What does Fvisibility hidden do?

-fvisibility=hidden makes all your symbols hidden by default. What you then have to do, is choose which functions you want to be visible to users linking against your library and make them visible by marking them with a visible attribute.

What is __ attribute __ in C?

The __attribute__ directive is used to decorate a code declaration in C, C++ and Objective-C programming languages. This gives the declared code additional attributes that would help the compiler incorporate optimizations or elicit useful warnings to the consumer of that code.

What is attribute visibility?

With the visibility type attributes, you can control whether and how a structure/union/class or an enumeration that is defined in one module can be referenced or used in other modules. Visibility attributes affect only types with external linkage.


1 Answers

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.

like image 164
Mike Kinghan Avatar answered Oct 03 '22 15:10

Mike Kinghan