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.
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:
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.
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:
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 onf_b1
andf_b3
. This can be done by the following command, which gives all functions infile.c
the hidden attribute:Output of
objdump -t file.o
givesThis 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
frombinutils
as follows:Using objdump, gives
Likewise,
nm file.o
givesAlthough
f_b1
andf_b3
are still visible in the the symbol table they are local. Hence, functionsf_b1
andf_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
.The static functions
f_b1
andf_b2
are not anymore in the symbol table offile.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).
The
visibility("hidden")
attribute does not suppress a symbol from an object file and cannot prevent a symbol being extracted bynm
. 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:Compile the file:
Run
nm file.o
to list the symbols. Output:Now run
objdump -t file.o
for fuller information about the symbols. Output:Here we see that
f_b1
andf_b3
are global (g) functions (F) in the.text
section.Now modify the file like this:
Run
objdump
again:The output is the same, except that the symbols
f_b1
andf_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
andf_b3
from dynamic linkage in a shared library, you can usevisibility ("hidden")
as shown.If you want to conceal
f_b1
andf_b3
from static linkage in a static library, you cannot use thevisibility
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:And run
objump
again:You see that
f_b1
andf_b3
are still reported as functions in the.text
section, but are now classified local (l), not global. That is internal linkage. Runnm file.o
and the output is: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 thatnm file.o
will report a symbol if it exists infile.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 thestatic
keyword), this time with optimisation enabled:Now,
objdump
reports:f_b1
andf_b3
are gone, andnm file.o
reports nothing at all. Why? Becausestatic
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 usevisibility("hidden")
to mark a symbol.hidden
. Use the standardstatic
keyword to make a symbol local/internal.Note that for MacOS/iOS the linker has some extra options to control symbol visibility;
-[un|re]exported_symbols_list
-[un]exported_symbol
For more information check e.g. the ld64 documentation or have a look here.