From b12993b40b9ef05dda42adc978c5a3e9aa368507 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Tue, 19 Sep 2023 19:26:42 -0700 Subject: [PATCH 1/3] [ELF] Postpone "unable to move location counter backward" error 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 | 38 +++++++------------ .../ELF/linkerscript/locationcountererr.test | 2 +- 5 files changed, 33 insertions(+), 32 deletions(-) diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 943fd865ae0c1..14a89c79a65ec 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 (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::checkDotAndMemoryRegions() 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..a731610e3fdd5 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 checkDotAndMemoryRegions() 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..4c82967b0a47d 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->checkDotAndMemoryRegions(); 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..e01d1d84507df 100644 --- a/lld/test/ELF/linkerscript/locationcountererr-arm-exidx.test +++ b/lld/test/ELF/linkerscript/locationcountererr-arm-exidx.test @@ -3,27 +3,21 @@ # RUN: llvm-mc -filetype=obj -triple=armv7-linux-gnueabi a.s -o a.o ## If we don't merge adjacent duplicate entries, __code_size will be negative and -## . += __code_size will trigger a "move location counter backward" error. -## LLD may report more errors further down, but there is only one "move location counter backward" error. -# 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-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 +## . += __code_size will trigger an error. +# RUN: not ld.lld -z norelro -T a.t a.o -o /dev/null --no-merge-exidx-entries 2>&1 | FileCheck %s --check-prefix=ERR + +# ERR: a.t:10: unable to move location counter (0x4104) backward (0x4070) for section 'code.unused_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 -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] .text PROGBITS 00004000 004000 000054 00 AX 0 0 4 +# CHECK-NEXT: [ 2] .ARM.exidx ARM_EXIDX 00004054 004054 000010 00 AL 1 0 4 +# CHECK-NEXT: [ 3] code.unused_space NOBITS 00004064 004064 00000c 00 A 0 0 1 #--- a.s .globl _start @@ -46,17 +40,13 @@ f\@: #--- a.t MEMORY { - DUMMY1 (RW) : ORIGIN = 0x1000, LENGTH = 0x70 - DUMMY2 (RW) : ORIGIN = 0x2000, LENGTH = 0x70 CODE (RX) : ORIGIN = 0x4000, LENGTH = 0x70 } -code_end = ORIGIN(CODE) + LENGTH(CODE); +__code_end = ORIGIN(CODE) + LENGTH(CODE); SECTIONS { - dummy1 (NOLOAD) : { . += code_size; } > DUMMY1 - dummy2 (NOLOAD) : { . += code_size; } > DUMMY2 .text : { *(.text .text.*) } > CODE .ARM.exidx : { *(.ARM.exidx .ARM.exidx.*) } > CODE - code_size = code_end - .; - code.unused_space (NOLOAD) : { . += code_size; } > CODE + __code_size = __code_end - .; + code.unused_space (NOLOAD) : { . += __code_size; } > CODE } diff --git a/lld/test/ELF/linkerscript/locationcountererr.test b/lld/test/ELF/linkerscript/locationcountererr.test index 086bfeba1e3d4..181bc1f8ea00f 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 (0x10) for section '.text' SECTIONS { .text 0x2000 : { From 45423a4edd13f15d5dd0ee044905c3bf4656f2ad Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Tue, 19 Sep 2023 22:47:06 -0700 Subject: [PATCH 2/3] improve test --- lld/ELF/LinkerScript.cpp | 2 +- .../locationcountererr-arm-exidx.test | 32 +++++++++++++------ .../ELF/linkerscript/locationcountererr.test | 2 +- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 14a89c79a65ec..08f8bd0a3b542 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -175,7 +175,7 @@ void LinkerScript::setDot(Expr e, const Twine &loc, bool inSec) { if (val < dot && inSec) { backwardDotErr = (loc + ": unable to move location counter (0x" + Twine::utohexstr(dot) + - ") backward (0x" + Twine::utohexstr(val) + ") for section '" + + ") backward to 0x" + Twine::utohexstr(val) + " for section '" + state->outSec->name + "'") .str(); } diff --git a/lld/test/ELF/linkerscript/locationcountererr-arm-exidx.test b/lld/test/ELF/linkerscript/locationcountererr-arm-exidx.test index e01d1d84507df..791a9ae178fa9 100644 --- a/lld/test/ELF/linkerscript/locationcountererr-arm-exidx.test +++ b/lld/test/ELF/linkerscript/locationcountererr-arm-exidx.test @@ -3,21 +3,29 @@ # RUN: llvm-mc -filetype=obj -triple=armv7-linux-gnueabi a.s -o a.o ## If we don't merge adjacent duplicate entries, __code_size will be negative and -## . += __code_size will trigger an error. -# RUN: not ld.lld -z norelro -T a.t a.o -o /dev/null --no-merge-exidx-entries 2>&1 | FileCheck %s --check-prefix=ERR +## . += __code_size will trigger a "move location counter backward" error. +## LLD may report more errors further down, but there is only one "move location counter backward" error. +# 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: a.t:10: unable to move location counter (0x4104) backward (0x4070) for section '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: ld.lld -z norelro -T a.t a.o -o a +# RUN: ld.lld -z norelro -z max-page-size=4096 -T a.t a.o -o a # RUN: llvm-readelf -S a | FileCheck %s # 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] .text PROGBITS 00004000 004000 000054 00 AX 0 0 4 -# CHECK-NEXT: [ 2] .ARM.exidx ARM_EXIDX 00004054 004054 000010 00 AL 1 0 4 -# CHECK-NEXT: [ 3] code.unused_space NOBITS 00004064 004064 00000c 00 A 0 0 1 +# 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 @@ -40,13 +48,17 @@ f\@: #--- a.t MEMORY { + DUMMY1 (RW) : ORIGIN = 0x1000, LENGTH = 0x70 + DUMMY2 (RW) : ORIGIN = 0x2000, LENGTH = 0x70 CODE (RX) : ORIGIN = 0x4000, LENGTH = 0x70 } -__code_end = ORIGIN(CODE) + LENGTH(CODE); +code_end = ORIGIN(CODE) + LENGTH(CODE); SECTIONS { + dummy1 (NOLOAD) : { . += code_size; } > DUMMY1 + dummy2 (NOLOAD) : { . += code_size; } > DUMMY2 .text : { *(.text .text.*) } > CODE .ARM.exidx : { *(.ARM.exidx .ARM.exidx.*) } > CODE - __code_size = __code_end - .; - code.unused_space (NOLOAD) : { . += __code_size; } > CODE + code_size = code_end - .; + code.unused_space (NOLOAD) : { . += code_size; } > CODE } diff --git a/lld/test/ELF/linkerscript/locationcountererr.test b/lld/test/ELF/linkerscript/locationcountererr.test index 181bc1f8ea00f..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 (0x2000) backward (0x10) for section '.text' +# CHECK: {{.*}}.test:8: unable to move location counter (0x2000) backward to 0x10 for section '.text' SECTIONS { .text 0x2000 : { From 0f78cd25ef5abbc75d11aef6306971fe5f8fbb94 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Wed, 20 Sep 2023 08:50:05 -0700 Subject: [PATCH 3/3] Rename checkDotAndMemoryRegions to checkFinalScriptConditions --- lld/ELF/LinkerScript.cpp | 2 +- lld/ELF/LinkerScript.h | 2 +- lld/ELF/Writer.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 08f8bd0a3b542..df091613dc0a1 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -1502,7 +1502,7 @@ static void checkMemoryRegion(const MemoryRegion *region, } } -void LinkerScript::checkDotAndMemoryRegions() const { +void LinkerScript::checkFinalScriptConditions() const { if (backwardDotErr.size()) errorOrWarn(backwardDotErr); for (const OutputSection *sec : outputSections) { diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index a731610e3fdd5..18eaf58b785e3 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -346,7 +346,7 @@ class LinkerScript final { void printMemoryUsage(raw_ostream &os); // Check backward location counter assignment and memory region/LMA overflows. - void checkDotAndMemoryRegions() const; + void checkFinalScriptConditions() const; // SECTIONS command list. SmallVector sectionCommands; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 4c82967b0a47d..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->checkDotAndMemoryRegions(); + script->checkFinalScriptConditions(); if (config->emachine == EM_ARM && !config->isLE && config->armBe8) { addArmInputSectionMappingSymbols();