#c #linux #memory #ld #dlopen
#c #linux #память #ld #dlopen
Вопрос:
Я динамически загружаю некоторые библиотеки Linux на C. Я могу получить начальные адреса библиотек, используя
dlinfo
(см. 1).
Однако я не могу найти никакой информации, позволяющей получить размер библиотеки.
Единственное, что я обнаружил, это то, что нужно прочитать
/proc/[pid]/maps
создайте файл и проанализируйте его для получения соответствующей информации (см. 2). Есть ли более элегантный метод?
Комментарии:
1. Насколько я знаю, синтаксический анализ
maps
— самый простой метод. Почему, по вашему мнению, это не элегантно?2. По сравнению с простым выполнением следующего, возиться с синтаксическим анализом строк не очень приятно.
struct link_map *map; dlinfo(hLibrary, RTLD_DI_LINKMAP, amp;map); void* base = map->l_addr;
3. Существует
map->l_name
, и вы можете сделатьstat
на основе пути к библиотеке. Или вы можете попробовать покопаться в link_map поглубже и найти сегменты загруженного файла ELF.
Ответ №1:
(Этот ответ специфичен для LINUX / GLIBC)
Согласно http://s.eresi-project.org/inc/articles/elf-rtld.txt
есть link_map * map; map-> l_map_start amp; map-> l_map_end
/*
** Start and finish of memory map for this object.
** l_map_start need not be the same as l_addr.
*/
ElfW(Addr) l_map_start, l_map_end;
Это немного не точно, как сказано здесь http://www.cygwin.com/ml/libc-hacker/2007-06/msg00014.html
= некоторые библиотеки не являются непрерывными в памяти; в письме, на которое ссылается, есть несколько примеров … например, это очень внутренняя (для rtld) функция для определения, находится ли данный адрес внутри адресного пространства библиотеки или нет, на основе link_map и прямой работы с сегментами ELF:
/* Return non-zero if ADDR lies within one of L's segments. */
int
internal_function
_dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr)
{
int n = l->l_phnum;
const ElfW(Addr) reladdr = addr - l->l_addr;
while (--n >= 0)
if (l->l_phdr[n].p_type == PT_LOAD
amp;amp; reladdr - l->l_phdr[n].p_vaddr >= 0
amp;amp; reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz)
return 1;
return 0;
}
И эта функция является другой альтернативой, которая заключается в поиске заголовков программ / или разделов загруженного ELF (в link_map есть несколько ссылок на такую информацию)
И самый простой — использовать какой-нибудь stat
системный вызов с map->l_name
— для чтения размера файла с диска (неточно при обнаружении огромного раздела bss).
Ответ №2:
Синтаксический анализ /proc/self/maps
(или, возможно, popen
ввод pmap
команды) по-прежнему кажется мне самым простым. И есть также dladdr
функция (при условии, что у вас есть некоторый адрес для начала).