ОБЗОР
#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() позволяет приложению во время выполнения узнать, какие общие объекты были загружены.Функция dl_iterate_phdr() обходит список общих объектов приложения и однократно вызывает функцию callback для каждого объекта до тех пор, пока или все общие объекты не будут просмотрены, или функция callback не вернёт ненулевое значение.
При каждом вызове в callback передаётся три параметра: info (указатель на структуру с информацией об общем объекте), size (размер структуры, на которую указывает info) и data (копия любого значения, переданного вызывающей программой во втором параметре (также называемом data) в вызов dl_iterate_phdr().
Параметр 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; /* выравнивание сегмента */ } Elf32_Phdr;
Заметим, что мы можем вычислить расположение определённого программного заголовка x в виртуальной памяти по следующей формуле:
addr == info->dlpi_addr + info->dlpi_phdr[x].p_vaddr;
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Функция dl_iterate_phdr() возвращает значение, которое было получено в результате последнего вызова callback.ВЕРСИИ
Функция dl_iterate_phdr() доступна в glibc начиная с версии 2.2.4.АТРИБУТЫ
Описание терминов данного раздела смотрите в attributes(7).Интерфейс | Атрибут | Значение |
dl_iterate_phdr() | безвредность в нитях | безвредно (MT-Safe) |
СООТВЕТСТВИЕ СТАНДАРТАМ
Функция dl_iterate_phdr() не описана в каком-либо стандарте. Эта функция есть в некоторых других системах, при чём возвращаемая структура dl_phdr_info имеет другой формат. В BSD и Solaris, в структуре есть поля dlpi_addr, dlpi_name, dlpi_phdr и dlpi_phnum (помимо других внесённых реализацией полей).ЗАМЕЧАНИЯ
В будущих версиях библиотеки C в структуре dl_phdr_info могут появиться дополнительные поля; для этого случая предусмотрен аргумент size, который предоставляет вызываемой функции механизм обнаружения того, что она работает в системе с добавленными полями.ПРИМЕР
Следующая программа выводит список путей общий объектов, из которых они были загружены. Для каждого общего объекта программа показывает виртуальный адрес, по которому загружены сегменты ELF объекта.
#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("имя=%s (%d сегментов)\n", info->dlpi_name, info->dlpi_phnum); for (j = 0; j < info->dlpi_phnum; j++) printf("\t\t заголовок %2d: адрес=%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); }