#define _GNU_SOURCE /* feature_test_macros(7) 参照 */ #include <link.h> int dl_iterate_phdr( int (*callback) (struct dl_phdr_info *info, size_t size, void *data), void *data);
dl_iterate_phdr() 関数はアプリケーションの共有オブジェクトのリストを辿り、 各オブジェクトに対して関数 callback を 1 回ずつ呼び出す。 これは全ての共有オブジェクトが処理されるか、 callback が 0 以外の値を返すまで行われる。
各々の callback 呼び出しは 3 つの引き数を受け取る: info は共有オブジェクトの情報を保持する構造体へのポインターである。 size は info で指される構造体のサイズである。 data は呼び出し元プログラムから dl_iterate_phdr() の呼び出しの (同じく data という名前の) 第 2 引き数として渡される値のコピーである。
info 引き数は、以下のような型の構造体である。
struct dl_phdr_info { ElfW(Addr) dlpi_addr; /* オブジェクトのベースアドレス */ const char *dlpi_name; /* (ヌル文字で終端された) オブジェクト名 */ const ElfW(Phdr) *dlpi_phdr; /* このオブジェクトの ELF プログラムヘッダーの 配列へのポインター */ ElfW(Half) dlpi_phnum; /* dlpi_phdr のアイテム数 */ };
(ElfW() マクロ定義は引き数をハードウェアアーキテクチャーに適した ELF データ型の名前に変換する。 たとえば、32 ビットプラットフォームでは ElfW(Addr) はデータ型名 Elf32_Addr を生成する。 これらの型についての更に詳細な情報は、ヘッダーファイル <elf.h> と <link.h> にある。
dlpi_addr フィールドは共有オブジェクトのベースアドレス (つまり、共有オブジェクトの仮想メモリーアドレスと、 ファイル (このファイルから共有オブジェクトがロードされる) における 共有オブジェクトのオフセットとの差分) を表す。 dlpi_name はヌル文字で終端された文字列であり、 このパス名のファイルから共有オブジェクトがロードされる。
dlpi_phdr と dlpi_phnum フィールドの意味を理解するには、 ELF 共有オブジェクトが幾つかのセグメントから構成されていることと、 各セグメントがそれに対応するプログラムヘッダー (そのセグメントを説明する) を持っていることを知っている必要がある。 dlpi_phdr フィールドは、この共有オブジェクトのプログラムヘッダーの配列へのポインターである。 dlpi_phnum は、この配列のサイズを表す。
これらのプログラムヘッダーは以下のような形式の構造体である:
typedef struct { Elf32_Word p_type; /* セグメントの型 */ Elf32_Off p_offset; /* セグメントのファイルオフセット */ Elf32_Addr p_vaddr; /* セグメントの仮想アドレス */ Elf32_Addr p_paddr; /* セグメントの物理アドレス */ Elf32_Word p_filesz; /* ファイルにおけるセグメントサイズ */ Elf32_Word p_memsz; /* メモリーにおけるセグメントサイズ */ Elf32_Word p_flags; /* セグメントフラグ */ Elf32_Word p_align; /* セグメントの配置 (alignment) */ } Elf32_Phdr;
特定のプログラムヘッダー x の仮想メモリーにおける位置は、以下の式で計算できる点に注意すること:
addr == info->dlpi_addr + info->dlpi_phdr[x].p_vaddr;
#define _GNU_SOURCE #include <link.h> #include <stdlib.h> #include <stdio.h> static int callback(struct dl_phdr_info *info, size_t size, void *data) { int j; printf("name=%s (%d segments)\n", info->dlpi_name, info->dlpi_phnum); for (j = 0; j < info->dlpi_phnum; j++) printf("\t\t header %2d: address=%10p\n", j, (void *) (info->dlpi_addr + info->dlpi_phdr[j].p_vaddr)); return 0; } int main(int argc, char *argv[]) { dl_iterate_phdr(callback, NULL); exit(EXIT_SUCCESS); }
オンラインのいろいろな場所で入手できる Executable and Linking Format Specification