Index: lld/ELF/LinkerScript.h =================================================================== --- lld/ELF/LinkerScript.h +++ lld/ELF/LinkerScript.h @@ -339,6 +339,9 @@ // Describe memory region usage. void printMemoryUsage(raw_ostream &os); + // Verify for memory/lma overflows. + void verifyMemoryRegions() const; + // SECTIONS command list. SmallVector sectionCommands; Index: lld/ELF/LinkerScript.cpp =================================================================== --- lld/ELF/LinkerScript.cpp +++ lld/ELF/LinkerScript.cpp @@ -157,12 +157,6 @@ static void expandMemoryRegion(MemoryRegion *memRegion, uint64_t size, StringRef secName) { memRegion->curPos += size; - uint64_t newSize = memRegion->curPos - memRegion->getOrigin(); - uint64_t length = memRegion->getLength(); - if (newSize > length) - error("section '" + secName + "' will not fit in region '" + - memRegion->name + "': overflowed by " + Twine(newSize - length) + - " bytes"); } void LinkerScript::expandMemoryRegions(uint64_t size) { @@ -1456,3 +1450,25 @@ os << '\n'; } } + +static void verifyMemoryRegion(const MemoryRegion *memoryRegion, + const OutputSection *osec, uint64_t addr) { + + uint64_t osecEnd = addr + osec->size; + uint64_t regionEnd = memoryRegion->getOrigin() + memoryRegion->getLength(); + + if (osecEnd > regionEnd) { + error("section '" + osec->name + "' will not fit in region '" + + memoryRegion->name + "': overflowed by " + + Twine(osecEnd - regionEnd) + " bytes"); + } +} + +void LinkerScript::verifyMemoryRegions() const { + for (const OutputSection *sec : outputSections) { + if (const MemoryRegion *memoryRegion = sec->memRegion) + verifyMemoryRegion(memoryRegion, sec, sec->addr); + if (const MemoryRegion *lmaRegion = sec->lmaRegion) + verifyMemoryRegion(lmaRegion, sec, sec->getLMA()); + } +} Index: lld/ELF/Writer.cpp =================================================================== --- lld/ELF/Writer.cpp +++ lld/ELF/Writer.cpp @@ -2144,6 +2144,8 @@ // of finalizing other sections. for (OutputSection *sec : outputSections) sec->finalize(); + + script->verifyMemoryRegions(); } // Ensure data sections are not mixed with executable sections when Index: lld/test/ELF/linkerscript/end-overflow-check.test =================================================================== --- /dev/null +++ lld/test/ELF/linkerscript/end-overflow-check.test @@ -0,0 +1,96 @@ +REQUIRES: x86 + +# RUN: split-file %s %ts +# RUN: llvm-mc -filetype=obj -triple=x86_64 %ts/a.s -o %ts/a.o + +# The error should be triggered only for the second test where the overflow really exists. + +RUN: ld.lld %ts/a.o -T %ts/b.lds -o /dev/null 2>&1 +RUN: not ld.lld %ts/a.o -T %ts/c.lds -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s + +# ERROR: ld.lld: error: section '_abss' will not fit in region 'SRAM0': overflowed by 512 bytes +# ERROR: ld.lld: error: section '.c.bss' will not fit in region 'SRAM0': overflowed by 512 bytes +# ERROR: ld.lld: error: section '.text' will not fit in region 'SRAM0': overflowed by 513 bytes + +#--- a.s +.section .a.bss, "aw", %nobits +.globl abss +abss: +.zero 0xDF0 +.size abss, 0xDF0 + +.section .b.bss, "aw", %nobits +.globl abss +bbss: +.zero 16 +.size bbss, 16 + +.section .c.bss, "aw", %nobits +.globl cbss + +.text +.globl _start +_start: +nop + +#--- b.lds + +MEMORY +{ + SRAM0 (rw) : ORIGIN = 0x20000400, LENGTH = 20K +} + +SECTIONS +{ + _bbss 0x20001D60 : + { + REGION2_BEGIN = .; + *(.b.bss) + REGION2_END = .; + } > SRAM0 + _abss : + { + REGION1__BEGIN = .; . = ALIGN(REGION1__PRE_ALIGNMENT); REGION1__ALIGNED_BEGIN = .; REGION1_ALIGNED_BEGIN = .; + *(.a.bss) + REGION1__END = .; . = ALIGN(REGION1__POST_ALIGNMENT); REGION1_ALIGNED_END = .; + } > SRAM0 +} + + +REGION1__PRE_ALIGNMENT = 0x00000800; +REGION1__PADDED_XOR = ((ABSOLUTE(REGION1__ALIGNED_BEGIN) | (ABSOLUTE(REGION1__END) - 1)) & ~(ABSOLUTE(REGION1__ALIGNED_BEGIN) & (ABSOLUTE(REGION1__END) - 1))); +REGION1__PADDED_REGION_SHIFT = LOG2CEIL(REGION1__PADDED_XOR); +REGION1__PADDED_SR_SHIFT = REGION1__PADDED_REGION_SHIFT - 3; +REGION1__PADDED_SR_SIZE = MAX(1 << REGION1__PADDED_SR_SHIFT, 32); +REGION1__POST_ALIGNMENT = REGION1__PADDED_SR_SIZE; + +#--- c.lds + +MEMORY +{ + SRAM0 (rw) : ORIGIN = 0x20000400, LENGTH = 10K +} + +SECTIONS +{ + _bbss 0x20001D60 : + { + REGION2_BEGIN = .; + *(.b.bss) + REGION2_END = .; + } > SRAM0 + _abss : + { + REGION1__BEGIN = .; . = ALIGN(REGION1__PRE_ALIGNMENT); REGION1__ALIGNED_BEGIN = .; REGION1_ALIGNED_BEGIN = .; + *(.a.bss) + REGION1__END = .; . = ALIGN(REGION1__POST_ALIGNMENT); REGION1_ALIGNED_END = .; + } > SRAM0 +} + + +REGION1__PRE_ALIGNMENT = 0x00000800; +REGION1__PADDED_XOR = ((ABSOLUTE(REGION1__ALIGNED_BEGIN) | (ABSOLUTE(REGION1__END) - 1)) & ~(ABSOLUTE(REGION1__ALIGNED_BEGIN) & (ABSOLUTE(REGION1__END) - 1))); +REGION1__PADDED_REGION_SHIFT = LOG2CEIL(REGION1__PADDED_XOR); +REGION1__PADDED_SR_SHIFT = REGION1__PADDED_REGION_SHIFT - 3; +REGION1__PADDED_SR_SIZE = MAX(1 << REGION1__PADDED_SR_SHIFT, 32); +REGION1__POST_ALIGNMENT = REGION1__PADDED_SR_SIZE; Index: lld/test/ELF/linkerscript/memory-err.s =================================================================== --- lld/test/ELF/linkerscript/memory-err.s +++ lld/test/ELF/linkerscript/memory-err.s @@ -62,14 +62,14 @@ ## ORIGIN/LENGTH can be simple symbolic expressions. If the expression ## requires interaction with memory regions, it may fail. -# RUN: echo 'MEMORY { ram : ORIGIN = symbol, LENGTH = 4097 } \ +# RUN: echo 'MEMORY { ram : ORIGIN = symbol, LENGTH = 4094 } \ # RUN: SECTIONS { \ # RUN: .text : { *(.text) } > ram \ # RUN: symbol = .; \ # RUN: .data : { *(.data) } > ram \ # RUN: }' > %t.script # RUN: not ld.lld -T %t.script %t.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR_OVERFLOW %s -# ERR_OVERFLOW: error: section '.text' will not fit in region 'ram': overflowed by 18446744073709547518 bytes +# ERR_OVERFLOW: error: section '.data' will not fit in region 'ram': overflowed by 2 bytes nop