GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Rufen Sie Funktionsnamen in einer gemeinsam genutzten Bibliothek programmgesteuert ab

AKTUALISIEREN | TL;DR :

Ich habe tatsächlich einen kürzeren Weg gefunden:

    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);
        }
    }

ALT

Ich glaube, der Autor braucht das nicht mehr, aber vielleicht braucht jemand aktuellen Code und hier ist er (basierend auf der vorherigen Antwort)

Zuerst brauchen wir einen Callback für 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;
}

Als nächstes rufen wir dl_iterate_phdr() auf :

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;
}

Wenn Sie diese Namen irgendwo speichern müssen, können Sie einen Zeiger auf Ihren Container übergeben, ihn mit Cast wiederherstellen und dort schreiben.

Für meine Beispielbibliothek:

#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");
}

Druckt dies:

Library is initialized

_ITM_deregisterTMCloneTable
puts
__gmon_start__
_ITM_registerTMCloneTable
__cxa_finalize
_Z11initLibraryv
make_number
_Z14cleanUpLibraryv
Library is exited

Dafür gibt es keine libc-Funktion. Sie können jedoch selbst einen schreiben (oder den Code aus einem Tool wie readelf kopieren/einfügen).

Unter Linux dlopen() gibt die Adresse von link_map zurück -Struktur, die ein Element namens l_addr hat die auf die Basisadresse des geladenen gemeinsamen Objekts zeigt (vorausgesetzt, Ihr System verteilt die Platzierung gemeinsam genutzter Bibliotheken nicht zufällig und Ihre Bibliothek wurde nicht vorverlinkt).

Unter Linux eine Möglichkeit, die Basisadresse zu finden (die Adresse von Elf*_Ehdr ) soll dl_iterate_phdr() verwenden nach dlopen() der Bibliothek.

Mit dem ELF-Header sollten Sie in der Lage sein, eine Liste exportierter Symbole (die dynamische Symboltabelle) zu durchlaufen, indem Sie zuerst Elf*_Phdr suchen vom Typ PT_DYNAMIC , und suchen Sie dann DT_SYMTAB , DT_STRTAB Einträge und Iterieren über alle Symbole in der dynamischen Symboltabelle. Verwenden Sie /usr/include/elf.h um Sie zu führen.

Zusätzlich könntest du libelf verwenden, das ich persönlich nicht sehr gut kenne.

Beachten Sie jedoch, dass Sie eine Liste definierter Funktionen erhalten, aber keine Ahnung haben, wie man sie aufruft.


Linux
  1. Geteilte Libsdl-Bibliothek lässt sich nicht öffnen?

  2. Konvertieren Sie eine statische Bibliothek in eine gemeinsam genutzte Bibliothek?

  3. So initialisieren Sie eine gemeinsam genutzte Bibliothek unter Linux

  4. Verbindungsgeschwindigkeit programmgesteuert abrufen?

  5. Wie kann ich die Liste der Funktionen anzeigen, die eine gemeinsam genutzte Linux-Bibliothek exportiert?

Beginnen Sie mit GNUPlot

Einführung in gemeinsam genutzte Linux-Bibliotheken (So erstellen Sie gemeinsam genutzte Bibliotheken)

Was sind Linux-Systemaufrufe und Bibliotheksfunktionen?

Statischer Link der gemeinsam genutzten Bibliotheksfunktion in gcc

Übergeordnete PID eines anderen Prozesses programmgesteuert abrufen?

Holen Sie sich eine Liste von Funktionsnamen in einem Shell-Skript