Hiding symbol names in library

shared library symbols
c static library hide symbols
strip symbols from shared library
fvisibility
fvisibility=hidden static library
gcc dllexport
gcc no export-all symbols
static library export symbols

I want to hide symbol names which are not relevant to the last user and make visible only APIs in my shared or static library. I have a simple code like that:

int f_b1(){
return 21 ;
}

int f_b3(){
return f_b1() ;
}

I applied the all methods stated here such as using __attribute__ ((visibility ("hidden"))) and static data but got no successful result. My operating system is Ubuntu and x86_64 GNU/Linux processor. Do we use special options while compiling with gcc? I am listing modules and function of libraries with nm command. In my example above I only want to make visible f_b3 function. When I use attribute hidden macro compiler does not give any error but the function still exists in list outputted by nm command.

The visibility("hidden") attribute does not suppress a symbol from an object file and cannot prevent a symbol being extracted by nm. It just instructs the dynamic linker that the symbol cannot be called from outside a shared library that contains it.

Consider a source file file.c containing your example functions:

int f_b1(){
return 21 ;
}

int f_b3(){
return f_b1() ;
}

Compile the file:

gcc -c -o file.o file.c

Run nm file.o to list the symbols. Output:

0000000000000000 T f_b1
000000000000000b T f_b3

Now run objdump -t file.o for fuller information about the symbols. Output:

file.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 file.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 l    d  .bss   0000000000000000 .bss
0000000000000000 l    d  .note.GNU-stack    0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame  0000000000000000 .eh_frame
0000000000000000 l    d  .comment   0000000000000000 .comment
0000000000000000 g     F .text  000000000000000b f_b1
000000000000000b g     F .text  000000000000000b f_b3

Here we see that f_b1 and f_b3 are global (g) functions (F) in the .text section.

Now modify the file like this:

__attribute__((visibility ("hidden"))) int f_b1(void){
return 21 ;
}

__attribute__((visibility ("hidden"))) int f_b3(void){
return f_b1() ;
}

Run objdump again:

file.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 file.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 l    d  .bss   0000000000000000 .bss
0000000000000000 l    d  .note.GNU-stack    0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame  0000000000000000 .eh_frame
0000000000000000 l    d  .comment   0000000000000000 .comment
0000000000000000 g     F .text  000000000000000b .hidden f_b1
000000000000000b g     F .text  000000000000000b .hidden f_b3

The output is the same, except that the symbols f_b1 and f_b3 are now marked .hidden. They still have external (global) linkage and could be statically called, for example, from other modules within a library that contains them, but could not be dymamically called from outside that library.

So, if you want to conceal f_b1 and f_b3 from dynamic linkage in a shared library, you can use visibility ("hidden") as shown.

If you want to conceal f_b1 and f_b3 from static linkage in a static library, you cannot use the visibility attribute to do that at all.

In the case of a static library, you can "hide" a symbol only be giving it internal instead of external linkage. The way to do that is by prefixing the standard static keyword. But internal linkage means that the symbol is visible only within its own compilation unit: it can't be referenced from other modules. It is not available to the linker at all.

Modify file.c again, like this:

static int f_b1(void){
return 21 ;
}

static int f_b3(void){
return f_b1() ;
}

And run objump again:

file.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 file.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 l    d  .bss   0000000000000000 .bss
0000000000000000 l     F .text  000000000000000b f_b1
000000000000000b l     F .text  000000000000000b f_b3
0000000000000000 l    d  .note.GNU-stack    0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame  0000000000000000 .eh_frame
0000000000000000 l    d  .comment   0000000000000000 .comment

You see that f_b1 and f_b3 are still reported as functions in the .text section, but are now classified local (l), not global. That is internal linkage. Run nm file.o and the output is:

0000000000000000 t f_b1
000000000000000b t f_b3

That is the same as for the original file, except that instead of 'T' flags we now have 't' flags. Both flags mean that the symbol is in the .text section, but 'T' means it is global and 't' means it is local.

Apparently, what you would like nm to report for this file is no symbols at all. You should now understand that nm file.o will report a symbol if it exists in file.o, but its existence has got nothing to do with whether it is visible for static or dynamic linkage.

To make the function symbols disappear, compile file.c yet again (still with the static keyword), this time with optimisation enabled:

gcc -c -O1 -o file.o file.c

Now, objdump reports:

file.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 file.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 l    d  .bss   0000000000000000 .bss
0000000000000000 l    d  .note.GNU-stack    0000000000000000 .note.GNU-stack
0000000000000000 l    d  .comment   0000000000000000 .comment

f_b1 and f_b3 are gone, and nm file.o reports nothing at all. Why? Because static tells the compiler that these symbols can only be called from within the file it is compiling, and optimisation decides that there is no need to refer to them; so the compiler eliminates them from the object code. But if they weren't already invisible to linker, without optimisation, then we couldn't optimise them away.

Bottom line: It doesn't matter whether nm can extract a symbol. If the symbol is local/internal, it can't be linked, either statically or dynamically. If the symbol is marked .hidden then it can't be dynamically linked. You can use visibility("hidden") to mark a symbol .hidden. Use the standard static keyword to make a symbol local/internal.

How to hide the exported symbols name within a shared library , The previous answers regarding attribute ((visibility ("hidden"))) is good when you want to maintain the code long term, but if you only have a� An exports file contains raw symbol names, one per line. Xcode has “Exported Symbols File” and “Unexported Symbols File” options to which you pass the file name, and it will either hide or show all the symbols on the list. CMake. The problem with CMake is that it calls ar on static libraries, not ld. We need it to call ld -r so it will

I realize this is already an old thread. However, I'd like to share some facts about static linking in the sense of making hidden symbols local and hence prevent those symbols from (global) static linkage in an object file or static library. This does not mean making them invisible in the symbol table.

Mike Kingham's answer is very usefull but not complete on the following detail:

If you want to conceal f_b1 and f_b3 from static linkage in a static library, you cannot use the visibility attribute to do that at all.

Let me show that hidden symbols can certainly be made local by using the example of the simple code in file.c and applying ypsu's answer in Symbol hiding in static libraries built with Xcode/gcc. At a first step let's reproduce the objdump output with the hidden attribute visible on f_b1 and f_b3. This can be done by the following command, which gives all functions in file.c the hidden attribute:

gcc -fvisibility=hidden -c file.c

Output of objdump -t file.o gives

file.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 file.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 l    d  .bss   0000000000000000 .bss
0000000000000000 l    d  .note.GNU-stack    0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame  0000000000000000 .eh_frame
0000000000000000 l    d  .comment   0000000000000000 .comment
0000000000000000 g     F .text  000000000000000b .hidden f_b1
000000000000000b g     F .text  0000000000000010 .hidden f_b3

This is exactly the same intermediate result as obtained by Mike Kingham. Now let's make the symbols with the hidden attribute local. That is accomplished by using objcopy from binutils as follows:

objcopy --localize-hidden --strip-unneeded file.o

Using objdump, gives

file.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l     F .text  000000000000000b .hidden f_b1
000000000000000b l     F .text  0000000000000010 .hidden f_b3
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 l    d  .bss   0000000000000000 .bss
0000000000000000 l    d  .comment   0000000000000000 .comment
0000000000000000 l    d  .note.GNU-stack    0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame  0000000000000000 .eh_frame

Likewise, nm file.o gives

0000000000000000 t f_b1
000000000000000b t f_b3

Although f_b1 and f_b3 are still visible in the the symbol table they are local. Hence, functions f_b1 and f_b3 are concealed from static linking!

I'd also like to add a note on declaring functions static and by that having the possibility to remove them from the symbol table completely. First, the removal can be done deterministically and not depending on compiler optimization by using objcopy.

objcopy --strip-unneeded file.o

The static functions f_b1 and f_b2 are not anymore in the symbol table of file.o.

Secondly, this use of declaring functions static to let them disappear from the symbol table only works in single source file C-projects. As soon as a C-project consists of many components and hence files this only can be done by merging all C-source and -header files into one single source file and declare all internal interfaces (functions) static with obvious the exception of the global (top) interface. If that is not possible, one can fallback to the method originally described by ypsu (and probably many others - see for instance Restricting symbols in a Linux static library).

Hiding what's exposed in a shared library, Specifically we will focus on hiding all unnecessary symbol names in your For our example we have built a very small library that we name� contained in the library, then internal symbol names may expose some amount of that IP. You may also want to hide internal functionality to prevent unintended use. For example, if a library exposed a symbol named perform_operation_foobar a curious programmer may believe they can directly

Hiding Symbols in Static Libraries with Xcode or CMake, a file output by your compiler by default, even a release build without debug symbols, it will contain a lot of readable text: The names of all your� Introduction. This Technical Note discusses how symbols from a library can be hidden, using isymexport and a steering file. Issue. The application is defining global variables and/or functions having the same name as non-weak global variables and/or functions in a library you have made.

Actually, in the ELF structure there are 2 symbol tables: "symtab" and "dynsym". In my custom libs, I'm always stripping all the symbols, because they are not needed for proper linking - i.e. the "symtab" (which is printed by the "nm" utility) can be empty, because the linker is actually using the "dynsym" table. This allows to reduce the lib size by ~10-20% (typically)

The functions with "hidden" attribute are removed only from "symtab", but they can still be visible in the "dynsym" table.

You can verify this by using:

readelf --syms --dyn-syms <your dso here>

The "dynsym" table always contains all the entries needed by the linker, including f.e. the STD:: functions, marked as "UND" (undefined -> to be resolved by the linker)

Regards.

3. Exposing and Hiding Symbols, In the vast majority of cases, a dynamic library will provide a set of symbols a list of symbols to export; any symbol not in such lists will be hidden and thus not expression: symbols whose name matches the expression will be exposed by � Hiding symbol names in library. 2. Different math symbol bindings with shared library with dlopen and directly linked into executable (Linux) Hot Network Questions

Simple C++ Symbol Visibility Demo, Hidden visibility for a given symbol causes a shared library to never load that (" Default" is an unfortunate name for this visibility type since the� --exclude-libs also accepts a list of archives (i.e. static library names) for finer granularity on which libraries to hide symbols from. Note: this will only work in systems using GNU binutils (e.g. Linux) or with a linker supporting --exclude-libs (e.g. it won't work with OSX's ld64)

GNU Gnulib: Exported Symbols of Shared Libraries, Symbols that are not exported from the library cannot be used. the same name in the executable or in a shared library interposed with LD_PRELOAD . The programmer specifies a “hidden” attribute for every variable and function that shall� The standard tool for listing symbols is nm, you can use it simply like this: nm -gD yourLib.so If you want to see symbols of a C++ library, add the "-C" option which demangle the symbols (it's far more readable demangled). nm -gDC yourLib.so If your .so file is in elf format, you have two options: Either objdump (-C is also useful for

Part 1 – Introduction to symbol visibility – Build Smart. Build Secure , As soon as one links against a library with the same symbol names as that of However, though the static keyword can hide the symbol, it also� Symbols from (closed-source) static libraries are not exported. Symbols from the standard library are not exported. Non-public symbols from the object files are not exported. Our exported interface is C. I'm aware of the other similar questions on SO: NOT sharing all classes with shared library; How to REALLY strip a binary in MacOs

Comments
  • That is great explanation.
  • Is there a way to hide object file names also? My nm command outputs like this. b.o: 0000000000000000 T f_b2 0000000000000010 T f_b3 c.o: I would like to hide b.o and c.o names, as well. Thanks..
  • Yes: Run strip -s file.o. See man strip. Note that when you remove all symbols you can't debug the object file.
  • strip -s file.o removes all symbols, not only can I debug but I also can not use any functions since their symbols does not exists on symbol table. I only need to remove object file names from the library.
  • As I understand it is not possible to hide class member symbols without changing structure of classes. Using inline keyword converts methods to static which can not use internal variables of class which are not static. You again emphasize on -s|--strip-all command but it removes all symbols and it makes library unusable since the linker can not find any symbols. Am I missing something here? I only would like to make visible necessary APIs and hide all internal data. Is there a way to change symbol names on an object/library?