[lld] e4118a7 - [ELF] Fix early overflow check in finalizeAddressDependentContent

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 14 15:26:36 PDT 2023


Author: Andreu Carminati
Date: 2023-06-14T15:26:31-07:00
New Revision: e4118a7ac0fc2347e78d7c87a1663b70e8ab71ed

URL: https://github.com/llvm/llvm-project/commit/e4118a7ac0fc2347e78d7c87a1663b70e8ab71ed
DIFF: https://github.com/llvm/llvm-project/commit/e4118a7ac0fc2347e78d7c87a1663b70e8ab71ed.diff

LOG: [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

Added: 
    lld/test/ELF/linkerscript/end-overflow-check.test

Modified: 
    lld/ELF/LinkerScript.cpp
    lld/ELF/LinkerScript.h
    lld/ELF/Writer.cpp
    lld/test/ELF/linkerscript/memory-err.s

Removed: 
    


################################################################################
diff  --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 295b078653fe0..777f1f2f85f95 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -157,12 +157,6 @@ OutputDesc *LinkerScript::getOrCreateOutputSection(StringRef name) {
 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) {
@@ -1461,3 +1455,23 @@ void LinkerScript::printMemoryUsage(raw_ostream& os) {
     os << '\n';
   }
 }
+
+static void checkMemoryRegion(const MemoryRegion *region,
+                              const OutputSection *osec, uint64_t addr) {
+  uint64_t osecEnd = addr + osec->size;
+  uint64_t regionEnd = region->getOrigin() + region->getLength();
+  if (osecEnd > regionEnd) {
+    error("section '" + osec->name + "' will not fit in region '" +
+          region->name + "': overflowed by " + Twine(osecEnd - regionEnd) +
+          " bytes");
+  }
+}
+
+void LinkerScript::checkMemoryRegions() const {
+  for (const OutputSection *sec : outputSections) {
+    if (const MemoryRegion *memoryRegion = sec->memRegion)
+      checkMemoryRegion(memoryRegion, sec, sec->addr);
+    if (const MemoryRegion *lmaRegion = sec->lmaRegion)
+      checkMemoryRegion(lmaRegion, sec, sec->getLMA());
+  }
+}

diff  --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h
index 5b21cd5e619b1..ee0985ae94382 100644
--- a/lld/ELF/LinkerScript.h
+++ b/lld/ELF/LinkerScript.h
@@ -339,6 +339,9 @@ class LinkerScript final {
   // Describe memory region usage.
   void printMemoryUsage(raw_ostream &os);
 
+  // Verify memory/lma overflows.
+  void checkMemoryRegions() const;
+
   // SECTIONS command list.
   SmallVector<SectionCommand *, 0> sectionCommands;
 

diff  --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 25cb67a519692..3630b199714da 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -2147,6 +2147,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
   // of finalizing other sections.
   for (OutputSection *sec : outputSections)
     sec->finalize();
+
+  script->checkMemoryRegions();
 }
 
 // Ensure data sections are not mixed with executable sections when

diff  --git a/lld/test/ELF/linkerscript/end-overflow-check.test b/lld/test/ELF/linkerscript/end-overflow-check.test
new file mode 100644
index 0000000000000..3d0cd6d832ab6
--- /dev/null
+++ b/lld/test/ELF/linkerscript/end-overflow-check.test
@@ -0,0 +1,74 @@
+REQUIRES: x86
+
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a.s -o %t/a.o
+
+## The error should be triggered only for the second test where the overflow really exists.
+
+RUN: ld.lld %t/a.o -T %t/b.lds -o /dev/null 2>&1
+RUN: not ld.lld %t/a.o -T %t/c.lds -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s
+
+# ERROR: error: section '_abss' will not fit in region 'SRAM0': overflowed by 1024 bytes
+# ERROR: error: section '.c.bss' will not fit in region 'SRAM0': overflowed by 1024 bytes
+# ERROR: error: section '.text' will not fit in region 'SRAM0': overflowed by 1025 bytes
+
+#--- a.s
+.section .a.bss, "aw", %nobits
+.globl abss
+abss:
+.zero 0xDF0
+.size abss, 0xDF0
+
+.section .c.bss, "aw", %nobits
+.globl cbss
+
+.text
+.globl _start
+_start:
+nop
+
+#--- b.lds
+MEMORY
+{
+    SRAM0 (rw) : ORIGIN = 0x20000400, LENGTH = 10K
+}
+
+SECTIONS
+{
+    _abss ALIGN(REGION1__PRE_ALIGNMENT) :
+    {
+        REGION1__BEGIN = .; 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 = 4K
+}
+
+SECTIONS
+{
+    _abss ALIGN(REGION1__PRE_ALIGNMENT) :
+    {
+        REGION1__BEGIN = .; 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;

diff  --git a/lld/test/ELF/linkerscript/memory-err.s b/lld/test/ELF/linkerscript/memory-err.s
index 0b1a077176adf..98e71e79f17d8 100644
--- a/lld/test/ELF/linkerscript/memory-err.s
+++ b/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
 


        


More information about the llvm-commits mailing list