Skip to content

[LLD][ELF] Allow memory region in OVERLAY #133540

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion lld/ELF/LinkerScript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/LinkerScript.h
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ class LinkerScript final {
MemoryRegion *lmaRegion = nullptr;
uint64_t lmaOffset = 0;
uint64_t tbssAddr = 0;
uint64_t overlaySize;
};

Ctx &ctx;
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/OutputSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class OutputSection final : public SectionBase {
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
Expand Down
23 changes: 13 additions & 10 deletions lld/ELF/ScriptParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,37 +561,40 @@ void ScriptParser::readSearchDir() {
// https://sourceware.org/binutils/docs/ld/Overlay-Description.html#Overlay-Description
SmallVector<SectionCommand *, 0> 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<SectionCommand *, 0> 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<OutputDesc *>(v.front())->osec.firstInOverlay = true;
if (consume(">")) {
StringRef regionName = readName();
for (SectionCommand *od : v)
static_cast<OutputDesc *>(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
Expand Down
33 changes: 33 additions & 0 deletions lld/test/ELF/linkerscript/overlay.test
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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 ) {
Expand Down
Loading