Skip to content

Commit 9e98f3e

Browse files
Andreu Carminatiluismarques
authored andcommitted
[ELF] Fix early overflow check in finalizeAddressDependentContent
LLD terminates with errors when it detects overflows in the finalizeAddressDependentContent calculation. Although, sometimes, those errors are not really errors, but an intermediate result of an ongoing address calculation. If we continue the fixed-point algorithm we can converge to the correct result. This patch * Removes the verification inside the fixed point algorithm. * Calls checkMemoryRegions at the end. Reviewed By: peter.smith, MaskRay Differential Revision: https://reviews.llvm.org/D152170 Backported by: a-will
1 parent d3ac1d3 commit 9e98f3e

File tree

5 files changed

+104
-8
lines changed

5 files changed

+104
-8
lines changed

lld/ELF/LinkerScript.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,12 +157,6 @@ OutputDesc *LinkerScript::getOrCreateOutputSection(StringRef name) {
157157
static void expandMemoryRegion(MemoryRegion *memRegion, uint64_t size,
158158
StringRef secName) {
159159
memRegion->curPos += size;
160-
uint64_t newSize = memRegion->curPos - (memRegion->origin)().getValue();
161-
uint64_t length = (memRegion->length)().getValue();
162-
if (newSize > length)
163-
error("section '" + secName + "' will not fit in region '" +
164-
memRegion->name + "': overflowed by " + Twine(newSize - length) +
165-
" bytes");
166160
}
167161

168162
void LinkerScript::expandMemoryRegions(uint64_t size) {
@@ -1432,3 +1426,23 @@ SmallVector<size_t, 0> LinkerScript::getPhdrIndices(OutputSection *cmd) {
14321426
}
14331427
return ret;
14341428
}
1429+
1430+
static void checkMemoryRegion(const MemoryRegion *region,
1431+
const OutputSection *osec, uint64_t addr) {
1432+
uint64_t osecEnd = addr + osec->size;
1433+
uint64_t regionEnd = region->getOrigin() + region->getLength();
1434+
if (osecEnd > regionEnd) {
1435+
error("section '" + osec->name + "' will not fit in region '" +
1436+
region->name + "': overflowed by " + Twine(osecEnd - regionEnd) +
1437+
" bytes");
1438+
}
1439+
}
1440+
1441+
void LinkerScript::checkMemoryRegions() const {
1442+
for (const OutputSection *sec : outputSections) {
1443+
if (const MemoryRegion *memoryRegion = sec->memRegion)
1444+
checkMemoryRegion(memoryRegion, sec, sec->addr);
1445+
if (const MemoryRegion *lmaRegion = sec->lmaRegion)
1446+
checkMemoryRegion(lmaRegion, sec, sec->getLMA());
1447+
}
1448+
}

lld/ELF/LinkerScript.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ struct MemoryRegion {
151151
uint32_t negInvFlags;
152152
uint64_t curPos = 0;
153153

154+
uint64_t getOrigin() const { return origin().getValue(); }
155+
uint64_t getLength() const { return length().getValue(); }
156+
154157
bool compatibleWith(uint32_t secFlags) const {
155158
if ((secFlags & negFlags) || (~secFlags & negInvFlags))
156159
return false;
@@ -333,6 +336,9 @@ class LinkerScript final {
333336
// Used to handle INSERT AFTER statements.
334337
void processInsertCommands();
335338

339+
// Verify memory/lma overflows.
340+
void checkMemoryRegions() const;
341+
336342
// SECTIONS command list.
337343
SmallVector<SectionCommand *, 0> sectionCommands;
338344

lld/ELF/Writer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2156,6 +2156,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
21562156
// of finalizing other sections.
21572157
for (OutputSection *sec : outputSections)
21582158
sec->finalize();
2159+
2160+
script->checkMemoryRegions();
21592161
}
21602162

21612163
// Ensure data sections are not mixed with executable sections when
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
REQUIRES: x86
2+
3+
# RUN: rm -rf %t && split-file %s %t
4+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a.s -o %t/a.o
5+
6+
## The error should be triggered only for the second test where the overflow really exists.
7+
8+
RUN: ld.lld %t/a.o -T %t/b.lds -o /dev/null 2>&1
9+
RUN: not ld.lld %t/a.o -T %t/c.lds -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s
10+
11+
# ERROR: error: section '_abss' will not fit in region 'SRAM0': overflowed by 1024 bytes
12+
# ERROR: error: section '.c.bss' will not fit in region 'SRAM0': overflowed by 1024 bytes
13+
# ERROR: error: section '.text' will not fit in region 'SRAM0': overflowed by 1025 bytes
14+
15+
#--- a.s
16+
.section .a.bss, "aw", %nobits
17+
.globl abss
18+
abss:
19+
.zero 0xDF0
20+
.size abss, 0xDF0
21+
22+
.section .c.bss, "aw", %nobits
23+
.globl cbss
24+
25+
.text
26+
.globl _start
27+
_start:
28+
nop
29+
30+
#--- b.lds
31+
MEMORY
32+
{
33+
SRAM0 (rw) : ORIGIN = 0x20000400, LENGTH = 10K
34+
}
35+
36+
SECTIONS
37+
{
38+
_abss ALIGN(REGION1__PRE_ALIGNMENT) :
39+
{
40+
REGION1__BEGIN = .; REGION1__ALIGNED_BEGIN = .; REGION1_ALIGNED_BEGIN = .;
41+
*(.a.bss)
42+
REGION1__END = .; . = ALIGN(REGION1__POST_ALIGNMENT); REGION1_ALIGNED_END = .;
43+
} > SRAM0
44+
}
45+
46+
REGION1__PRE_ALIGNMENT = 0x00000800;
47+
REGION1__PADDED_XOR = ((ABSOLUTE(REGION1__ALIGNED_BEGIN) | (ABSOLUTE(REGION1__END) - 1)) & ~(ABSOLUTE(REGION1__ALIGNED_BEGIN) & (ABSOLUTE(REGION1__END) - 1)));
48+
REGION1__PADDED_REGION_SHIFT = LOG2CEIL(REGION1__PADDED_XOR);
49+
REGION1__PADDED_SR_SHIFT = REGION1__PADDED_REGION_SHIFT - 3;
50+
REGION1__PADDED_SR_SIZE = MAX(1 << REGION1__PADDED_SR_SHIFT, 32);
51+
REGION1__POST_ALIGNMENT = REGION1__PADDED_SR_SIZE;
52+
53+
#--- c.lds
54+
MEMORY
55+
{
56+
SRAM0 (rw) : ORIGIN = 0x20000400, LENGTH = 4K
57+
}
58+
59+
SECTIONS
60+
{
61+
_abss ALIGN(REGION1__PRE_ALIGNMENT) :
62+
{
63+
REGION1__BEGIN = .; REGION1__ALIGNED_BEGIN = .; REGION1_ALIGNED_BEGIN = .;
64+
*(.a.bss)
65+
REGION1__END = .; . = ALIGN(REGION1__POST_ALIGNMENT); REGION1_ALIGNED_END = .;
66+
} > SRAM0
67+
}
68+
69+
REGION1__PRE_ALIGNMENT = 0x00000800;
70+
REGION1__PADDED_XOR = ((ABSOLUTE(REGION1__ALIGNED_BEGIN) | (ABSOLUTE(REGION1__END) - 1)) & ~(ABSOLUTE(REGION1__ALIGNED_BEGIN) & (ABSOLUTE(REGION1__END) - 1)));
71+
REGION1__PADDED_REGION_SHIFT = LOG2CEIL(REGION1__PADDED_XOR);
72+
REGION1__PADDED_SR_SHIFT = REGION1__PADDED_REGION_SHIFT - 3;
73+
REGION1__PADDED_SR_SIZE = MAX(1 << REGION1__PADDED_SR_SHIFT, 32);
74+
REGION1__POST_ALIGNMENT = REGION1__PADDED_SR_SIZE;

lld/test/ELF/linkerscript/memory-err.s

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,14 @@
6262
## ORIGIN/LENGTH can be simple symbolic expressions. If the expression
6363
## requires interaction with memory regions, it may fail.
6464

65-
# RUN: echo 'MEMORY { ram : ORIGIN = symbol, LENGTH = 4097 } \
65+
# RUN: echo 'MEMORY { ram : ORIGIN = symbol, LENGTH = 4094 } \
6666
# RUN: SECTIONS { \
6767
# RUN: .text : { *(.text) } > ram \
6868
# RUN: symbol = .; \
6969
# RUN: .data : { *(.data) } > ram \
7070
# RUN: }' > %t.script
7171
# RUN: not ld.lld -T %t.script %t.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR_OVERFLOW %s
72-
# ERR_OVERFLOW: error: section '.text' will not fit in region 'ram': overflowed by 18446744073709547518 bytes
72+
# ERR_OVERFLOW: error: section '.data' will not fit in region 'ram': overflowed by 2 bytes
7373

7474
nop
7575

0 commit comments

Comments
 (0)