更新 | TL;DR :
私は実際にもっと短い方法を見つけました:
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);
}
}
古い
作者はもうこれを必要としないと思いますが、おそらく誰かが実際のコードを必要としており、ここにあります(以前の回答に基づく)
まず、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;
}
次に、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;
}
これらの名前をどこかに保存する必要がある場合は、ポインターをコンテナーに渡し、キャストで復元してそこに書き込むことができます。
サンプル ライブラリの場合:
#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");
}
これを印刷します:
Library is initialized
_ITM_deregisterTMCloneTable
puts
__gmon_start__
_ITM_registerTMCloneTable
__cxa_finalize
_Z11initLibraryv
make_number
_Z14cleanUpLibraryv
Library is exited
それを行う libc 関数はありません。ただし、自分で作成することもできます (または、readelf などのツールからコードをコピーして貼り付けることもできます)。
Linux では、dlopen()
link_map
のアドレスを返します l_addr
という名前のメンバーを持つ構造体 これは、ロードされた共有オブジェクトのベース アドレスを指します (システムが共有ライブラリの配置をランダム化せず、ライブラリが事前にリンクされていないと仮定します)。
Linux では、ベース アドレス (Elf*_Ehdr
のアドレス) を見つける方法 ) は dl_iterate_phdr()
を使用することです dlopen()
以降
ELF ヘッダーがあれば、最初に Elf*_Phdr
を見つけて、エクスポートされたシンボルのリスト (動的シンボル テーブル) を反復処理できるはずです。 タイプ PT_DYNAMIC
の 、そして DT_SYMTAB
を見つけます 、 DT_STRTAB
エントリ、および動的シンボル テーブル内のすべてのシンボルを反復処理します。 /usr/include/elf.h
を使用
さらに、個人的によく知らない libelf を使用することもできます。
ただし、定義済み関数のリストは取得できますが、それらを呼び出す方法がわからないことに注意してください。