Skip to content

Commit 2d7add6

Browse files
authored
[LLD][ELF] Allow memory region in OVERLAY (#133540)
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. Closes #129816
1 parent 143c371 commit 2d7add6

File tree

5 files changed

+62
-11
lines changed

5 files changed

+62
-11
lines changed

Diff for: lld/ELF/LinkerScript.cpp

+14-1
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) {
@@ -1218,6 +1229,8 @@ bool LinkerScript::assignOffsets(OutputSection *sec) {
12181229
// We can call this method multiple times during the creation of
12191230
// thunks and want to start over calculation each time.
12201231
sec->size = 0;
1232+
if (sec->firstInOverlay)
1233+
state->overlaySize = 0;
12211234

12221235
// We visited SectionsCommands from processSectionCommands to
12231236
// layout sections. Now, we visit SectionsCommands again to fix

Diff for: lld/ELF/LinkerScript.h

+1
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;
314315
};
315316

316317
Ctx &ctx;

Diff for: lld/ELF/OutputSections.h

+1
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 firstInOverlay = 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

Diff for: lld/ELF/ScriptParser.cpp

+13-10
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.front())->osec.firstInOverlay = 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

Diff for: lld/test/ELF/linkerscript/overlay.test

+33
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,23 @@
4141
# ERR2-NEXT:>>> .out.aaa { *(.aaa) } > AX AT>FLASH
4242
# ERR2-NEXT:>>> ^
4343

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

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

0 commit comments

Comments
 (0)