#define _GNU_SOURCE #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; /* (null 文字で終端された) オブジェクト名 */ 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 は null 文字で終端された文字列であり、 このパス名のファイルから共有オブジェクトがロードされる。
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); }