GNU/Linux >> Belajar Linux >  >> Linux

Bagaimana cara mendaftar dengan cepat semua fungsi/simbol yang tersedia dalam kode C pada arsitektur Linux?

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:

  1. Dapatkan alamat tajuk program dari dl_phdr_info struktur diteruskan kembali kepada Anda.
  2. Gunakan PT_DYNAMIC tajuk program untuk menemukan _DYNAMIC tabel untuk modul.
  3. Gunakan DT_SYMTAB , DT_STRTAB , dan DT_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.


Linux
  1. Cara membuat daftar semua lokal yang tersedia di RHEL7 Linux

  2. Bagaimana cara mendaftar semua pengguna dalam grup Linux?

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

  1. Cara Mengetahui Daftar Semua Port Terbuka di Linux

  2. Bagaimana saya bisa mendaftar semua pengguna yang terkunci di Linux?

  3. Bagaimana cara mendaftar semua file partisi di linux?

  1. Cara Mendaftar Ketergantungan Paket Di Linux

  2. Cara Mendaftar Semua Paket yang Terinstal Di Linux

  3. Bagaimana menemukan semua file yang jarang di Linux