Qual é a diferença de seção e segmento no formato de arquivo ELF

Do formato executável e vinculável do wiki:

Os segmentos contêm informações necessárias para a execução do tempo de execução do arquivo, enquanto as seções contêm dados importantes para vinculação e realocação. Qualquer byte no arquivo inteiro pode ser de propriedade de no máximo uma seção, e pode haver bytes órfãos que não pertencem a nenhuma seção.

Mas qual a diferença entre seção e segmento? Em um arquivo ELF executável, um segmento contém uma ou mais seções?

Mas qual a diferença entre seção e segmento?

Exatamente o que você citou: os segmentos contêm informações necessárias no tempo de execução, enquanto as seções contêm informações necessárias durante a vinculação.

um segmento contém uma ou mais seções?

Um segmento pode conter 0 ou mais seções. Exemplo:

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 RE 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 RE 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 

Aqui, o segmento PHDR contém 0 seções, o segmento INTERP contém a seção .interp e o primeiro segmento LOAD contém .interp seções.

Leitura adicional com uma boa ilustração .

A seção contém estática para o vinculador, segmenta dados dynamics para o sistema operacional

A cotação está correta, mas para realmente entender a diferença, você deve tentar entender os campos do header da seção e inputs do header do programa (segmento) e como eles são usados ​​pelo vinculador (seções) e pelo sistema operacional (segmento) .

Informações particularmente importantes são (além de comprimentos):

  • seção: informe ao vinculador se uma seção é:

    • dados brutos a serem carregados na memory, por exemplo .data , .text , etc.
    • ou metadados formatados sobre outras seções, que serão usados ​​pelo vinculador, mas desaparecerão em tempo de execução, por exemplo, .srttab , .rela.text , .rela.text
  • segmento: informa ao sistema operacional:

    • onde um segmento deve ser carregado na memory virtual
    • quais permissions os segmentos possuem (leia, escreva, execute). Lembre-se de que isso pode ser eficientemente imposto pelo processador: Como funciona a paginação x86?

Eu escrevi um tutorial que cobre isso com mais detalhes em: http://www.cirosantilli.com/elf-hello-world/

Um segmento contém uma ou mais seções?

Sim, e é o vinculador que coloca as seções em segmentos.

No Binutils, como as seções são colocadas em segmentos por ld é determinado por um arquivo de texto chamado script de vinculador . Documentos: https://sourceware.org/binutils/docs/ld/Scripts.html

Você pode obter o padrão com ld --verbose e definir um personalizado com -T .

Por exemplo, meu script de vinculador padrão do Ubuntu 17.04 contém:

  .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.*) } 

que diz ao linker para colocar seções chamadas .text.unlikely , .text.*_unlikely , .text.exit , etc. no segmento .text .

O desenvolvimento do sistema operacional é um caso em que scripts personalizados são úteis, exemplo mínimo: https://github.com/cirosantilli/x86-bare-metal-examples/blob/d217b180be4220a0b4a453f31275d38e697a99e0/linker.ld

Uma vez vinculado o executável, só é possível saber qual seção foi para qual segmento se o vinculador armazena o header de seção opcional no executável: Onde está o “Mapeamento de seção a segmento” armazenado em arquivos ELF?

Intereting Posts