смещение файла и виртуальный адрес в общей библиотеке

Для файла общей библиотеки, как преобразовать смещение файла и виртуальный адрес определения символа?

В документе ELF для символа в таблице символов

В исполняемых и общих объектных файлах st_value содержит виртуальный адрес. Чтобы сделать символы этих файлов более полезными для динамического компоновщика, смещение раздела (интерпретация файла) уступает место виртуальному адресу (интерпретация памяти), для которого номер раздела не имеет значения.

Но как я могу получить соответствующее смещение в файле? Или, учитывая смещение, как я могу вычислить виртуальный адрес (интерпретацию файла в интерпретацию памяти)?

Представьте себе такой сценарий. Во время выполнения процесса предположим, что он использует функцию, реализованную в разделяемой библиотеке, скажем, libx.so, и что файл библиотеки отображается в область, представленную vma.

//addr holds the value of PC
offset = (vma->vm_pgoff << PAGE_SIZE) + addr -vma->vm_start;

Насколько я понял, теперь offset содержит смещение инструкции в библиотечном файле. Учитывая это смещение, я хотел бы знать имя функции. Один из способов — вычислить виртуальный адрес, соответствующий offset, и сравнить виртуальный адрес с st_value в таблице символов. Если st_value обрабатываются для хранения в порядке возрастания, то st_value_1 < virtual_address < st_value_2 означает, что st_name_1 — это то, что я ищу. Таким образом, проблема заключается в преобразовании.
Для справки, структура данных записи таблицы символов:

typedef struct{
  Elf32_Word     st_name; 
  Elf32_Addr     st_value;
  Elf32_Word     st_size;
  unsigned char  st_info;
  unsigned char  st_other;
  Elf32_Half     st_shndx;
}Elf32_Sym;

person dudu    schedule 11.10.2017    source источник
comment
Вы знаете о GOT и PLT? Не уверен, что понимаю ваш точный вопрос, но я считаю, что лекция htwsl может помочь вам понять некоторые понятия, которые здесь отсутствуют,   -  person Tomasz Andel    schedule 12.10.2017
comment
Если st_values ​​обрабатываются для хранения в порядке возрастания, то st_value_1 ‹ виртуальный_адрес ‹ st_value_2 означает, что st_name_1 — это то, что я ищу.: Вы должны использовать длину символа, чтобы узнать размер функции. Между st_value1 и st_value2 могут быть другие вещи (функции, отсутствующие в таблице suymbol).*   -  person ysdx    schedule 17.10.2017
comment
@ysdx Согласно документации ELF, для объектов данных st_size — это количество байтов, содержащихся в объекте. Но я думаю, что это правило не работает для функций. Для символов, являющихся функциями, st_size ненадежен, и я не могу найти способ получить размер функции.   -  person dudu    schedule 17.10.2017
comment
Да, действительно, неясно, что может означать st_size для символа STT_FUNC. И не обязательно иметь ненулевое значение.   -  person ysdx    schedule 17.10.2017


Ответы (1)


Записи в таблицах заголовков программы PT_LOAD определяют, как загрузчик/компоновщик должен отображать части файла ELF в виртуальном адресном пространстве. Вы должны использовать это, если хотите преобразовать смещение файла и (относительные) адреса виртуальной памяти:

~$ readelf -l /lib/i386-linux-gnu/libc-2.24.so 

Elf file type is DYN (Shared object file)
Entry point 0x18400
There are 10 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x00000034 0x00000034 0x00140 0x00140 R E 0x4
  INTERP         0x166374 0x00166374 0x00166374 0x00013 0x00013 R   0x4
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x00000000 0x00000000 0x1b01c8 0x1b01c8 R E 0x1000
  LOAD           0x1b0260 0x001b1260 0x001b1260 0x02c74 0x0579c RW  0x1000
  DYNAMIC        0x1b1db0 0x001b2db0 0x001b2db0 0x000f0 0x000f0 RW  0x4
  NOTE           0x000174 0x00000174 0x00000174 0x00044 0x00044 R   0x4
  TLS            0x1b0260 0x001b1260 0x001b1260 0x00008 0x00048 R   0x4
  GNU_EH_FRAME   0x166388 0x00166388 0x00166388 0x061ec 0x061ec R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x1b0260 0x001b1260 0x001b1260 0x01da0 0x01da0 R   0x1

Например, рассматривая этот символ

   Num:    Value  Size Type    Bind   Vis      Ndx Name
   188: 0005df80    35 FUNC    GLOBAL DEFAULT   13 fopen@@GLIBC_2.1

Его (относительный) виртуальный адрес 0x0005df80. Он принадлежит первой записи PT_LOAD, которая находится в относительной виртуальной памяти от 0x00000000 до 0x00000000 + 0x1b01c8. Его смещение внутри сегмента равно Value - VirtAddr = 0x00000000. Таким образом, его смещение в файле равно PhysAddr + (Value - VirtAddr) = 0005df80.

person ysdx    schedule 17.10.2017