Механизм сопоставления PT_LOADLinux

Ответить
Anonymous
 Механизм сопоставления PT_LOAD

Сообщение Anonymous »

Сейчас я играю с эльфийскими файлами. Меня смущает то, как сегменты PT_LOAD загружаются в память. Я имею в виду, как используются p_offset, p_filesz, p_vaddr и p_memsz.
Во-первых, это вывод заголовка моей программы с использованием **readelf**: =

Код: Выделить всё

➜  ~ readelf -l /usr/bin/cat

Elf file type is DYN (Shared object file)
Entry point 0x31f0
There are 13 program headers, starting at offset 64

Program Headers:
Type           Offset             VirtAddr           PhysAddr
FileSiz            MemSiz              Flags  Align
PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000002d8 0x00000000000002d8  R      0x8
INTERP         0x0000000000000318 0x0000000000000318 0x0000000000000318
0x000000000000001c 0x000000000000001c  R      0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
0x00000000000016e0 0x00000000000016e0  R      0x1000
LOAD           0x0000000000002000 0x0000000000002000 0x0000000000002000
0x0000000000004431 0x0000000000004431  R E    0x1000
LOAD           0x0000000000007000 0x0000000000007000 0x0000000000007000
0x00000000000021d0 0x00000000000021d0  R      0x1000
LOAD           0x0000000000009a90 0x000000000000aa90 0x000000000000aa90
0x0000000000000630 0x00000000000007c8  RW     0x1000
DYNAMIC        0x0000000000009c38 0x000000000000ac38 0x000000000000ac38
0x00000000000001f0 0x00000000000001f0  RW     0x8
NOTE           0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000020 0x0000000000000020  R      0x8
NOTE           0x0000000000000358 0x0000000000000358 0x0000000000000358
0x0000000000000044 0x0000000000000044  R      0x4
GNU_PROPERTY   0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000020 0x0000000000000020  R      0x8
GNU_EH_FRAME   0x000000000000822c 0x000000000000822c 0x000000000000822c
0x00000000000002bc 0x00000000000002bc  R      0x4
GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000  RW     0x10
GNU_RELRO      0x0000000000009a90 0x000000000000aa90 0x000000000000aa90
0x0000000000000570 0x0000000000000570  R      0x1

Section to Segment mapping:
Segment Sections...
00
01     .interp
02     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
03     .init .plt .plt.got .plt.sec .text .fini
04     .rodata .eh_frame_hdr .eh_frame
05     .init_array .fini_array .data.rel.ro .dynamic .got .data .bss
06     .dynamic
07     .note.gnu.property
08     .note.gnu.build-id .note.ABI-tag
09     .note.gnu.property
10     .eh_frame_hdr
11
12     .init_array .fini_array .data.rel.ro .dynamic .got
В приведенном выше выводе я вижу четыре сегмента LOAD. Я использую GDB, чтобы начать исследовать, как эти четыре сегмента отображаются в памяти. Я запускаю программу и проверяю сопоставления процессов следующим образом:

Код: Выделить всё

(gdb) shell cat /proc/18331/maps
555555554000-555555556000 r--p 00000000 103:03 3276961                   /usr/bin/cat
555555556000-55555555b000 r-xp 00002000 103:03 3276961                   /usr/bin/cat
55555555b000-55555555e000 r--p 00007000 103:03 3276961                   /usr/bin/cat
55555555e000-555555560000 rw-p 00009000 103:03 3276961                   /usr/bin/cat
7ffff7fc9000-7ffff7fcd000 r--p 00000000 00:00 0                          [vvar]
7ffff7fcd000-7ffff7fcf000 r-xp 00000000 00:00 0                          [vdso]
7ffff7fcf000-7ffff7fd0000 r--p 00000000 103:03 3325699                   /usr/lib/x86_64-linux-gnu/ld-2.31.so
7ffff7fd0000-7ffff7ff3000 r-xp 00001000 103:03 3325699                   /usr/lib/x86_64-linux-gnu/ld-2.31.so
7ffff7ff3000-7ffff7ffb000 r--p 00024000 103:03 3325699                   /usr/lib/x86_64-linux-gnu/ld-2.31.so
7ffff7ffc000-7ffff7ffe000 rw-p 0002c000 103:03 3325699                   /usr/lib/x86_64-linux-gnu/ld-2.31.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
Давайте посмотрим на четвертый сегмент: из сопоставлений процессов я вижу, что это сегмент размером 0x2000 байт со смещением 0x9000 из файла /usr/bin/cat. Что меня смущает, так это разница между p_offset (0x9a90) и p_vaddr (0xaa90).
Прочитав много материалов, я думаю, что потому, что p_offset этого сегмента равен 0x9a90, что означает, что он будет находиться на той же странице, что и предыдущий сегмент. Таким образом, p_vaddr перемещается на 0x1000 байт вперед, чтобы его можно было поместить на другую страницу. Это означает, что фактический адрес, используемый для mmap, будет рассчитываться с помощью смещения плюс p_vaddr, округленного до ближайшего начального адреса страницы. Смещение рассчитывается по формуле p_offset минус p_offset mod p_align. При этом длина mmap будет вычисляться с помощью p_filesz плюс мод p_offset p_align:

Код: Выделить всё

mmap(PAGESTART(bias + p_vaddr), PAGE_ALIGN(p_filesz + p_offset mod p_align), FLAGS , p_offset - p_offset mod p_align)
И вот мой первый вопрос: верно ли приведенное выше предположение?
Двигаясь дальше, в четвертом сегменте я вижу множество разделов:

Код: Выделить всё

.init_array .fini_array .data.rel.ro .dynamic .got .data .bss
Я проверяю это с помощью objdump, результат следующий:

Код: Выделить всё

➜  ~ objdump --disassemble-all /usr/bin/cat --start-address=0x9000 --stop-address=0xd000

/usr/bin/cat:     file format elf64-x86-64

Disassembly of section .eh_frame:

0000000000009000 :

Disassembly of section .init_array:

000000000000aa90 :
...

Disassembly of section .fini_array:

000000000000aa98 :
...

Disassembly of section .data.rel.ro:

000000000000aaa0 :
...
Дело в том, что раздел .init_array начинается с адреса 0xaa90 (это p_vaddr), а не так, как я ожидал. Я думаю, что этот раздел должен начинаться с 0x9a90, что соответствует p_offset этого сегмента.
Итак, если смещение 0x9000 и размер этого раздела 0x2000, не означает ли это, что Я полностью пропущу некоторые байты из этого сегмента (mmap отображает только адреса от 0x9000 до 0xB000, однако .init_array начинается с 0xaa90, что означает, что сегмент должен заканчиваться на 0xaa90 + p_filesz = 0xaa90 + 0x630 = 0xb0c0) ?

Подробнее здесь: https://stackoverflow.com/questions/784 ... -mechanism
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Linux»