MISE À JOUR | TL;DR :
En fait, j'ai trouvé un chemin plus court :
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);
}
}
ANCIEN
Je crois que l'auteur n'en a plus besoin mais peut-être que quelqu'un a besoin de code réel et le voici (basé sur la réponse précédente)
Tout d'abord, nous avons besoin d'un rappel pour 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;
}
Ensuite, nous appelons 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;
}
Si vous avez besoin de stocker ces noms quelque part, vous pouvez passer un pointeur vers votre conteneur, le restaurer avec cast et y écrire.
Pour mon exemple de bibliothèque :
#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");
}
Imprime ceci :
Library is initialized
_ITM_deregisterTMCloneTable
puts
__gmon_start__
_ITM_registerTMCloneTable
__cxa_finalize
_Z11initLibraryv
make_number
_Z14cleanUpLibraryv
Library is exited
Il n'y a pas de fonction libc pour faire cela. Cependant, vous pouvez en écrire un vous-même (ou copier/coller le code depuis un outil comme readelf).
Sous Linux, dlopen()
retourne l'adresse d'un link_map
structure, qui a un membre nommé l_addr
qui pointe vers l'adresse de base de l'objet partagé chargé (en supposant que votre système ne randomise pas le placement de la bibliothèque partagée et que votre bibliothèque n'a pas été préliée).
Sous Linux, un moyen de trouver l'adresse de base (l'adresse de Elf*_Ehdr
) est d'utiliser dl_iterate_phdr()
après dlopen()
la bibliothèque.
Avec l'en-tête ELF, vous devriez pouvoir parcourir une liste de symboles exportés (la table de symboles dynamiques), en localisant d'abord le Elf*_Phdr
de type PT_DYNAMIC
, puis en localisant DT_SYMTAB
, DT_STRTAB
entrées et en itérant sur tous les symboles de la table de symboles dynamiques. Utilisez /usr/include/elf.h
pour vous guider.
De plus, vous pouvez utiliser libelf, que je ne connais pas très bien personnellement.
Cependant, notez que vous obtiendrez une liste de fonctions définies, mais vous ne saurez pas comment les appeler.