Linux exported symbols library

How to export specific symbol from executables in GNU/Linux

While loading dynamic libraries by ::dlopen() , exporting symbols from executables can be done by -rdynamic option, but it exports all the symbols of the executable, which results in bigger binary size. Is there a way to export just specific function(s)? For example, I have testlib.cpp and main.cpp as below: testlib.cpp

extern void func_export(int i); extern "C" void func_test(void)
#include #include void func_export(int i) < ::fprintf(stderr, "%s: %d\n", __func__, i); >void func_not_export(int i) < ::fprintf(stderr, "%s: %d\n", __func__, i); >typedef void (*void_func)(void); int main(void) < void* handle = NULL; void_func func = NULL; handle = ::dlopen("./libtestlib.so", RTLD_NOW | RTLD_GLOBAL); if (handle == NULL) < fprintf(stderr, "Unable to open lib: %s\n", ::dlerror()); return 1; >func = reinterpret_cast(::dlsym(handle, "func_test")); if (func == NULL) < fprintf(stderr, "Unable to get symbol\n"); return 1; >func(); return 0; > 
g++ -fPIC -shared -o libtestlib.so testlib.cpp g++ -c -o main.o main.cpp 

I want func_export to be used by the dynamic library, but hide the func_not_export. If link with -rdynamic, g++ -o main -ldl -rdynamic main.o , both functions are exported. If not link with -rdynamic, g++ -o main_no_rdynamic -ldl main.o , I got runtime error Unable to open lib: ./libtestlib.so: undefined symbol: _Z11func_exporti Is it possible to achieve the requirement that only export the specific function?

Источник

How do I list the symbols in a .so file

How do I list the symbols being exported from a .so file? If possible, I’d also like to know their source (e.g. if they are pulled in from a static library). I’m using gcc 4.0.2, if that makes a difference.

The platform makes a difference. Apple provides a GCC 4.0, but its nm does not respond to some options, like -D and -g (IIRC).

11 Answers 11

The standard tool for listing symbols is nm , you can use it simply like this:

If you want to see symbols of a C++ library, add the «-C» option which demangle the symbols (it’s far more readable demangled).

If your .so file is in elf format, you have two options:

Either objdump ( -C is also useful for demangling C++):

$ objdump -TC libz.so libz.so: file format elf64-x86-64 DYNAMIC SYMBOL TABLE: 0000000000002010 l d .init 0000000000000000 .init 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 free 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __errno_location 0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable 
$ readelf -Ws libz.so Symbol table '.dynsym' contains 112 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000002010 0 SECTION LOCAL DEFAULT 10 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND free@GLIBC_2.2.5 (14) 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __errno_location@GLIBC_2.2.5 (14) 4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable 

Источник

Читайте также:  Создание сокетов в linux

Using `fvisibility’ compiler option

The compiler flag -fvisibility=hidden is designed for dealing with exactly this kind of problems. By using this option, the user tells the compiler to exclude all of the symbols from the export table:

$ g++ code.cpp -o libcode.so -shared -fPIC -fvisibility=hidden $ nm -CD libcode.so | grep " T " 00000000000007e8 T _fini 00000000000005f8 T _init 

But, we want also to include the entry_point function in the table, because it’s our API function. This is why we need to change the source code a little bit:

#include <iostream> using namespace std; void function1() < cout __attribute__ ((visibility ("default"))) void entry_point()

After compilation, our goal is matched:

$ g++ code.cpp -o libcode.so -shared -fPIC -fvisibility=hidden $ nm -CD libcode.so | grep " T " 0000000000000778 T entry_point() 0000000000000818 T _fini 0000000000000628 T _init 

The __attribute__ ((visibility ("default"))) is very similar to __declspec(dllexport) that can be found on Microsoft's compilers. In fact, GCC should handle it as well. The attribute overrides the -fvisibility=hidden compiler option only for only one symbol, and makes it public. That's why it's included in the export table.

Static library used by a shared library problems

However, there is one problem with this approach. If our shared library is large enough, it may use other libraries that are statically linked. Let's consider another example.

Let's suppose we have a static library, libutil.a , that is statically linked into our shared library, libcode.so .

Here is our util.cpp file, that is the source of the static library:

#include <iostream> using namespace std; void util_function()

Let's compile it, and build a static library from this code:

$ g++ util.cpp -o util.o -c -fPIC $ ar r libutil.a util.o 

We have now libutil.a static library which can be used in our shared object. Let's modify the shared object to include a reference to the code of libutil.a (without it, libutil.a would be dropped in the linking process):

#include <iostream> using namespace std; extern void util_function(); void function1() < util_function(); cout __attribute__ ((visibility ("default"))) void entry_point()

Let's compile our shared library and see its export table:

$ g++ code.cpp libutil.a -o libcode.so -shared -fPIC -fvisibility=hidden $ nm -CD libcode.so | grep " T " 00000000000007ed T entry_point() 0000000000000858 T util_function() 0000000000000918 T _fini 0000000000000688 T _init 

As you can see, util_function is included in the list, but we don't want it there. How to fix this?

Читайте также:  Linux узнать пользователя apache

One solution is to add -fvisibility=hidden to libutil.a library's build process, but sometimes we don't have the control over it. What then?

Linker scripts to the rescue.

Using `ld' linker version script

We need to get rid of the util_function symbol during the linking process, because we may not have any control over the compilation of libutil.a library.

Fortunately, ld supports export table filtering (and much more) by using a "version script", which will contain some definitions on what to include, and what to skip. It even supports wildcards which also may help.

So, let's skip the -fvisibility=hidden option for now, and build our shared library like this:

$ g++ code.cpp libutil.a -o libcode.so -shared -fPIC 

Then, create a text file, libcode.version , with this content:

This version file tells the linker, that all symbols ( * ) should be considered as local symbols (that is: hidden), and all symbols that match the wildcard *entry_point* should be considered as global (so, visible).

Compilation is done by the g++ driver:

$ g++ code.cpp libutil.a -o shared -fPIC -Wl,--version-script=libcode.version 
$ nm -CD libcode.so | grep " T " 000000000000074d T entry_point() 

It even stripped out the _init and _fini symbols. Job done!

The problem with this approach is that it can't handle some more complicated scenarios, like filtering only some symbols that are using C++ templates. Some of the template-based symbols in C++ can easily grow up to few hundred characters, but you probably know what I mean. Once you start using functions from std:: , you'll know.

Please do some reading about the linker's version scripts, because it allows you to perform some really cool things, like symbol versioning!

Источник

How do I find out what all symbols are exported from a shared object?

All symbols in the object are exported - even the "internal" functions. You just have to declare them to the compiler so that they'll be ready for the linker. This is usually done with a header file, like Ryan Fox said below.

Chris Lutz is mistaken: not all symbols are exported from relocatable object files, much less from shared libraries.

9 Answers 9

Do you have a "shared object" (usually a shared library on AIX), a UNIX shared library, or a Windows DLL? These are all different things, and your question conflates them all 🙁

  • For an AIX shared object, use dump -Tv /path/to/foo.o .
  • For an ELF shared library, use readelf -Ws --dyn-syms /path/to/libfoo.so , or (if you have GNU nm) nm -D /path/to/libfoo.so .
  • For a non-ELF UNIX shared library, please state which UNIX you are interested in.
  • For a Windows DLL, use dumpbin /EXPORTS foo.dll .
Читайте также:  Display graphic card linux

Very helpful, good to have such overview. nm also works on MacOSX, except the -D option. Or brew install binutils and use the GNU version via gnm . For GNU nm , --demangle is also useful. Also gobjdump .

Actually, you can work both with shared libraries, dlls, and object filles from a single utility just fine, see this answer.

I suppose there is no API to do this in runtime, right? I've found that on windows you have GetProcAddress() but you can't use it without actually executing the library (which is very dangerous if the parent app has too much access rights).

objdump is another good one on linux.

If it is a Windows DLL file and your OS is Linux then use winedump:

$ winedump -j export pcre.dll Contents of pcre.dll: 229888 bytes Exports table: Name: pcre.dll Characteristics: 00000000 TimeDateStamp: 53BBA519 Tue Jul 8 10:00:25 2014 Version: 0.00 Ordinal base: 1 # of functions: 31 # of Names: 31 Addresses of functions: 000375C8 Addresses of name ordinals: 000376C0 Addresses of names: 00037644 Entry Pt Ordn Name 0001FDA0 1 pcre_assign_jit_stack 000380B8 2 pcre_callout 00009030 3 pcre_compile . 

On *nix check nm. On windows use the program Dependency Walker

Specifically, nm --defined-only -g something.so will print the symbols that are both defined in the library and extern symbols, which is probably what the OP wants.

GNU nm lists the symbols from object files objfile. If no object files are listed as arguments, nm assumes the file a.out.

The cross-platform way (not only cross-platform itself, but also working, at the very least, with both *.so and *.dll ) is using reverse-engineering framework radare2. E.g.:

$ rabin2 -s glew32.dll | head -n 5 [Symbols] vaddr=0x62afda8d paddr=0x0005ba8d ord=000 fwd=NONE sz=0 bind=GLOBAL type=FUNC name=glew32.dll___GLEW_3DFX_multisample vaddr=0x62afda8e paddr=0x0005ba8e ord=001 fwd=NONE sz=0 bind=GLOBAL type=FUNC name=glew32.dll___GLEW_3DFX_tbuffer vaddr=0x62afda8f paddr=0x0005ba8f ord=002 fwd=NONE sz=0 bind=GLOBAL type=FUNC name=glew32.dll___GLEW_3DFX_texture_compression_FXT1 vaddr=0x62afdab8 paddr=0x0005bab8 ord=003 fwd=NONE sz=0 bind=GLOBAL type=FUNC name=glew32.dll___GLEW_AMD_blend_minmax_factor 

As a bonus, rabin2 recognizes C++ name mangling, for example (and also with .so file):

$ rabin2 -s /usr/lib/libabw-0.1.so.1.0.1 | head -n 5 [Symbols] vaddr=0x00027590 paddr=0x00027590 ord=124 fwd=NONE sz=430 bind=GLOBAL type=FUNC name=libabw::AbiDocument::isFileFormatSupported vaddr=0x0000a730 paddr=0x0000a730 ord=125 fwd=NONE sz=58 bind=UNKNOWN type=FUNC name=boost::exception::~exception vaddr=0x00232680 paddr=0x00032680 ord=126 fwd=NONE sz=16 bind=UNKNOWN type=OBJECT name=typeinfoforboost::exception_detail::clone_base vaddr=0x00027740 paddr=0x00027740 ord=127 fwd=NONE sz=235 bind=GLOBAL type=FUNC name=libabw::AbiDocument::parse 

Works with object files too:

$ g++ test.cpp -c -o a.o $ rabin2 -s a.o | head -n 5 Warning: Cannot initialize program headers Warning: Cannot initialize dynamic strings Warning: Cannot initialize dynamic section [Symbols] vaddr=0x08000149 paddr=0x00000149 ord=006 fwd=NONE sz=1 bind=LOCAL type=OBJECT name=std::piecewise_construct vaddr=0x08000149 paddr=0x00000149 ord=007 fwd=NONE sz=1 bind=LOCAL type=OBJECT name=std::__ioinit vaddr=0x080000eb paddr=0x000000eb ord=017 fwd=NONE sz=73 bind=LOCAL type=FUNC name=__static_initialization_and_destruction_0 vaddr=0x08000134 paddr=0x00000134 ord=018 fwd=NONE sz=21 bind=LOCAL type=FUNC name=_GLOBAL__sub_I__Z4funcP6Animal 

Источник

Оцените статью
Adblock
detector