[lld] [ELF] Postpone "unable to move location counter backward" error (PR #66854)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 19 20:16:53 PDT 2023
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/66854
>From 363c4f3e57bfda8ea5ffb9b88df2d7aa2b17a9a2 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Tue, 19 Sep 2023 19:26:42 -0700
Subject: [PATCH] [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 - .; . += __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 | 52 +++++++++++++++++++
.../ELF/linkerscript/locationcountererr.test | 2 +-
5 files changed, 71 insertions(+), 8 deletions(-)
create mode 100644 lld/test/ELF/linkerscript/locationcountererr-arm-exidx.test
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 943fd865ae0c15c..14a89c79a65ecf8 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 89780bb60f48244..a731610e3fdd504 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<SectionCommand *, 0> 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 40f7d7981d9d441..4c82967b0a47d25 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -2187,7 +2187,7 @@ template <class ELFT> void Writer<ELFT>::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
new file mode 100644
index 000000000000000..e01d1d84507dfee
--- /dev/null
+++ b/lld/test/ELF/linkerscript/locationcountererr-arm-exidx.test
@@ -0,0 +1,52 @@
+# REQUIRES: arm
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# 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
+
+# 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: ld.lld -z norelro -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
+
+#--- a.s
+.globl _start
+_start:
+ bx lr
+
+.macro A
+.section .text.f\@,"ax"
+.globl f\@
+f\@:
+.fnstart
+ bx lr
+.cantunwind
+.fnend
+.endm
+
+.rept 20
+ A
+.endr
+
+#--- a.t
+MEMORY {
+ CODE (RX) : ORIGIN = 0x4000, LENGTH = 0x70
+}
+__code_end = ORIGIN(CODE) + LENGTH(CODE);
+
+SECTIONS {
+ .text : { *(.text .text.*) } > CODE
+ .ARM.exidx : { *(.ARM.exidx .ARM.exidx.*) } > 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 086bfeba1e3d455..181bc1f8ea00fa4 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 : {
More information about the llvm-commits
mailing list