diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index e19823f2ea75..8149513d821e 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -182,7 +182,18 @@ void LinkerScript::expandMemoryRegions(uint64_t size) { void LinkerScript::expandOutputSection(uint64_t size) { state->outSec->size += size; - expandMemoryRegions(size); + size_t regionSize = size; + if (state->outSec->inOverlay) { + // Expand the overlay if necessary, and expand the region by the + // corresponding amount. + if (state->outSec->size > state->overlaySize) { + regionSize = state->outSec->size - state->overlaySize; + state->overlaySize = state->outSec->size; + } else { + regionSize = 0; + } + } + expandMemoryRegions(regionSize); } void LinkerScript::setDot(Expr e, const Twine &loc, bool inSec) { @@ -1218,6 +1229,8 @@ bool LinkerScript::assignOffsets(OutputSection *sec) { // We can call this method multiple times during the creation of // thunks and want to start over calculation each time. sec->size = 0; + if (sec->firstInOverlay) + state->overlaySize = 0; // We visited SectionsCommands from processSectionCommands to // layout sections. Now, we visit SectionsCommands again to fix diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 0a2dda13f4ef..80c4f564afab 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -311,6 +311,7 @@ class LinkerScript final { MemoryRegion *lmaRegion = nullptr; uint64_t lmaOffset = 0; uint64_t tbssAddr = 0; + uint64_t overlaySize; }; Ctx &ctx; diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 3ab36a21ce48..77654f85ca78 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -102,6 +102,7 @@ public: bool expressionsUseSymbols = false; bool usedInExpression = false; bool inOverlay = false; + bool firstInOverlay = false; // Tracks whether the section has ever had an input section added to it, even // if the section was later removed (e.g. because it is a synthetic section diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index 4c52bfda7a70..4345b7bac117 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -561,37 +561,40 @@ void ScriptParser::readSearchDir() { // https://sourceware.org/binutils/docs/ld/Overlay-Description.html#Overlay-Description SmallVector ScriptParser::readOverlay() { Expr addrExpr; - if (consume(":")) { - addrExpr = [s = ctx.script] { return s->getDot(); }; - } else { + if (!consume(":")) { addrExpr = readExpr(); expect(":"); } - // When AT is omitted, LMA should equal VMA. script->getDot() when evaluating - // lmaExpr will ensure this, even if the start address is specified. - Expr lmaExpr = consume("AT") ? readParenExpr() - : [s = ctx.script] { return s->getDot(); }; + Expr lmaExpr = consume("AT") ? readParenExpr() : Expr{}; expect("{"); SmallVector v; OutputSection *prev = nullptr; while (!errCount(ctx) && !consume("}")) { // VA is the same for all sections. The LMAs are consecutive in memory - // starting from the base load address specified. + // starting from the base load address. OutputDesc *osd = readOverlaySectionDescription(); osd->osec.addrExpr = addrExpr; if (prev) { osd->osec.lmaExpr = [=] { return prev->getLMA() + prev->size; }; } else { osd->osec.lmaExpr = lmaExpr; - // Use first section address for subsequent sections as initial addrExpr - // can be DOT. Ensure the first section, even if empty, is not discarded. + // Use first section address for subsequent sections. Ensure the first + // section, even if empty, is not discarded. osd->osec.usedInExpression = true; addrExpr = [=]() -> ExprValue { return {&osd->osec, false, 0, ""}; }; } v.push_back(osd); prev = &osd->osec; } + if (!v.empty()) + static_cast(v.front())->osec.firstInOverlay = true; + if (consume(">")) { + StringRef regionName = readName(); + for (SectionCommand *od : v) + static_cast(od)->osec.memoryRegionName = + std::string(regionName); + } // According to the specification, at the end of the overlay, the location // counter should be equal to the overlay base address plus size of the diff --git a/lld/test/ELF/linkerscript/overlay.test b/lld/test/ELF/linkerscript/overlay.test index 7c64303b4565..e230134ad554 100644 --- a/lld/test/ELF/linkerscript/overlay.test +++ b/lld/test/ELF/linkerscript/overlay.test @@ -41,6 +41,23 @@ # ERR2-NEXT:>>> .out.aaa { *(.aaa) } > AX AT>FLASH # ERR2-NEXT:>>> ^ +# RUN: ld.lld a.o -T region.t -o region +# RUN: llvm-readelf --sections -l region | FileCheck --check-prefix=REGION %s + +# REGION: Name Type Address Off Size +# REGION: .big1 PROGBITS 0000000000001000 001000 000008 +# REGION-NEXT: .small1 PROGBITS 0000000000001000 002000 000004 +# REGION: .big2 PROGBITS 0000000000001008 002008 000008 +# REGION-NEXT: .small2 PROGBITS 0000000000001008 003008 000004 +# REGION-NEXT: .text PROGBITS 0000000000001010 003010 000001 + +# REGION: Program Headers: +# REGION: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# REGION-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000008 0x000008 R 0x1000 +# REGION-NEXT: LOAD 0x002000 0x0000000000001000 0x0000000000001008 0x000010 0x000010 R 0x1000 +# REGION-NEXT: LOAD 0x003008 0x0000000000001008 0x0000000000001018 0x000004 0x000004 R 0x1000 +# REGION-NEXT: LOAD 0x003010 0x0000000000001010 0x0000000000001020 0x000001 0x000001 R E 0x1000 + #--- a.s .globl _start _start: @@ -76,6 +93,22 @@ SECTIONS { .text : { *(.text) } } +#--- region.t +MEMORY { region : ORIGIN = 0x1000, LENGTH = 0x1000 } +SECTIONS { +## Memory region instead of explicit address. + OVERLAY : { + .big1 { *(.big1) } + .small1 { *(.small1) } + } >region + OVERLAY : { + .big2 { *(.big2) } + .small2 { *(.small2) } + } >region + .text : { *(.text) } >region + /DISCARD/ : { *(.big* .small*) } +} + #--- err1.t SECTIONS { OVERLAY 0x1000 : AT ( 0x2000 ) {