GNU/Linux >> Znalost Linux >  >> Linux

Získejte názvy funkcí ve sdílené knihovně programově

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.


Linux
  1. Dynamická sdílená knihovna C++ v systému Linux

  2. Převést statickou knihovnu na sdílenou?

  3. Statický odkaz funkce sdílené knihovny v gcc

  1. Programově získat nadřazené pid jiného procesu?

  2. Jak inicializovat sdílenou knihovnu v Linuxu

  3. Získejte seznam názvů funkcí ve skriptu shellu

  1. Úvod do sdílených knihoven Linuxu (Jak vytvořit sdílené knihovny)

  2. Nelze najít chybu knihovny libcrypto

  3. Jak zkontrolovat, zda je nainstalována sdílená knihovna?