The requirement is you need to provide a .so to the application exposing only your new symbols and not the symbols of the other .o/.so files that you might have used in creating your file.
Lets see an example of how to do it.
The ace card we use for this game is the gcc flag "-fvisibility=hidden".
Lets create a lib1.o which will serve as the .o that we want to include into our new file. After that we create a lib2.o that provides a wrapper (lib2_fun2) around the function (lib1_fun1) that we want to provide to the application. Finally we test this concept with a test application where we will call all the functions to check their visibility/ availability at this layer.
Step 1:
lib1.c : Function with Default visibility, built with hidden visibility.
void /*__attribute__ ((visibility ("default")) )*/ lib1_fun1(void);
void /*__attribute__ ((visibility ("default")) )*/ lib1_fun1(void)
{
printf("%s\n",__FUNCTION__);
}
$ gcc -fvisibility=hidden -fPIC -Wall -c lib1.c
$ readelf -s lib1.o | grep fun
Num: Value Size Type Bind Vis Ndx Name
12: 00000000 38 FUNC GLOBAL HIDDEN 2 lib1_fun1
Notice the Vis column saying "HIDDEN". :-) wasn't that what we wanted.
---------------------------------------------------------------------------------
Step 2:
lib2.c : Function _fun1 with hidden visibility & _fun2 with Default visibility, file built with hidden visibility.
void __attribute__ ((visibility ("hidden")) ) lib2_fun1(void);
void __attribute__ ((visibility ("default")) ) lib2_fun2(void);
void __attribute__ ((visibility ("default")) ) lib2_fun2(void)
{
printf("%s is calling ",__FUNCTION__);
lib1_fun1(); //This is the function we want to wrap and provide functionality to outside world
}
$ gcc -fvisibility=hidden -fPIC -Wall -c lib2.c
$ readelf -s lib2.o | grep fun
Num: Value Size Type Bind Vis Ndx Name
13: 00000000 38 FUNC GLOBAL HIDDEN 2 lib2_fun1
17: 00000026 53 FUNC GLOBAL DEFAULT 2 lib2_fun2
19: 00000000 0 NOTYPE GLOBAL DEFAULT UND lib1_fun1
---------------------------------------------------------------------------------
Make a .so file which includes both the object files in it.
$ gcc -fvisibility=hidden -shared -Wl,-soname,lib12.so -o lib12.so lib1.o lib2.o
$ readelf -s lib12.so | grep fun
Num: Value Size Type Bind Vis Ndx Name
6: 000004ea 53 FUNC GLOBAL DEFAULT 11 lib2_fun2
45: 0000049c 38 FUNC LOCAL DEFAULT 11 lib1_fun1
47: 000004c4 38 FUNC LOCAL DEFAULT 11 lib2_fun1
51: 000004ea 53 FUNC GLOBAL DEFAULT 11 lib2_fun2
Notice the lib1_fun1 is declared as 'LOCAL' even though the Visibilty is 'DEFAULT'
---------------------------------------------------------------------------------
With this we have achieved hiding the symbol from the outside world's usage. But the symbol is still exposed when we do a readelf. How do we get rid of that?
Thats were we use another tool called "strip"
$ strip --strip-all --discard-all lib12.so
$ readelf -s lib12.so | grep fun
Num: Value Size Type Bind Vis Ndx Name
6: 000004ea 53 FUNC GLOBAL DEFAULT 11 lib2_fun2
With this, the application writer can only "see" the symbols you want him to see and rest are completely removed. :-)
---------------------------------------------------------------------------------
Now make the testap to test all our theories.
int main(void)
{
lib1_fun1();
lib2_fun1();
lib2_fun2();
return 0;
}
$gcc -o testapp testlib.c -L. -l12
The result is
/tmp/cc2DnM96.o: In function `main':
testlib.c:(.text+0x7): undefined reference to `lib1_fun1'
testlib.c:(.text+0xc): undefined reference to `lib2_fun1'
collect2: ld returned 1 exit status
This shows that the only symbol available to the application out of the lib12.so is 'lib2_fun2' which we wanted to provide and hence declared as global. The rest of the symbols are only 'Local' to the library and are NOT available outside the library to any application that might link to it.
For more information about the "-fvisibility" option, check the below links
http://blog.fesnel.com/blog/2009/08/19/hiding-whats-exposed-in-a-shared-library/
http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Function-Attributes.html