Quelle est la différence entre la section et le segment dans le format de fichier ELF?
de wiki format exécutable et liable :
les segments contiennent les informations nécessaires à l'exécution de l'exécution du fichier, tandis que les sections contiennent des données importantes pour le lien et le déplacement. N'importe quel octet dans le dossier entier peut être possédé par au plus une section, et il peut y avoir des octets orphelins qui ne sont pas possédés par n'importe quelle section.
mais quelle est la différence entre la section et segment? Dans un fichier ELF exécutable, un segment contient-il une ou plusieurs sections?
2 réponses
mais quelle est la différence entre la section et le segment?
exactement ce que vous avez cité: les segments contiennent les informations nécessaires à l'exécution, tandis que les sections contiennent les informations nécessaires lors du lien.
un segment contient-il une ou plusieurs sections?
un segment peut contenir 0 ou plus de sections. Exemple:
readelf -l /bin/date
Elf file type is EXEC (Executable file)
Entry point 0x402000
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000d5ac 0x000000000000d5ac R E 200000
LOAD 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x0000000000000440 0x0000000000000610 RW 200000
DYNAMIC 0x000000000000de38 0x000000000060de38 0x000000000060de38
0x00000000000001a0 0x00000000000001a0 RW 8
NOTE 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x0000000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0x000000000000c700 0x000000000040c700 0x000000000040c700
0x00000000000002a4 0x00000000000002a4 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 8
GNU_RELRO 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x00000000000001f0 0x00000000000001f0 R 1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
08 .ctors .dtors .jcr .dynamic .got
ici, Le segment PHDR
contient 0 sections, le segment INTERP
contient la section .interp
, et le premier segment LOAD
contient tout un tas de sections.
autre lecture avec une belle illustration .
Section contient statique pour l'éditeur de liens, le segment dynamique des données pour le système d'exploitation
le devis est correct, mais pour le comprendre réellement la différence, vous devriez essayer de comprendre les champs de l'en-tête de section et les entrées de l'en-tête de programme (segment), et comment ils sont utilisés par le linker (sections) et le système d'exploitation (segment).
les informations particulièrement importantes sont (outre les longueurs):
-
section: indiquer au linker si une section est:
- données brutes à charger en mémoire, p.ex.
.data
,.text
, etc. - ou des métadonnées formatées sur d'autres sections, qui seront utilisées par le linker, mais disparaîtront à l'exécution, par exemple
.symtab
,.srttab
,.rela.text
- données brutes à charger en mémoire, p.ex.
-
segment: indique le système d'exploitation:
- où un segment être chargé dans la mémoire virtuelle
- quelles permissions ont les segments (lire, écrire, exécuter). Rappelez-vous que cela peut être efficacement appliqué par le processeur: Comment fonctionne x86 paging?
j'ai écrit un tutoriel qui couvre cela plus en détail à: http://www.cirosantilli.com/elf-hello-world/
est-ce qu'un segment contient une ou plusieurs sections?
Oui, et c'est le linker qui met les sections en segments.
dans les Binutils, la façon dont les sections sont mises en segments par ld
est déterminée par un fichier texte appelé linker script . Docs: https://sourceware.org/binutils/docs/ld/Scripts.html
Vous pouvez obtenir la valeur par défaut avec ld --verbose
, et définir une valeur personnalisée avec -T
.
par exemple, mon script par défaut Ubuntu 17.04 contient:
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
}
qui dit au linker de mettre les sections nommées .text.unlikely
, .text.*_unlikely
, .text.exit
, etc. dans le segment .text
.
développement OS est un cas où les scripts personnalisés sont utiles, exemple minimal: https://github.com/cirosantilli/x86-bare-metal-examples/blob/d217b180be4220a0b4a453f31275d38e697a99e0/linker.ld
une fois que l'exécutable est lié, il n'est possible de savoir quelle section est passée à quel segment si le linker stocke l'en-tête de section optionnel dans l'exécutable: Où est la "section to segment mapping" stockée dans les fichiers ELF?