Index: lld/trunk/ELF/LinkerScript.cpp =================================================================== --- lld/trunk/ELF/LinkerScript.cpp +++ lld/trunk/ELF/LinkerScript.cpp @@ -1006,17 +1006,13 @@ return alignDown(min, config->maxPageSize); } -// Try to find an address for the file and program headers output sections, -// which were unconditionally added to the first PT_LOAD segment earlier. +// When the SECTIONS command is used, try to find an address for the file and +// program headers output sections, which can be added to the first PT_LOAD +// segment when program headers are created. // -// When using the default layout, we check if the headers fit below the first -// allocated section. When using a linker script, we also check if the headers -// are covered by the output section. This allows omitting the headers by not -// leaving enough space for them in the linker script; this pattern is common -// in embedded systems. -// -// If there isn't enough space for these sections, we'll remove them from the -// PT_LOAD segment, and we'll also remove the PT_PHDR segment. +// We check if the headers fit below the first allocated section. If there isn't +// enough space for these sections, we'll remove them from the PT_LOAD segment, +// and we'll also remove the PT_PHDR segment. void LinkerScript::allocateHeaders(std::vector &phdrs) { uint64_t min = std::numeric_limits::max(); for (OutputSection *sec : outputSections) @@ -1062,28 +1058,23 @@ } } -static uint64_t getInitialDot() { - // By default linker scripts use an initial value of 0 for '.', - // but prefer -image-base if set. - if (script->hasSectionsCommand) - return config->imageBase ? *config->imageBase : 0; - - uint64_t startAddr = UINT64_MAX; - // The sections with -T
have been sorted in order of ascending - // address. We must lower startAddr if the lowest -T
as - // calls to setDot() must be monotonically increasing. - for (auto &kv : config->sectionStartMap) - startAddr = std::min(startAddr, kv.second); - return std::min(startAddr, target->getImageBase() + elf::getHeaderSize()); -} - // Here we assign addresses as instructed by linker script SECTIONS // sub-commands. Doing that allows us to use final VA values, so here // we also handle rest commands like symbol assignments and ASSERTs. // Returns a symbol that has changed its section or value, or nullptr if no // symbol has changed. const Defined *LinkerScript::assignAddresses() { - dot = getInitialDot(); + if (script->hasSectionsCommand) { + // With a linker script, assignment of addresses to headers is covered by + // allocateHeaders(). + dot = config->imageBase.getValueOr(0); + } else { + // Assign addresses to headers right now. + dot = target->getImageBase(); + Out::elfHeader->addr = dot; + Out::programHeaders->addr = dot + Out::elfHeader->size; + dot += getHeaderSize(); + } auto deleter = std::make_unique(); ctx = deleter.get(); Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -555,7 +555,8 @@ for (OutputSection *sec : outputSections) sec->maybeCompress(); - script->allocateHeaders(mainPart->phdrs); + if (script->hasSectionsCommand) + script->allocateHeaders(mainPart->phdrs); // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a // 0 sized region. This has to be done late since only after assignAddresses Index: lld/trunk/test/ELF/basic-aarch64.s =================================================================== --- lld/trunk/test/ELF/basic-aarch64.s +++ lld/trunk/test/ELF/basic-aarch64.s @@ -159,8 +159,8 @@ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_PHDR (0x6) # CHECK-NEXT: Offset: 0x40 -# CHECK-NEXT: VirtualAddress: 0x210040 -# CHECK-NEXT: PhysicalAddress: 0x210040 +# CHECK-NEXT: VirtualAddress: 0x200040 +# CHECK-NEXT: PhysicalAddress: 0x200040 # CHECK-NEXT: FileSize: 224 # CHECK-NEXT: MemSize: 224 # CHECK-NEXT: Flags [ (0x4) @@ -171,8 +171,8 @@ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD (0x1) # CHECK-NEXT: Offset: 0x0 -# CHECK-NEXT: VirtualAddress: 0x210000 -# CHECK-NEXT: PhysicalAddress: 0x210000 +# CHECK-NEXT: VirtualAddress: 0x200000 +# CHECK-NEXT: PhysicalAddress: 0x200000 # CHECK-NEXT: FileSize: 288 # CHECK-NEXT: MemSize: 288 # CHECK-NEXT: Flags [ Index: lld/trunk/test/ELF/basic-i386.s =================================================================== --- lld/trunk/test/ELF/basic-i386.s +++ lld/trunk/test/ELF/basic-i386.s @@ -129,8 +129,8 @@ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_PHDR (0x6) # CHECK-NEXT: Offset: 0x34 -# CHECK-NEXT: VirtualAddress: 0x401034 -# CHECK-NEXT: PhysicalAddress: 0x401034 +# CHECK-NEXT: VirtualAddress: 0x400034 +# CHECK-NEXT: PhysicalAddress: 0x400034 # CHECK-NEXT: FileSize: 128 # CHECK-NEXT: MemSize: 128 # CHECK-NEXT: Flags [ (0x4) @@ -141,8 +141,8 @@ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD (0x1) # CHECK-NEXT: Offset: 0x0 -# CHECK-NEXT: VirtualAddress: 0x401000 -# CHECK-NEXT: PhysicalAddress: 0x401000 +# CHECK-NEXT: VirtualAddress: 0x400000 +# CHECK-NEXT: PhysicalAddress: 0x400000 # CHECK-NEXT: FileSize: 180 # CHECK-NEXT: MemSize: 180 # CHECK-NEXT: Flags [ Index: lld/trunk/test/ELF/basic-ppc.s =================================================================== --- lld/trunk/test/ELF/basic-ppc.s +++ lld/trunk/test/ELF/basic-ppc.s @@ -143,8 +143,8 @@ // CHECK-NEXT: ProgramHeader { // CHECK-NEXT: Type: PT_PHDR (0x6) // CHECK-NEXT: Offset: 0x34 -// CHECK-NEXT: VirtualAddress: 0x10010034 -// CHECK-NEXT: PhysicalAddress: 0x10010034 +// CHECK-NEXT: VirtualAddress: 0x10000034 +// CHECK-NEXT: PhysicalAddress: 0x10000034 // CHECK-NEXT: FileSize: 128 // CHECK-NEXT: MemSize: 128 // CHECK-NEXT: Flags [ (0x4) @@ -155,8 +155,8 @@ // CHECK-NEXT: ProgramHeader { // CHECK-NEXT: Type: PT_LOAD (0x1) // CHECK-NEXT: Offset: 0x0 -// CHECK-NEXT: VirtualAddress: 0x10010000 -// CHECK-NEXT: PhysicalAddress: 0x10010000 +// CHECK-NEXT: VirtualAddress: 0x10000000 +// CHECK-NEXT: PhysicalAddress: 0x10000000 // CHECK-NEXT: FileSize: 180 // CHECK-NEXT: MemSize: 180 // CHECK-NEXT: Flags [ (0x4) Index: lld/trunk/test/ELF/basic-sparcv9.s =================================================================== --- lld/trunk/test/ELF/basic-sparcv9.s +++ lld/trunk/test/ELF/basic-sparcv9.s @@ -150,8 +150,8 @@ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_PHDR (0x6) # CHECK-NEXT: Offset: 0x40 -# CHECK-NEXT: VirtualAddress: 0x200040 -# CHECK-NEXT: PhysicalAddress: 0x200040 +# CHECK-NEXT: VirtualAddress: 0x100040 +# CHECK-NEXT: PhysicalAddress: 0x100040 # CHECK-NEXT: FileSize: 224 # CHECK-NEXT: MemSize: 224 # CHECK-NEXT: Flags [ (0x4) @@ -162,8 +162,8 @@ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD (0x1) # CHECK-NEXT: Offset: 0x0 -# CHECK-NEXT: VirtualAddress: 0x200000 -# CHECK-NEXT: PhysicalAddress: 0x200000 +# CHECK-NEXT: VirtualAddress: 0x100000 +# CHECK-NEXT: PhysicalAddress: 0x100000 # CHECK-NEXT: FileSize: 288 # CHECK-NEXT: MemSize: 288 # CHECK-NEXT: Flags [ Index: lld/trunk/test/ELF/ttext-tdata-tbss.s =================================================================== --- lld/trunk/test/ELF/ttext-tdata-tbss.s +++ lld/trunk/test/ELF/ttext-tdata-tbss.s @@ -13,7 +13,9 @@ # CHECK-NEXT: PHDR # CHECK-NEXT: LOAD 0x000000 0x0000000000200000 -## With .text at 0 there is no space to allocate the headers. +## If -Ttext is smaller than the image base (which defaults to 0x200000 for -no-pie), +## the headers will still be allocated, but mapped at a higher address, +## which may look strange. # RUN: ld.lld -Ttext 0x0 -Tdata 0x4000 -Tbss 0x8000 %t.o -o %t2 # RUN: llvm-readelf -S -l %t2 | FileCheck %s --check-prefix=USER1 # USER1: .text PROGBITS 0000000000000000 001000 000001 @@ -22,10 +24,12 @@ # USER1-NEXT: .rodata PROGBITS 0000000000009000 003000 000008 # USER1-NEXT: .aw PROGBITS 000000000000a000 004000 000008 # USER1: Type +# USER1-NEXT: PHDR 0x000040 0x0000000000200040 +# USER1-NEXT: LOAD 0x000000 0x0000000000200000 # USER1-NEXT: LOAD 0x001000 0x0000000000000000 -## With .text at 0x1000 there is space to allocate the headers. -# RUN: ld.lld -Ttext 0x1000 -Tdata 0x4000 -Tbss 0x8000 %t.o -o %t3 +## Specify --image-base to make program headers look normal. +# RUN: ld.lld --image-base=0 -Ttext 0x1000 -Tdata 0x4000 -Tbss 0x8000 %t.o -o %t3 # RUN: llvm-readelf -S -l %t3 | FileCheck %s --check-prefix=USER2 # USER2: .text PROGBITS 0000000000001000 001000 000001 # USER2-NEXT: .data PROGBITS 0000000000004000 002000 000008 @@ -33,8 +37,9 @@ # USER2-NEXT: .rodata PROGBITS 0000000000009000 003000 000008 # USER2-NEXT: .aw PROGBITS 000000000000a000 004000 000008 # USER2: Type -# USER2-NEXT: PHDR +# USER2-NEXT: PHDR 0x000040 0x0000000000000040 # USER2-NEXT: LOAD 0x000000 0x0000000000000000 +# USER2-NEXT: LOAD 0x001000 0x0000000000001000 ## With .text well above 200000 we don't need to change the image base # RUN: ld.lld -Ttext 0x201000 %t.o -o %t4 @@ -45,8 +50,9 @@ # USER3-NEX: .data PROGBITS 0000000000203008 003008 000008 # USER3-NEX: .bss NOBITS 0000000000203010 003010 000008 # USER3: Type -# USER3-NEXT: PHDR +# USER3-NEXT: PHDR 0x000040 0x0000000000200040 # USER3-NEXT: LOAD 0x000000 0x0000000000200000 +# USER3-NEXT: LOAD 0x001000 0x0000000000201000 .text .globl _start