Skip to content

Commit 535578e

Browse files
committed
[LLD][ELF] Allow memory region in OVERLAY
This allows the contents of OVERLAYs to be attributed to memory regions. This is the only clean way to overlap VMAs in linker scripts that choose to primarily use memory regions to lay out addresses. This also simplifies OVERLAY expansion to better match GNU LD. Expressions for the first section's LMA and VMA are not generated if the user did not provide them. This allows the LMA/VMA offset to be preserved across multiple overlays in the same region, as with regular sections. Fixes #129816
1 parent dcc2fae commit 535578e

File tree

5 files changed

+63
-11
lines changed

5 files changed

+63
-11
lines changed

lld/ELF/LinkerScript.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,18 @@ void LinkerScript::expandMemoryRegions(uint64_t size) {
182182

183183
void LinkerScript::expandOutputSection(uint64_t size) {
184184
state->outSec->size += size;
185-
expandMemoryRegions(size);
185+
size_t regionSize = size;
186+
if (state->outSec->inOverlay) {
187+
// Expand the overlay if necessary, and expand the region by the
188+
// corresponding amount.
189+
if (state->outSec->size > state->overlaySize) {
190+
regionSize = state->outSec->size - state->overlaySize;
191+
state->overlaySize = state->outSec->size;
192+
} else {
193+
regionSize = 0;
194+
}
195+
}
196+
expandMemoryRegions(regionSize);
186197
}
187198

188199
void LinkerScript::setDot(Expr e, const Twine &loc, bool inSec) {
@@ -1273,6 +1284,8 @@ bool LinkerScript::assignOffsets(OutputSection *sec) {
12731284
// NOBITS TLS sections are similar. Additionally save the end address.
12741285
state->tbssAddr = dot;
12751286
dot = savedDot;
1287+
} else if (sec->lastInOverlay) {
1288+
state->overlaySize = 0;
12761289
}
12771290
return addressChanged;
12781291
}

lld/ELF/LinkerScript.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ class LinkerScript final {
311311
MemoryRegion *lmaRegion = nullptr;
312312
uint64_t lmaOffset = 0;
313313
uint64_t tbssAddr = 0;
314+
uint64_t overlaySize = 0;
314315
};
315316

316317
Ctx &ctx;

lld/ELF/OutputSections.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ class OutputSection final : public SectionBase {
102102
bool expressionsUseSymbols = false;
103103
bool usedInExpression = false;
104104
bool inOverlay = false;
105+
bool lastInOverlay = false;
105106

106107
// Tracks whether the section has ever had an input section added to it, even
107108
// if the section was later removed (e.g. because it is a synthetic section

lld/ELF/ScriptParser.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -561,37 +561,40 @@ void ScriptParser::readSearchDir() {
561561
// https://sourceware.org/binutils/docs/ld/Overlay-Description.html#Overlay-Description
562562
SmallVector<SectionCommand *, 0> ScriptParser::readOverlay() {
563563
Expr addrExpr;
564-
if (consume(":")) {
565-
addrExpr = [s = ctx.script] { return s->getDot(); };
566-
} else {
564+
if (!consume(":")) {
567565
addrExpr = readExpr();
568566
expect(":");
569567
}
570-
// When AT is omitted, LMA should equal VMA. script->getDot() when evaluating
571-
// lmaExpr will ensure this, even if the start address is specified.
572-
Expr lmaExpr = consume("AT") ? readParenExpr()
573-
: [s = ctx.script] { return s->getDot(); };
568+
Expr lmaExpr = consume("AT") ? readParenExpr() : Expr{};
574569
expect("{");
575570

576571
SmallVector<SectionCommand *, 0> v;
577572
OutputSection *prev = nullptr;
578573
while (!errCount(ctx) && !consume("}")) {
579574
// VA is the same for all sections. The LMAs are consecutive in memory
580-
// starting from the base load address specified.
575+
// starting from the base load address.
581576
OutputDesc *osd = readOverlaySectionDescription();
582577
osd->osec.addrExpr = addrExpr;
583578
if (prev) {
584579
osd->osec.lmaExpr = [=] { return prev->getLMA() + prev->size; };
585580
} else {
586581
osd->osec.lmaExpr = lmaExpr;
587-
// Use first section address for subsequent sections as initial addrExpr
588-
// can be DOT. Ensure the first section, even if empty, is not discarded.
582+
// Use first section address for subsequent sections. Ensure the first
583+
// section, even if empty, is not discarded.
589584
osd->osec.usedInExpression = true;
590585
addrExpr = [=]() -> ExprValue { return {&osd->osec, false, 0, ""}; };
591586
}
592587
v.push_back(osd);
593588
prev = &osd->osec;
594589
}
590+
if (!v.empty())
591+
static_cast<OutputDesc *>(v.back())->osec.lastInOverlay = true;
592+
if (consume(">")) {
593+
StringRef regionName = readName();
594+
for (SectionCommand *od : v)
595+
static_cast<OutputDesc *>(od)->osec.memoryRegionName =
596+
std::string(regionName);
597+
}
595598

596599
// According to the specification, at the end of the overlay, the location
597600
// counter should be equal to the overlay base address plus size of the

lld/test/ELF/linkerscript/overlay.test

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
## .text does not cause overlapping error and that
1010
## .text's VA is 0x1000 + max(sizeof(.out.big), sizeof(.out.small)).
1111

12+
# RUN: ld.lld a.o -T a.t -o a
1213
# RUN: llvm-readelf --sections -l a | FileCheck %s
1314

1415
# CHECK: Name Type Address Off Size
@@ -41,6 +42,23 @@
4142
# ERR2-NEXT:>>> .out.aaa { *(.aaa) } > AX AT>FLASH
4243
# ERR2-NEXT:>>> ^
4344

45+
# RUN: ld.lld a.o -T region.t -o region
46+
# RUN: llvm-readelf --sections -l region | FileCheck --check-prefix=REGION %s
47+
48+
# REGION: Name Type Address Off Size
49+
# REGION: .big1 PROGBITS 0000000000001000 001000 000008
50+
# REGION-NEXT: .small1 PROGBITS 0000000000001000 002000 000004
51+
# REGION: .big2 PROGBITS 0000000000001008 002008 000008
52+
# REGION-NEXT: .small2 PROGBITS 0000000000001008 003008 000004
53+
# REGION-NEXT: .text PROGBITS 0000000000001010 003010 000001
54+
55+
# REGION: Program Headers:
56+
# REGION: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
57+
# REGION-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000008 0x000008 R 0x1000
58+
# REGION-NEXT: LOAD 0x002000 0x0000000000001000 0x0000000000001008 0x000010 0x000010 R 0x1000
59+
# REGION-NEXT: LOAD 0x003008 0x0000000000001008 0x0000000000001018 0x000004 0x000004 R 0x1000
60+
# REGION-NEXT: LOAD 0x003010 0x0000000000001010 0x0000000000001020 0x000001 0x000001 R E 0x1000
61+
4462
#--- a.s
4563
.globl _start
4664
_start:
@@ -76,6 +94,22 @@ SECTIONS {
7694
.text : { *(.text) }
7795
}
7896

97+
#--- region.t
98+
MEMORY { region : ORIGIN = 0x1000, LENGTH = 0x1000 }
99+
SECTIONS {
100+
## Memory region instead of explicit address.
101+
OVERLAY : {
102+
.big1 { *(.big1) }
103+
.small1 { *(.small1) }
104+
} >region
105+
OVERLAY : {
106+
.big2 { *(.big2) }
107+
.small2 { *(.small2) }
108+
} >region
109+
.text : { *(.text) } >region
110+
/DISCARD/ : { *(.big* .small*) }
111+
}
112+
79113
#--- err1.t
80114
SECTIONS {
81115
OVERLAY 0x1000 : AT ( 0x2000 ) {

0 commit comments

Comments
 (0)