From 0de0b6dded4752040350feb9c81415d82478d065 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Wed, 20 Sep 2023 09:06:45 -0700 Subject: [PATCH] [ELF] Postpone "unable to move location counter backward" error (#66854) The size of .ARM.exidx may shrink across `assignAddress` calls. It is possible that the initial iteration has a larger location counter, causing `__code_size = __code_end - .; osec : { . += __code_size; }` to report an error, while the error would have been suppressed for subsequent `assignAddress` iterations. Other sections like .relr.dyn may change sizes across `assignAddress` calls as well. However, their initial size is zero, so it is difficiult to trigger a similar error. Similar to https://reviews.llvm.org/D152170, postpone the error reporting. Fix #66836. While here, add more information to the error message. --- lld/ELF/LinkerScript.cpp | 18 +++++++++++++---- lld/ELF/LinkerScript.h | 5 +++-- lld/ELF/Writer.cpp | 2 +- .../locationcountererr-arm-exidx.test | 20 ++++++++++--------- .../ELF/linkerscript/locationcountererr.test | 2 +- 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 943fd865ae0c1..df091613dc0a1 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -169,9 +169,16 @@ void LinkerScript::expandOutputSection(uint64_t size) { void LinkerScript::setDot(Expr e, const Twine &loc, bool inSec) { uint64_t val = e().getValue(); - if (val < dot && inSec) - error(loc + ": unable to move location counter backward for: " + - state->outSec->name); + // If val is smaller and we are in an output section, record the error and + // report it if this is the last assignAddresses iteration. dot may be smaller + // if there is another assignAddresses iteration. + if (val < dot && inSec) { + backwardDotErr = + (loc + ": unable to move location counter (0x" + Twine::utohexstr(dot) + + ") backward to 0x" + Twine::utohexstr(val) + " for section '" + + state->outSec->name + "'") + .str(); + } // Update to location counter means update to section size. if (inSec) @@ -1343,6 +1350,7 @@ const Defined *LinkerScript::assignAddresses() { state = &st; errorOnMissingSection = true; st.outSec = aether; + backwardDotErr.clear(); SymbolAssignmentMap oldValues = getSymbolAssignmentValues(sectionCommands); for (SectionCommand *cmd : sectionCommands) { @@ -1494,7 +1502,9 @@ static void checkMemoryRegion(const MemoryRegion *region, } } -void LinkerScript::checkMemoryRegions() const { +void LinkerScript::checkFinalScriptConditions() const { + if (backwardDotErr.size()) + errorOrWarn(backwardDotErr); for (const OutputSection *sec : outputSections) { if (const MemoryRegion *memoryRegion = sec->memRegion) checkMemoryRegion(memoryRegion, sec, sec->addr); diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 89780bb60f482..18eaf58b785e3 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -345,8 +345,8 @@ class LinkerScript final { // Describe memory region usage. void printMemoryUsage(raw_ostream &os); - // Verify memory/lma overflows. - void checkMemoryRegions() const; + // Check backward location counter assignment and memory region/LMA overflows. + void checkFinalScriptConditions() const; // SECTIONS command list. SmallVector sectionCommands; @@ -358,6 +358,7 @@ class LinkerScript final { bool seenDataAlign = false; bool seenRelroEnd = false; bool errorOnMissingSection = false; + std::string backwardDotErr; // List of section patterns specified with KEEP commands. They will // be kept even if they are unused and --gc-sections is specified. diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 40f7d7981d9d4..d6adc4ff3d644 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -2187,7 +2187,7 @@ template void Writer::finalizeSections() { for (OutputSection *sec : outputSections) sec->finalize(); - script->checkMemoryRegions(); + script->checkFinalScriptConditions(); if (config->emachine == EM_ARM && !config->isLE && config->armBe8) { addArmInputSectionMappingSymbols(); diff --git a/lld/test/ELF/linkerscript/locationcountererr-arm-exidx.test b/lld/test/ELF/linkerscript/locationcountererr-arm-exidx.test index 4dd7ae05d0674..791a9ae178fa9 100644 --- a/lld/test/ELF/linkerscript/locationcountererr-arm-exidx.test +++ b/lld/test/ELF/linkerscript/locationcountererr-arm-exidx.test @@ -8,22 +8,24 @@ # RUN: not ld.lld -z norelro -z max-page-size=4096 -T a.t a.o -o /dev/null --no-merge-exidx-entries 2>&1 | \ # RUN: FileCheck %s --check-prefix=ERR --implicit-check-not=error: -# ERR: error: a.t:14: unable to move location counter backward for: code.unused_space -# ERR-NEXT: error: a.t:9: unable to move location counter backward for: dummy1 -# ERR-NEXT: error: a.t:10: unable to move location counter backward for: dummy2 -# ERR-NEXT: error: a.t:14: unable to move location counter backward for: code.unused_space -# ERR-NEXT: error: a.t:9: unable to move location counter backward for: dummy1 -# ERR-NEXT: error: a.t:10: unable to move location counter backward for: dummy2 -# ERR-NEXT: error: a.t:14: unable to move location counter backward for: code.unused_space +# ERR: error: a.t:14: unable to move location counter (0x4104) backward to 0x4070 for section 'code.unused_space' +# ERR-NEXT: error: section '.ARM.exidx' will not fit in region 'CODE': overflowed by 148 bytes # ERR-NEXT: error: section dummy1 at 0x1000 of size 0xFFFFFFFFFFFFFF6C exceeds available address space # ERR-NEXT: error: section dummy2 at 0x2000 of size 0xFFFFFFFFFFFFFF6C exceeds available address space # ERR-NEXT: error: section code.unused_space at 0x4104 of size 0xFFFFFFFFFFFFFF6C exceeds available address space ## If we merge adjacent duplicate entries, we will have enough space. Don't report ## a spurious error https://github.com/llvm/llvm-project/issues/66836 -# RUN: not ld.lld -z norelro -z max-page-size=4096 -T a.t a.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR2 +# RUN: ld.lld -z norelro -z max-page-size=4096 -T a.t a.o -o a +# RUN: llvm-readelf -S a | FileCheck %s -# ERR2: error: a.t:14: unable to move location counter backward for: code.unused_space +# CHECK: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CHECK-NEXT: [ 0] NULL 00000000 000000 000000 00 0 0 0 +# CHECK-NEXT: [ 1] dummy1 NOBITS 00001000 001000 00000c 00 A 0 0 1 +# CHECK-NEXT: [ 2] dummy2 NOBITS 00002000 001000 00000c 00 A 0 0 1 +# CHECK-NEXT: [ 3] .text PROGBITS 00004000 001000 000054 00 AX 0 0 4 +# CHECK-NEXT: [ 4] .ARM.exidx ARM_EXIDX 00004054 001054 000010 00 AL 3 0 4 +# CHECK-NEXT: [ 5] code.unused_space NOBITS 00004064 001064 00000c 00 A 0 0 1 #--- a.s .globl _start diff --git a/lld/test/ELF/linkerscript/locationcountererr.test b/lld/test/ELF/linkerscript/locationcountererr.test index 086bfeba1e3d4..2ab6d7a3ce2cb 100644 --- a/lld/test/ELF/linkerscript/locationcountererr.test +++ b/lld/test/ELF/linkerscript/locationcountererr.test @@ -1,7 +1,7 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t # RUN: not ld.lld %t --script %s -o /dev/null 2>&1 | FileCheck %s -# CHECK: {{.*}}.test:8: unable to move location counter backward for: .text +# CHECK: {{.*}}.test:8: unable to move location counter (0x2000) backward to 0x10 for section '.text' SECTIONS { .text 0x2000 : {