GNU/Linux >> Linux の 問題 >  >> Linux

Linux アーキテクチャの C コードで利用可能なすべての関数/シンボルをオンザフライで一覧表示する方法は?

実行時にロードされたすべてのシンボル名を取得する必要があったため、R..の回答に基づいていくつかの調査を行いました。ここでは、私の gcc 4.3.4 で動作する ELF 形式の Linux 共有ライブラリの詳細なソリューションを示しますが、新しいバージョンでも動作することを願っています。

このソリューションを開発するために、主に次のソースを使用しました:

  • ELF マンページ
  • サンプル コード (「dl_iterate_phdr」の検索中に見つかりました)

そして、これが私のコードです。わかりやすい変数名を使用し、わかりやすいように詳細なコメントを追加しました。何かが間違っているか不足している場合は、私に知らせてください... )

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

動的にリンクされた ELF ベースのシステムでは、関数 dl_iterate_phdr がある場合があります 利用可能。その場合、それを使用して、ロードされた各共有ライブラリ ファイルに関する情報を収集できます。得られた情報は、シンボル テーブルを調べるのに十分です。プロセスは基本的に次のとおりです。

<オール>
  • dl_phdr_info からプログラム ヘッダーのアドレスを取得します。 構造があなたに返されます。
  • PT_DYNAMIC を使用 _DYNAMIC を見つけるためのプログラム ヘッダー モジュールのテーブル
  • DT_SYMTAB を使用する 、 DT_STRTAB 、および DT_HASH _DYNAMIC のエントリ シンボルのリストを見つける。 DT_HASH 他の場所には保存されていないように見えるため、シンボル テーブルの長さを取得するためだけに必要です。
  • 必要な型はすべて <elf.h> である必要があります および <link.h> .


    これは実際には C 固有のものではありませんが、オペレーティング システムとバイナリ形式、および (デバッグ シンボルとマングルされていない C++ シンボル名について) コンパイラ固有の質問です。一般的な方法も真にエレガントな方法もありません。

    最も移植性が高く将来性のある方法は、おそらく nm などの外部プログラムを実行することです 、これは POSIX にあります。 Linux で見られる GNU バージョンにはおそらく拡張機能が多数含まれているため、移植性と将来性を重視する場合は避けるべきです。

    その出力は安定している必要があり、バイナリ形式が変更された場合でも、更新されて機能し続けます。正しいスイッチで実行し、その出力をキャプチャします (おそらく popen を介して実行します) 一時ファイルを回避するため)、それを解析します。


    Linux
    1. Linux ですべてのスパース ファイルを見つける方法

    2. Linux グループ内のすべてのユーザーを一覧表示する方法は?

    3. Linux 共有ライブラリがエクスポートしている関数のリストを表示するにはどうすればよいですか?

    1. RHEL7Linuxで使用可能なすべてのロケールを一覧表示する方法

    2. Linuxで開いているすべてのポートのリストを見つける方法

    3. Linuxでパッケージの依存関係を一覧表示する方法

    1. Linuxにインストールされているすべてのパッケージを一覧表示する方法

    2. Linux でロックされているすべてのユーザーを一覧表示するにはどうすればよいですか?

    3. Linuxでパーティションのすべてのファイルを一覧表示する方法は?