Karena saya memiliki kebutuhan yang sama untuk mengambil semua nama simbol yang dimuat saat runtime, saya melakukan penelitian berdasarkan jawaban R... Jadi, inilah solusi mendetail untuk pustaka bersama linux dalam format ELF yang berfungsi dengan gcc 4.3.4 saya, tetapi mudah-mudahan juga dengan versi yang lebih baru.
Saya kebanyakan menggunakan sumber berikut untuk mengembangkan solusi ini:
- Halaman ELF
- Beberapa contoh kode (ditemukan saat mencari "dl_iterate_phdr")
Dan ini kode saya. Saya menggunakan nama variabel yang menjelaskan sendiri dan menambahkan komentar mendetail agar dapat dimengerti. Jika ada yang salah atau hilang, beri tahu saya...(Sunting:Saya baru menyadari bahwa pertanyaannya adalah untuk C dan kode saya untuk C++. Tetapi jika Anda mengabaikan vektor dan string, itu juga akan berfungsi untuk C )
#include <link.h>
#include <string>
#include <vector>
using namespace std;
/* Callback for dl_iterate_phdr.
* Is called by dl_iterate_phdr for every loaded shared lib until something
* else than 0 is returned by one call of this function.
*/
int retrieve_symbolnames(struct dl_phdr_info* info, size_t info_size, void* symbol_names_vector)
{
/* ElfW is a macro that creates proper typenames for the used system architecture
* (e.g. on a 32 bit system, ElfW(Dyn*) becomes "Elf32_Dyn*") */
ElfW(Dyn*) dyn;
ElfW(Sym*) sym;
ElfW(Word*) hash;
char* strtab = 0;
char* sym_name = 0;
ElfW(Word) sym_cnt = 0;
/* the void pointer (3rd argument) should be a pointer to a vector<string>
* in this example -> cast it to make it usable */
vector<string>* symbol_names = reinterpret_cast<vector<string>*>(symbol_names_vector);
/* Iterate over all headers of the current shared lib
* (first call is for the executable itself) */
for (size_t header_index = 0; header_index < info->dlpi_phnum; header_index++)
{
/* Further processing is only needed if the dynamic section is reached */
if (info->dlpi_phdr[header_index].p_type == PT_DYNAMIC)
{
/* Get a pointer to the first entry of the dynamic section.
* It's address is the shared lib's address + the virtual address */
dyn = (ElfW(Dyn)*)(info->dlpi_addr + info->dlpi_phdr[header_index].p_vaddr);
/* Iterate over all entries of the dynamic section until the
* end of the symbol table is reached. This is indicated by
* an entry with d_tag == DT_NULL.
*
* Only the following entries need to be processed to find the
* symbol names:
* - DT_HASH -> second word of the hash is the number of symbols
* - DT_STRTAB -> pointer to the beginning of a string table that
* contains the symbol names
* - DT_SYMTAB -> pointer to the beginning of the symbols table
*/
while(dyn->d_tag != DT_NULL)
{
if (dyn->d_tag == DT_HASH)
{
/* Get a pointer to the hash */
hash = (ElfW(Word*))dyn->d_un.d_ptr;
/* The 2nd word is the number of symbols */
sym_cnt = hash[1];
}
else if (dyn->d_tag == DT_STRTAB)
{
/* Get the pointer to the string table */
strtab = (char*)dyn->d_un.d_ptr;
}
else if (dyn->d_tag == DT_SYMTAB)
{
/* Get the pointer to the first entry of the symbol table */
sym = (ElfW(Sym*))dyn->d_un.d_ptr;
/* Iterate over the symbol table */
for (ElfW(Word) sym_index = 0; sym_index < sym_cnt; sym_index++)
{
/* get the name of the i-th symbol.
* This is located at the address of st_name
* relative to the beginning of the string table. */
sym_name = &strtab[sym[sym_index].st_name];
symbol_names->push_back(string(sym_name));
}
}
/* move pointer to the next entry */
dyn++;
}
}
}
/* Returning something != 0 stops further iterations,
* since only the first entry, which is the executable itself, is needed
* 1 is returned after processing the first entry.
*
* If the symbols of all loaded dynamic libs shall be found,
* the return value has to be changed to 0.
*/
return 1;
}
int main()
{
vector<string> symbolNames;
dl_iterate_phdr(retrieve_symbolnames, &symbolNames);
return 0;
}
Pada sistem berbasis ELF yang terhubung secara dinamis, Anda mungkin memiliki fungsi dl_iterate_phdr
tersedia. Jika demikian, itu dapat digunakan untuk mengumpulkan informasi pada setiap file perpustakaan bersama yang dimuat, dan informasi yang Anda dapatkan cukup untuk memeriksa tabel simbol. Prosesnya pada dasarnya adalah:
- Dapatkan alamat tajuk program dari
dl_phdr_info
struktur diteruskan kembali kepada Anda. - Gunakan
PT_DYNAMIC
tajuk program untuk menemukan_DYNAMIC
tabel untuk modul. - Gunakan
DT_SYMTAB
,DT_STRTAB
, danDT_HASH
entri_DYNAMIC
untuk menemukan daftar simbol.DT_HASH
hanya diperlukan untuk mendapatkan panjang tabel simbol, karena tampaknya tidak disimpan di tempat lain.
Jenis yang Anda butuhkan semuanya harus ada di <elf.h>
dan <link.h>
.
Ini sebenarnya bukan khusus C, tetapi sistem operasi dan format biner dan (untuk simbol debugging dan nama simbol C++ yang tidak terurai) bahkan pertanyaan khusus kompiler. Tidak ada cara umum, dan juga tidak ada cara yang benar-benar elegan.
Cara yang paling portabel dan tahan masa depan mungkin adalah menjalankan program eksternal seperti nm
, yang ada di POSIX. Versi GNU yang ditemukan di Linux mungkin memiliki banyak ekstensi, yang harus Anda hindari jika Anda menginginkan portabilitas dan bukti masa depan.
Keluarannya harus tetap stabil, dan bahkan jika format biner berubah, itu juga akan diperbarui dan tetap berfungsi. Jalankan saja dengan sakelar yang tepat, tangkap hasilnya (mungkin dengan menjalankannya melalui popen
untuk menghindari file temp) dan menguraikannya.