[PATCH] D122459: [ELF] Fix relocations against .eh_frame

Ayrton Muñoz via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 24 22:00:18 PDT 2022


ayrtonm created this revision.
ayrtonm added a reviewer: ruiu.
Herald added subscribers: atanasyan, jrtc27, JDevlieghere, arichardson, emaste.
Herald added a reviewer: MaskRay.
Herald added a project: All.
ayrtonm requested review of this revision.
Herald added subscribers: llvm-commits, StephenFan.
Herald added a project: LLVM.

`SectionBase::getOffset` translates offsets in input sections to offsets in the
output sections, but it previously returned input offsets unchanged for
.eh_frame. This gives incorrect offsets for relocations against .eh_frame when
linking multiple .eh_frame sections. This commit calculates the output offset
the same way as MergeInputSection since both are handled as a vector of section
pieces instead of a single blob. This fixes unwinding in the simplest scenarios
on the rust psp target.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D122459

Files:
  lld/ELF/InputSection.cpp
  lld/ELF/InputSection.h
  lld/test/ELF/mips-eh_frame-offset.s


Index: lld/test/ELF/mips-eh_frame-offset.s
===================================================================
--- /dev/null
+++ lld/test/ELF/mips-eh_frame-offset.s
@@ -0,0 +1,18 @@
+# REQUIRES: mips
+## Check that offsets for emitted relocations are correct when linking multiple
+## .eh_frame sections
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t-1.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t-2.o
+# RUN: ld.lld --emit-relocs --entry=0 %t-1.o %t-2.o -o %t.exe
+# RUN: llvm-readobj -r %t.exe | FileCheck %s --check-prefix=RELOCS
+
+# RELOCS:        [[OFFSET:0x[0-9,A-F]+]] R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE .text 0x0
+# RELOCS-NOT:    [[OFFSET]] R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE .text 0x10
+
+.ent func
+func:
+	.cfi_startproc
+	nop
+	.cfi_endproc
+.end func
Index: lld/ELF/InputSection.h
===================================================================
--- lld/ELF/InputSection.h
+++ lld/ELF/InputSection.h
@@ -325,6 +325,15 @@
   SmallVector<EhSectionPiece, 0> pieces;
 
   SyntheticSection *getParent() const;
+  // Translate an offset in the input section to an offset in the parent
+  // MergeSyntheticSection.
+  uint64_t getParentOffset(uint64_t offset) const;
+
+  // Returns the SectionPiece at a given input section offset.
+  EhSectionPiece *getSectionPiece(uint64_t offset);
+  const EhSectionPiece *getSectionPiece(uint64_t offset) const {
+    return const_cast<EhInputSection *>(this)->getSectionPiece(offset);
+  }
 };
 
 // This is a section that is added directly to an output section
Index: lld/ELF/InputSection.cpp
===================================================================
--- lld/ELF/InputSection.cpp
+++ lld/ELF/InputSection.cpp
@@ -160,11 +160,15 @@
   case Regular:
   case Synthetic:
     return cast<InputSection>(this)->outSecOff + offset;
-  case EHFrame:
+  case EHFrame: {
     // The file crtbeginT.o has relocations pointing to the start of an empty
     // .eh_frame that is known to be the first in the link. It does that to
     // identify the start of the output .eh_frame.
-    return offset;
+    const EhInputSection *es = cast<EhInputSection>(this);
+    if (InputSection *isec = es->getParent())
+      return isec->outSecOff + es->getParentOffset(offset);
+    return es->getParentOffset(offset);
+  }
   case Merge:
     const MergeInputSection *ms = cast<MergeInputSection>(this);
     if (InputSection *isec = ms->getParent())
@@ -1334,6 +1338,29 @@
                 getObjMsg(d.data() - rawData.data()));
 }
 
+EhSectionPiece *EhInputSection::getSectionPiece(uint64_t offset) {
+  if (this->data().size() <= offset)
+    fatal(toString(this) + ": offset is outside the section");
+
+  // If Offset is not at beginning of a section piece, it is not in the map.
+  // In that case we need to do a binary search of the original section piece
+  // vector.
+  auto it = partition_point(
+      pieces, [=](EhSectionPiece p) { return p.inputOff <= offset; });
+  return &it[-1];
+}
+
+// Returns the offset in an output section for a given input offset.
+// Because contents of an eh_frame section is not contiguous in input,
+// it is not just an addition to a base output offset.
+uint64_t EhInputSection::getParentOffset(uint64_t offset) const {
+  // If Offset is not at beginning of a section piece, it is not in the map.
+  // In that case we need to search from the original section piece vector.
+  const EhSectionPiece &piece = *getSectionPiece(offset);
+  uint64_t addend = offset - piece.inputOff;
+  return piece.outputOff + addend;
+}
+
 static size_t findNull(StringRef s, size_t entSize) {
   for (unsigned i = 0, n = s.size(); i != n; i += entSize) {
     const char *b = s.begin() + i;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D122459.418130.patch
Type: text/x-patch
Size: 3711 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20220325/02d5e3e8/attachment.bin>


More information about the llvm-commits mailing list