mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 21:06:06 +00:00

(#79887) When the offset of a PT_INTERP segment equals the offset of a PT_LOAD segment, we consider that the parent of the PT_LOAD segment is the PT_INTERP segment. In `layoutSegments`, we place both segments to be after the current `Offset`, ignoring the PT_LOAD alignment. This scenario is possible with fixed section addresses, but doesn't happen with default linker layouts (.interp precedes other sections and is part of a PT_LOAD segment containing the ELF header and program headers). ``` % cat a.s .globl _start; _start: ret .rodata; .byte 0 .tdata; .balign 4096; .byte 0 % clang -fuse-ld=lld a.s -o a -nostdlib -no-pie -z separate-loadable-segments -Wl,-Ttext=0x201000,--section-start=.interp=0x202000,--section-start=.rodata=0x202020,-z,nognustack % llvm-objcopy a a2 % llvm-readelf -l a2 # incorrect offset(PT_LOAD) Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000040 0x0000000000200040 0x0000000000200040 0x0001c0 0x0001c0 R 0x8 INTERP 0x001001 0x0000000000202000 0x0000000000202000 0x00001c 0x00001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x000000 0x0000000000200000 0x0000000000200000 0x000200 0x000200 R 0x1000 LOAD 0x001000 0x0000000000201000 0x0000000000201000 0x000001 0x000001 R E 0x1000 //// incorrect offset LOAD 0x001001 0x0000000000202000 0x0000000000202000 0x000021 0x000021 R 0x1000 LOAD 0x002000 0x0000000000203000 0x0000000000203000 0x000001 0x001000 RW 0x1000 TLS 0x002000 0x0000000000203000 0x0000000000203000 0x000001 0x000001 R 0x1000 GNU_RELRO 0x002000 0x0000000000203000 0x0000000000203000 0x000001 0x001000 R 0x1000 ``` The same issue occurs for PT_TLS/PT_GNU_RELRO if we PT_TLS's alignment is smaller and we place the PT_LOAD after PT_TLS/PT_GNU_RELRO segments (not linker default, but possible with a `PHDRS` linker script command). Fix #79887: when two segments have the same offset, order the one with a larger alignment first. In the previous case, the PT_LOAD segment will go before the PT_INTERP segment. In case of equal alignments, it doesn't matter which segment is treated as the parent segment.