Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to programmatically list ELF shared library symbols

In my C shared library, I want to dlopen() another shared library and retrieve a list of the exported symbols this library has.

Is there a way I can do that programmatically, without running nm/objdump?

As a secondary question: How can I retrieve the base address where this second library got loaded after dlopen() - without knowing the names of any symbols (so I can't run dlsym!) and without reading /proc/self/maps?

I have tried the following:

struct link_map *imagehandle = (struct link_map*)dlopen(libraryname, RTLD_LOCAL | RTLD_LAZY);
void * fbase = (void*) imagehandle->l_addr;
printf("base addr is %p",fbase)

This prints

"base addr is 0x6862696c"

However, the library is not located there:

[ /proc/pid/maps output: ]

b6d27000-b6d28000 r-xp 00000000 1f:01 1581       mysecondlib.so
b6d28000-b6d29000 r--p 00000000 1f:01 1581       mysecondlib.so
b6d29000-b6d2a000 rw-p 00001000 1f:01 1581       mysecondlib.so

It has been suggested that l_addr is not the actual library base address ,but the offset from the executable header - but I am not sure how to find that header address.

like image 729
linker Avatar asked Nov 16 '14 18:11

linker


1 Answers

Yes, you definitely can get the symbol table programmatically. I would suggest that instead of running dlopen() on the SO, you open it yourself via mmap or even just read the file into contiguous memory yourself. Once it's in memory, you can quite easily iterate through each section of the SO by following documentation here: http://linux.die.net/man/5/elf. Sections having sh_type equal to SHT_SYMTAB (symbol table) are what you are looking for.

IF you still need to find the base address of a loaded SO, I have not found a way to get it from dlopen() in my experience. The best way I have found is to call dladdr() on a known symbol in the SO, which populates a Dl_info structure that contains a dli_fbase member, which is the base address of the module which the symbol came from. IF you indeed do not know any symbol from that SO, you can use dl_iterate_phdr (http://linux.die.net/man/3/dl_iterate_phdr), which will iterate over all the loaded SOs in your process and give you a dl_phdr_info struct instance for each one. This struct contains the name, base address (dlpi_addr), and array of program headers.

like image 63
Nicholas Smith Avatar answered Nov 14 '22 15:11

Nicholas Smith