Как просмотреть информацию о карте памяти Linux на C?

#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 функция (при условии, что у вас есть некоторый адрес для начала).