AGGIORNAMENTO | TL;DR :
In realtà ho trovato un modo più breve:
auto library = dlopen("/path/to/lib.so", RTLD_LAZY | RTLD_GLOBAL);
const char * libname = "lib.so";
struct link_map * map = nullptr;
dlinfo(library, RTLD_DI_LINKMAP, &map);
Elf64_Sym * symtab = nullptr;
char * strtab = nullptr;
int symentries = 0;
for (auto section = map->l_ld; section->d_tag != DT_NULL; ++section)
{
if (section->d_tag == DT_SYMTAB)
{
symtab = (Elf64_Sym *)section->d_un.d_ptr;
}
if (section->d_tag == DT_STRTAB)
{
strtab = (char*)section->d_un.d_ptr;
}
if (section->d_tag == DT_SYMENT)
{
symentries = section->d_un.d_val;
}
}
int size = strtab - (char *)symtab;
for (int k = 0; k < size / symentries; ++k)
{
auto sym = &symtab[k];
// If sym is function
if (ELF64_ST_TYPE(symtab[k].st_info) == STT_FUNC)
{
//str is name of each symbol
auto str = &strtab[sym->st_name];
printf("%s\n", str);
}
}
VECCHIO
Credo che l'autore non ne abbia più bisogno, ma forse qualcuno ha bisogno del codice effettivo ed eccolo qui (basato sulla risposta precedente)
Innanzitutto, abbiamo bisogno di una richiamata per dl_iterate_phdr()
:
static int callback(struct dl_phdr_info *info, size_t size, void *data)
{
// data is copy of 2nd arg in dl_iterate_phdr
// you can use it for your lib name as I did
const char * libname = (const char *)data;
// if current elf's name contains your lib
if (strstr(info->dlpi_name, libname))
{
printf("loaded %s from: %s\n", libname, info->dlpi_name);
for (int j = 0; j < info->dlpi_phnum; j++)
{
// we need to save dyanmic section since it contains symbolic table
if (info->dlpi_phdr[j].p_type == PT_DYNAMIC)
{
Elf64_Sym * symtab = nullptr;
char * strtab = nullptr;
int symentries = 0;
auto dyn = (Elf64_Dyn *)(info->dlpi_addr + info->dlpi_phdr[j].p_vaddr);
for (int k = 0; k < info->dlpi_phdr[j].p_memsz / sizeof(Elf64_Dyn); ++k)
{
if (dyn[k].d_tag == DT_SYMTAB)
{
symtab = (Elf64_Sym *)dyn[k].d_un.d_ptr;
}
if (dyn[k].d_tag == DT_STRTAB)
{
strtab = (char*)dyn[k].d_un.d_ptr;
}
if (dyn[k].d_tag == DT_SYMENT)
{
symentries = dyn[k].d_un.d_val;
}
}
int size = strtab - (char *)symtab;
// for each string in table
for (int k = 0; k < size / symentries; ++k)
{
auto sym = &symtab[k];
auto str = &strtab[sym->st_name];
printf("%s\n", str);
}
break;
}
}
}
return 0;
}
Successivamente, chiamiamo dl_iterate_phdr()
:
int main()
{
auto library = dlopen("/path/to/library.so", RTLD_LAZY | RTLD_GLOBAL);
const char * libname = "library.so";
dl_iterate_phdr(callback, (void*)libname);
return 0;
}
Se hai bisogno di memorizzare quei nomi da qualche parte, puoi passare un puntatore al tuo contenitore, ripristinarlo con cast e scrivere lì.
Per la mia libreria di esempio:
#include "simple_lib.h"
#include <cstdio>
void __attribute__ ((constructor)) initLibrary(void)
{
printf("Library is initialized\n");
}
void __attribute__ ((destructor)) cleanUpLibrary(void)
{
printf("Library is exited\n");
}
void make_number()
{
printf("1\n");
}
Stampa questo:
Library is initialized
_ITM_deregisterTMCloneTable
puts
__gmon_start__
_ITM_registerTMCloneTable
__cxa_finalize
_Z11initLibraryv
make_number
_Z14cleanUpLibraryv
Library is exited
Non esiste una funzione libc per farlo. Tuttavia, puoi scriverne uno tu stesso (o copiare/incollare il codice da uno strumento come readelf).
Su Linux, dlopen()
restituisce l'indirizzo di un link_map
struttura, che ha un membro chiamato l_addr
che punta all'indirizzo di base dell'oggetto condiviso caricato (supponendo che il tuo sistema non randomizzi il posizionamento della libreria condivisa e che la tua libreria non sia stata precollegata).
Su Linux, un modo per trovare l'indirizzo di base (l'indirizzo di Elf*_Ehdr
) è usare dl_iterate_phdr()
dopo dlopen()
ing la libreria.
Avendo l'intestazione ELF, dovresti essere in grado di iterare su un elenco di simboli esportati (la tabella dei simboli dinamici), individuando prima Elf*_Phdr
di tipo PT_DYNAMIC
, quindi individuando DT_SYMTAB
, DT_STRTAB
voci e l'iterazione su tutti i simboli nella tabella dei simboli dinamici. Usa /usr/include/elf.h
per guidarti.
Inoltre, potresti usare libelf, che personalmente non conosco molto bene.
Tuttavia, tieni presente che otterrai un elenco di funzioni definite, ma non avrai idea di come chiamarle.