GNU/Linux >> Belajar Linux >  >> Linux

Dapatkan nama fungsi di pustaka bersama secara terprogram

PEMBARUAN | TL;DR :

Saya sebenarnya menemukan cara yang lebih pendek:

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

LAMA

Saya yakin penulis tidak membutuhkan ini lagi, tetapi mungkin seseorang memerlukan kode aktual dan ini dia (berdasarkan jawaban sebelumnya)

Pertama, kita membutuhkan callback untuk 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;
}

Selanjutnya, kita panggil 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;
}

Jika Anda perlu menyimpan nama tersebut di suatu tempat, Anda dapat meneruskan penunjuk ke penampung, memulihkannya dengan cast, dan menulis di sana.

Untuk perpustakaan contoh saya:

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

Mencetak ini:

Library is initialized

_ITM_deregisterTMCloneTable
puts
__gmon_start__
_ITM_registerTMCloneTable
__cxa_finalize
_Z11initLibraryv
make_number
_Z14cleanUpLibraryv
Library is exited

Tidak ada fungsi libc untuk melakukan itu. Namun, Anda dapat menulisnya sendiri (atau menyalin/menempelkan kode dari alat seperti readelf).

Di Linux, dlopen() mengembalikan alamat link_map struktur, yang memiliki anggota bernama l_addr yang menunjuk ke alamat dasar dari objek bersama yang dimuat (dengan asumsi sistem Anda tidak mengacak penempatan pustaka bersama, dan bahwa pustaka Anda belum ditautkan sebelumnya).

Di Linux, cara untuk menemukan alamat dasar (alamat Elf*_Ehdr ) adalah menggunakan dl_iterate_phdr() setelah dlopen() di perpustakaan.

Memiliki header ELF, Anda seharusnya dapat mengulang daftar simbol yang diekspor (tabel simbol dinamis), dengan terlebih dahulu menempatkan Elf*_Phdr dengan tipe PT_DYNAMIC , lalu temukan DT_SYMTAB , DT_STRTAB entri, dan mengulangi semua simbol dalam tabel simbol dinamis. Gunakan /usr/include/elf.h untuk memandu Anda.

Selain itu, Anda dapat menggunakan pencemaran nama baik, yang secara pribadi tidak terlalu saya kenal.

Namun, perhatikan bahwa Anda akan mendapatkan daftar fungsi yang ditentukan, tetapi Anda tidak tahu cara memanggilnya.


Linux
  1. Pustaka Libsdl Bersama Gagal Dibuka?

  2. Secara terprogram dapatkan induk pid dari proses lain?

  3. Cara menginisialisasi perpustakaan bersama di Linux

  1. Dapatkan kecepatan tautan secara terprogram?

  2. Bagaimana cara melihat daftar fungsi yang diekspor oleh perpustakaan bersama Linux?

  3. Tidak dapat menemukan kesalahan perpustakaan libcrypto

  1. Cara mengatur googleTest sebagai perpustakaan bersama di Linux

  2. Bagaimana saya bisa menautkan ke versi lama dari perpustakaan bersama

  3. Galat Memuat Pustaka Bersama (glew)