AKTUALIZACE | TL;DR:
Vlastně jsem našel kratší cestu:
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);
}
}
STARÝ
Věřím, že to autor už nepotřebuje, ale možná někdo potřebuje skutečný kód a tady je (na základě předchozí odpovědi)
Nejprve potřebujeme zpětné volání pro 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;
}
Dále zavoláme 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;
}
Pokud potřebujete tato jména někam uložit, můžete předat ukazatel do svého kontejneru, obnovit jej pomocí přetypování a zapsat tam.
Pro moji ukázkovou knihovnu:
#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");
}
Vytiskne toto:
Library is initialized
_ITM_deregisterTMCloneTable
puts
__gmon_start__
_ITM_registerTMCloneTable
__cxa_finalize
_Z11initLibraryv
make_number
_Z14cleanUpLibraryv
Library is exited
K tomu neexistuje žádná funkce libc. Můžete si ho však napsat sami (nebo zkopírovat/vložit kód z nástroje, jako je readelf).
V systému Linux dlopen()
vrátí adresu link_map
struktura, která má člen s názvem l_addr
která ukazuje na základní adresu načteného sdíleného objektu (za předpokladu, že váš systém neznáhodňuje umístění sdílené knihovny a že vaše knihovna nebyla předem propojena).
V Linuxu je způsob, jak zjistit základní adresu (adresa Elf*_Ehdr
) je použít dl_iterate_phdr()
po dlopen()
v knihovně.
Pokud máte hlavičku ELF, měli byste být schopni iterovat seznam exportovaných symbolů (tabulka dynamických symbolů) tak, že nejprve najdete Elf*_Phdr
typu PT_DYNAMIC
a poté vyhledejte DT_SYMTAB
, DT_STRTAB
záznamy a iterování přes všechny symboly v tabulce dynamických symbolů. Použijte /usr/include/elf.h
aby vás vedl.
Navíc můžete použít pomluvu, kterou osobně moc neznám.
Upozorňujeme však, že získáte seznam definovaných funkcí, ale nebudete mít ponětí, jak je volat.