Index: lld/ELF/LinkerScript.h =================================================================== --- lld/ELF/LinkerScript.h +++ lld/ELF/LinkerScript.h @@ -272,7 +272,7 @@ std::vector getPhdrIndices(OutputSection *sec); - MemoryRegion *findMemoryRegion(OutputSection *sec); + MemoryRegion *findMemoryRegion(OutputSection *sec, MemoryRegion *prev); void switchTo(OutputSection *sec); uint64_t advance(uint64_t size, unsigned align); Index: lld/ELF/LinkerScript.cpp =================================================================== --- lld/ELF/LinkerScript.cpp +++ lld/ELF/LinkerScript.cpp @@ -883,7 +883,8 @@ // This function searches for a memory region to place the given output // section in. If found, a pointer to the appropriate memory region is // returned. Otherwise, a nullptr is returned. -MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *sec) { +MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *sec, + MemoryRegion *prev) { // If a memory region name was specified in the output section command, // then try to find that region first. if (!sec->memoryRegionName.empty()) { @@ -899,6 +900,10 @@ if (memoryRegions.empty()) return nullptr; + // An allocatable orphan section should continue the previous memory region. + if (sec->sectionIndex == UINT32_MAX && sec->flags & SHF_ALLOC && prev) + return prev; + // See if a region can be found by matching section flags. for (auto &pair : memoryRegions) { MemoryRegion *m = pair.second; @@ -1132,6 +1137,7 @@ void LinkerScript::adjustSectionsAfterSorting() { // Try and find an appropriate memory region to assign offsets in. + MemoryRegion *prev = nullptr; for (BaseCommand *base : sectionCommands) { if (auto *sec = dyn_cast(base)) { if (!sec->lmaRegionName.empty()) { @@ -1140,7 +1146,8 @@ else error("memory region '" + sec->lmaRegionName + "' not declared"); } - sec->memRegion = findMemoryRegion(sec); + sec->memRegion = findMemoryRegion(sec, prev); + prev = sec->memRegion; } } Index: lld/ELF/Writer.cpp =================================================================== --- lld/ELF/Writer.cpp +++ lld/ELF/Writer.cpp @@ -1256,10 +1256,13 @@ // Consider all existing sections with the same proximity. int proximity = getRankProximity(sec, *i); unsigned sortRank = sec->sortRank; - if (script->hasPhdrsCommands()) - // Prevent the orphan section to be placed before the found section because - // that can result in adding it to a previous segment and changing flags of - // that segment, for example, making a read-only segment writable. + if (script->hasPhdrsCommands() || !script->memoryRegions.empty()) + // Prevent the orphan section to be placed before the found section. If + // custom program headers are defined, that helps to avoid adding it to a + // previous segment and changing flags of that segment, for example, making + // a read-only segment writable. If memory regions are defined, an orphan + // section should continue the same region as the found section to better + // resemble the behavior of GNU ld. sortRank = std::max(sortRank, foundSec->sortRank); for (; i != e; ++i) { auto *curSec = dyn_cast(*i); Index: lld/test/ELF/linkerscript/orphan-memory.test =================================================================== --- /dev/null +++ lld/test/ELF/linkerscript/orphan-memory.test @@ -0,0 +1,50 @@ +# REQUIRES: x86 + +# RUN: split-file %s %ts +# RUN: llvm-mc -filetype=obj -triple=x86_64 %ts/s -o %t.o +# RUN: ld.lld -o %t -T %ts/t %t.o +# RUN: llvm-readobj -S %t | FileCheck %s + +## Check that despite having a lower sort rank, an orphan section '.init_array' +## is placed after '.data' and in the same memory region. + +CHECK: Name: .data +CHECK-NEXT: Type: SHT_PROGBITS +CHECK-NEXT: Flags [ +CHECK-NEXT: SHF_ALLOC +CHECK-NEXT: SHF_WRITE +CHECK-NEXT: ] +CHECK-NEXT: Address: 0x9000 +CHECK-NEXT: Offset: +CHECK-NEXT: Size: 8 + +CHECK: Name: .init_array +CHECK-NEXT: Type: SHT_INIT_ARRAY +CHECK-NEXT: Flags [ +CHECK-NEXT: SHF_ALLOC +CHECK-NEXT: SHF_WRITE +CHECK-NEXT: ] +CHECK-NEXT: Address: 0x9008 + +#--- s + .text + nop + + .data + .quad 0 + + .section .init_array,"aw",@init_array + .quad 0 + +#--- t +MEMORY +{ + TEXT : ORIGIN = 0x8000, LENGTH = 0x1000 + DATA : ORIGIN = 0x9000, LENGTH = 0x1000 +} + +SECTIONS +{ + .text : { *(.text) } > TEXT + .data : { *(.data) } > DATA +}