GNU/Linux >> Tutoriales Linux >  >> Linux

Obtener nombres de funciones en una biblioteca compartida mediante programación

ACTUALIZACIÓN | TL;RD:

De hecho, encontré una forma más corta:

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

ANTIGUO

Creo que el autor ya no necesita esto, pero tal vez alguien necesite un código real y aquí está (basado en la respuesta anterior)

Primero, necesitamos una devolución de llamada para 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;
}

A continuación, llamamos a 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 necesita almacenar esos nombres en algún lugar, puede pasar un puntero a su contenedor, restaurarlo con cast y escribir allí.

Para mi biblioteca de ejemplo:

#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 esto:

Library is initialized

_ITM_deregisterTMCloneTable
puts
__gmon_start__
_ITM_registerTMCloneTable
__cxa_finalize
_Z11initLibraryv
make_number
_Z14cleanUpLibraryv
Library is exited

No hay una función libc para hacer eso. Sin embargo, puede escribir uno usted mismo (o copiar/pegar el código de una herramienta como readelf).

En Linux, dlopen() devuelve la dirección de un link_map estructura, que tiene un miembro llamado l_addr que apunta a la dirección base del objeto compartido cargado (suponiendo que su sistema no aleatorice la ubicación de la biblioteca compartida y que su biblioteca no haya sido previnculada).

En Linux, una forma de encontrar la dirección base (la dirección de Elf*_Ehdr ) es usar dl_iterate_phdr() después de dlopen() en la biblioteca.

Con el encabezado ELF, debería poder iterar sobre una lista de símbolos exportados (la tabla de símbolos dinámicos), ubicando primero el Elf*_Phdr de tipo PT_DYNAMIC y luego ubicando DT_SYMTAB , DT_STRTAB entradas e iterando sobre todos los símbolos en la tabla de símbolos dinámicos. Utilice /usr/include/elf.h para guiarte.

Además, podría usar difamación, que no conozco muy bien personalmente.

Sin embargo, tenga en cuenta que obtendrá una lista de funciones definidas, pero no tendrá idea de cómo llamarlas.


Linux
  1. Cómo inicializar una biblioteca compartida en Linux

  2. ¿Obtener la velocidad del enlace mediante programación?

  3. ¿Cómo veo la lista de funciones que exporta una biblioteca compartida de Linux?

  4. No se puede encontrar el error de la biblioteca libcrypto

  5. Cómo configurar googleTest como una biblioteca compartida en Linux

Comience con GNUPlot

¿Qué son las llamadas al sistema Linux y las funciones de biblioteca?

¿Obtener programáticamente el id principal de otro proceso?

Obtener una lista de nombres de funciones en un script de shell

¿Cómo hacer el control de versiones de una biblioteca compartida en Linux?

¿Cómo verificar si una biblioteca compartida está instalada?