mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-16 05:26:31 +00:00
[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
This commit is contained in:
parent
143c37123b
commit
2d7add6e2e
@ -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
|
||||
|
@ -311,6 +311,7 @@ class LinkerScript final {
|
||||
MemoryRegion *lmaRegion = nullptr;
|
||||
uint64_t lmaOffset = 0;
|
||||
uint64_t tbssAddr = 0;
|
||||
uint64_t overlaySize;
|
||||
};
|
||||
|
||||
Ctx &ctx;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 ) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user