Файл ELF (исполняемый файл Unix или разделяемый объект) имеет две основные концепции:
Раздел: Область внутри исполняемого файла с определенной ролью c , Внутри файла ELF могут быть разные разделы (можно увидеть в man elf ). Общие разделы в файле ELF:
.text
(SHT_PROGBITS): фактический исполняемый код в файле ELF. .dynsym
(SHT_DYNSYM): содержит информацию о символах который должен быть извлечен динамически. .rela.dyn
и .rela.plt
(SHT_RELA): содержит информацию о перемещении для динамического компоновщика c, используемого при загрузке файла ELF в память. .dynamic
(SHT_DYNAMI C): содержит информацию для динамического компоновщика c, такую как другие зависимости, смещения для различных секций во время выполнения и т. Д. c. .symtab
(SHT_SYMTAB) : Содержит таблицу символов. .strtab
(SHT_STRTAB): содержит таблицу строк.
Есть несколько разделов, а приведенные выше являются лишь несколькими общими.
Используя readelf
, можно увидеть все разделы в файле ELF:
readelf --sections -W <file>
Выполнение этой команды для общего объекта на моем компьютере приводит к следующему выводу (упрощенно):
There are 29 section headers, starting at offset 0x1898:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
...
[ 3] .dynsym DYNSYM 0000000000000230 000230 000168 18 A 4 2 8
[ 4] .dynstr STRTAB 0000000000000398 000398 0000b0 00 A 0 0 1
...
[ 7] .rela.dyn RELA 0000000000000488 000488 0000c0 18 A 3 0 8
[ 8] .rela.plt RELA 0000000000000548 000548 000030 18 AI 3 22 8
...
[12] .text PROGBITS 00000000000005e0 0005e0 000121 00 AX 0 0 16
...
[20] .dynamic DYNAMIC 0000000000200e18 000e18 0001c0 10 WA 4 0 8
...
[23] .data PROGBITS 0000000000201028 001028 000008 00 WA 0 0 8
...
[27] .symtab SYMTAB 0000000000000000 001068 000570 18 28 45 8
[28] .strtab STRTAB 0000000000000000 0015d8 0001c6 00 0 0 1
Сегмент: Область внутри исполняемого файла с loa d инструкция для динамического компоновщика c. Это означает, что сегмент - это просто область внутри ELF-файла, которая должна быть загружена в предпочтительную адресную память и имеет определенные c права доступа, выравнивание и т. Д. c.
Каждый раздел (который является областью в файле ELF с логической ролью) должен быть частью сегмента, с правильными разрешениями и характеристиками. Сегмент может иметь более одного раздела внутри, а раздел находится внутри одного сегмента (отношение один ко многим).
Используя readelf
, можно увидеть все сегменты в файле ELF:
readelf --segments -W <file>
Выполнение этой команды на разделяемом объекте на моем компьютере приводит к следующему выводу:
There are 7 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x00079c 0x00079c R E 0x200000
LOAD 0x000e00 0x0000000000200e00 0x0000000000200e00 0x000230 0x000238 RW 0x200000
DYNAMIC 0x000e18 0x0000000000200e18 0x0000000000200e18 0x0001c0 0x0001c0 RW 0x8
NOTE 0x0001c8 0x00000000000001c8 0x00000000000001c8 0x000024 0x000024 R 0x4
GNU_EH_FRAME 0x000718 0x0000000000000718 0x0000000000000718 0x00001c 0x00001c R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x000e00 0x0000000000200e00 0x0000000000200e00 0x000200 0x000200 R 0x1
Section to Segment mapping:
Segment Sections...
00 .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame
01 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
02 .dynamic
03 .note.gnu.build-id
04 .eh_frame_hdr
05
06 .init_array .fini_array .jcr .dynamic .got
Здесь мы видим, что все разделы, связанные с исполняемым кодом, а также многие разделы, связанные с динамической загрузкой файла c, находятся в сегменте 00 (PT_LOAD), который имеет права на чтение и выполнение (R E
). Разделы, которые должны быть изменены загрузчиком, находятся в сегменте 01 (PT_LOAD), который имеет разрешения на чтение и запись (RW
). Сегмент 02 имеет тип PT_DYNAMI C и содержит динамическую c информацию о связывании - секцию .dynamic
.
Линкер Dynami c учитывает всю эту информацию, когда загружает файл ELF в память , Он загружает различные сегменты файла ELF с диска в память и защищает их страницы с правильными разрешениями. Затем он перебирает различные разделы и использует их в соответствии с их ролями (перемещения, разрешение динамических c символов и т. Д. c ...).
Сама защита памяти создается ОС и само оборудование. Это похоже на использование Linux методов mprotect () . Более подробную информацию о защите памяти можно найти здесь .