[llvm] [JITLink] Allow multiple relocations at same offset in EHFrameEdgeFixer (PR #68252)

Jonas Hahnfeld via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 4 13:10:18 PDT 2023


https://github.com/hahnjo created https://github.com/llvm/llvm-project/pull/68252

The pass only requires that it can determine a uniquely identified target at some offsets. Multiple relocations at the same offset are fine otherwise and will be required when adding exception handling support for RISC-V.

---

This PR depends on https://github.com/llvm/llvm-project/pull/66707; only the top-most commit should be reviewed here.

>From 2b437c3520da880cbc4745f92fc096ee405f8ae1 Mon Sep 17 00:00:00 2001
From: Jonas Hahnfeld <hahnjo at hahnjo.de>
Date: Mon, 18 Sep 2023 21:53:21 +0200
Subject: [PATCH 1/4] [JITLink][EHFrameSupport] Remove unused variable

---
 llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
index 86249591a9be053..63ba765c8620ed1 100644
--- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
@@ -138,7 +138,6 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
       BlockEdges[E.getOffset()] = EdgeTarget(E);
     }
 
-  CIEInfosMap CIEInfos;
   BinaryStreamReader BlockReader(
       StringRef(B.getContent().data(), B.getContent().size()),
       PC.G.getEndianness());

>From 6fa388c69f3317c03a55b018427159fdba1c7607 Mon Sep 17 00:00:00 2001
From: Jonas Hahnfeld <hahnjo at hahnjo.de>
Date: Mon, 18 Sep 2023 21:22:53 +0200
Subject: [PATCH 2/4] [JITLink][EHFrameSupport] Error on existing edge at CIE
 pointer field

---
 .../JITLink/EHFrameSupport.cpp                | 48 +++++++------------
 1 file changed, 17 insertions(+), 31 deletions(-)

diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
index 63ba765c8620ed1..7b2af45ad3ce666 100644
--- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
@@ -325,40 +325,26 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
   {
     // Process the CIE pointer field.
     auto CIEEdgeItr = BlockEdges.find(RecordOffset + CIEDeltaFieldOffset);
+    if (CIEEdgeItr != BlockEdges.end())
+      return make_error<JITLinkError>(
+          "CIE pointer field already has edge at " +
+          formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset));
+
     orc::ExecutorAddr CIEAddress =
         RecordAddress + orc::ExecutorAddrDiff(CIEDeltaFieldOffset) -
         orc::ExecutorAddrDiff(CIEDelta);
-    if (CIEEdgeItr == BlockEdges.end()) {
-
-      LLVM_DEBUG({
-        dbgs() << "        Adding edge at "
-               << (RecordAddress + CIEDeltaFieldOffset)
-               << " to CIE at: " << CIEAddress << "\n";
-      });
-      if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
-        CIEInfo = *CIEInfoOrErr;
-      else
-        return CIEInfoOrErr.takeError();
-      assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");
-      B.addEdge(NegDelta32, RecordOffset + CIEDeltaFieldOffset,
-                *CIEInfo->CIESymbol, 0);
-    } else {
-      LLVM_DEBUG({
-        dbgs() << "        Already has edge at "
-               << (RecordAddress + CIEDeltaFieldOffset) << " to CIE at "
-               << CIEAddress << "\n";
-      });
-      auto &EI = CIEEdgeItr->second;
-      if (EI.Addend)
-        return make_error<JITLinkError>(
-            "CIE edge at " +
-            formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) +
-            " has non-zero addend");
-      if (auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))
-        CIEInfo = *CIEInfoOrErr;
-      else
-        return CIEInfoOrErr.takeError();
-    }
+    LLVM_DEBUG({
+      dbgs() << "        Adding edge at "
+             << (RecordAddress + CIEDeltaFieldOffset)
+             << " to CIE at: " << CIEAddress << "\n";
+    });
+    if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
+      CIEInfo = *CIEInfoOrErr;
+    else
+      return CIEInfoOrErr.takeError();
+    assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");
+    B.addEdge(NegDelta32, RecordOffset + CIEDeltaFieldOffset,
+              *CIEInfo->CIESymbol, 0);
   }
 
   // Process the PC-Begin field.

>From a73e2159064a58accf5fc72c9955114dc6cb07cf Mon Sep 17 00:00:00 2001
From: Jonas Hahnfeld <hahnjo at hahnjo.de>
Date: Mon, 18 Sep 2023 23:49:04 +0200
Subject: [PATCH 3/4] [JITLink] Simplify CFI processing in EHFrameEdgeFixer

The code expects DWARFRecordSectionSplitter to split each CFI record
into its own block, so remove loop over possibly multiple entries in
one block.
---
 .../JITLink/EHFrameSupport.cpp                | 101 +++++++-----------
 .../JITLink/EHFrameSupportImpl.h              |   6 +-
 .../JITLink/AArch64/ELF_ehframe.s             |  21 ++--
 .../JITLink/AArch64/MachO_ehframe.s           |  14 ++-
 .../LoongArch/ELF_loongarch64_ehframe.s       |  21 ++--
 .../JITLink/ppc64/ELF_ppc64_ehframe.s         |  14 ++-
 6 files changed, 71 insertions(+), 106 deletions(-)

diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
index 7b2af45ad3ce666..c095b13e8c30c56 100644
--- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
@@ -141,67 +141,49 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
   BinaryStreamReader BlockReader(
       StringRef(B.getContent().data(), B.getContent().size()),
       PC.G.getEndianness());
-  while (!BlockReader.empty()) {
-    size_t RecordStartOffset = BlockReader.getOffset();
 
-    LLVM_DEBUG({
-      dbgs() << "    Processing CFI record at "
-             << (B.getAddress() + RecordStartOffset) << "\n";
-    });
-
-    // Get the record length.
-    Expected<size_t> RecordRemaining = readCFIRecordLength(B, BlockReader);
-    if (!RecordRemaining)
-      return RecordRemaining.takeError();
-
-    if (BlockReader.bytesRemaining() < *RecordRemaining)
-      return make_error<JITLinkError>(
-          "Incomplete CFI record at " +
-          formatv("{0:x16}", B.getAddress() + RecordStartOffset));
+  // Get the record length.
+  Expected<size_t> RecordRemaining = readCFIRecordLength(B, BlockReader);
+  if (!RecordRemaining)
+    return RecordRemaining.takeError();
+
+  // We expect DWARFRecordSectionSplitter to split each CFI record into its own
+  // block.
+  if (BlockReader.bytesRemaining() != *RecordRemaining)
+    return make_error<JITLinkError>("Incomplete CFI record at " +
+                                    formatv("{0:x16}", B.getAddress()));
+
+  // Read the CIE delta for this record.
+  uint64_t CIEDeltaFieldOffset = BlockReader.getOffset();
+  uint32_t CIEDelta;
+  if (auto Err = BlockReader.readInteger(CIEDelta))
+    return Err;
 
-    // Read the CIE delta for this record.
-    uint64_t CIEDeltaFieldOffset = BlockReader.getOffset() - RecordStartOffset;
-    uint32_t CIEDelta;
-    if (auto Err = BlockReader.readInteger(CIEDelta))
+  if (CIEDelta == 0) {
+    if (auto Err = processCIE(PC, B, CIEDeltaFieldOffset, BlockEdges))
+      return Err;
+  } else {
+    if (auto Err = processFDE(PC, B, CIEDeltaFieldOffset, CIEDelta, BlockEdges))
       return Err;
-
-    if (CIEDelta == 0) {
-      if (auto Err = processCIE(PC, B, RecordStartOffset,
-                                CIEDeltaFieldOffset + *RecordRemaining,
-                                CIEDeltaFieldOffset, BlockEdges))
-        return Err;
-    } else {
-      if (auto Err = processFDE(PC, B, RecordStartOffset,
-                                CIEDeltaFieldOffset + *RecordRemaining,
-                                CIEDeltaFieldOffset, CIEDelta, BlockEdges))
-        return Err;
-    }
-
-    // Move to the next record.
-    BlockReader.setOffset(RecordStartOffset + CIEDeltaFieldOffset +
-                          *RecordRemaining);
   }
 
   return Error::success();
 }
 
 Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
-                                   size_t RecordOffset, size_t RecordLength,
                                    size_t CIEDeltaFieldOffset,
                                    const BlockEdgeMap &BlockEdges) {
 
-  LLVM_DEBUG(dbgs() << "      Record is CIE\n");
+  LLVM_DEBUG(dbgs() << "    Record is CIE\n");
 
-  auto RecordContent = B.getContent().slice(RecordOffset, RecordLength);
   BinaryStreamReader RecordReader(
-      StringRef(RecordContent.data(), RecordContent.size()),
+      StringRef(B.getContent().data(), B.getContent().size()),
       PC.G.getEndianness());
 
   // Skip past the CIE delta field: we've already processed this far.
   RecordReader.setOffset(CIEDeltaFieldOffset + 4);
 
-  auto &CIESymbol =
-      PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false);
+  auto &CIESymbol = PC.G.addAnonymousSymbol(B, 0, B.getSize(), false, false);
   CIEInformation CIEInfo(CIESymbol);
 
   uint8_t Version = 0;
@@ -267,7 +249,7 @@ Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
         if (auto Err =
                 getOrCreateEncodedPointerEdge(
                     PC, BlockEdges, *PersonalityPointerEncoding, RecordReader,
-                    B, RecordOffset + RecordReader.getOffset(), "personality")
+                    B, RecordReader.getOffset(), "personality")
                     .takeError())
           return Err;
         break;
@@ -278,7 +260,7 @@ Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
           if (CIEInfo.AddressEncoding == dwarf::DW_EH_PE_omit)
             return make_error<JITLinkError>(
                 "Invalid address encoding DW_EH_PE_omit in CIE at " +
-                formatv("{0:x}", (B.getAddress() + RecordOffset).getValue()));
+                formatv("{0:x}", B.getAddress().getValue()));
         } else
           return PE.takeError();
         break;
@@ -301,30 +283,27 @@ Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
 }
 
 Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
-                                   size_t RecordOffset, size_t RecordLength,
                                    size_t CIEDeltaFieldOffset,
                                    uint32_t CIEDelta,
                                    const BlockEdgeMap &BlockEdges) {
-  LLVM_DEBUG(dbgs() << "      Record is FDE\n");
+  LLVM_DEBUG(dbgs() << "    Record is FDE\n");
 
-  orc::ExecutorAddr RecordAddress = B.getAddress() + RecordOffset;
+  orc::ExecutorAddr RecordAddress = B.getAddress();
 
-  auto RecordContent = B.getContent().slice(RecordOffset, RecordLength);
   BinaryStreamReader RecordReader(
-      StringRef(RecordContent.data(), RecordContent.size()),
+      StringRef(B.getContent().data(), B.getContent().size()),
       PC.G.getEndianness());
 
   // Skip past the CIE delta field: we've already read this far.
   RecordReader.setOffset(CIEDeltaFieldOffset + 4);
 
-  auto &FDESymbol =
-      PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false);
+  auto &FDESymbol = PC.G.addAnonymousSymbol(B, 0, B.getSize(), false, false);
 
   CIEInformation *CIEInfo = nullptr;
 
   {
     // Process the CIE pointer field.
-    auto CIEEdgeItr = BlockEdges.find(RecordOffset + CIEDeltaFieldOffset);
+    auto CIEEdgeItr = BlockEdges.find(CIEDeltaFieldOffset);
     if (CIEEdgeItr != BlockEdges.end())
       return make_error<JITLinkError>(
           "CIE pointer field already has edge at " +
@@ -334,8 +313,7 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
         RecordAddress + orc::ExecutorAddrDiff(CIEDeltaFieldOffset) -
         orc::ExecutorAddrDiff(CIEDelta);
     LLVM_DEBUG({
-      dbgs() << "        Adding edge at "
-             << (RecordAddress + CIEDeltaFieldOffset)
+      dbgs() << "      Adding edge at " << (RecordAddress + CIEDeltaFieldOffset)
              << " to CIE at: " << CIEAddress << "\n";
     });
     if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
@@ -343,13 +321,12 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
     else
       return CIEInfoOrErr.takeError();
     assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");
-    B.addEdge(NegDelta32, RecordOffset + CIEDeltaFieldOffset,
-              *CIEInfo->CIESymbol, 0);
+    B.addEdge(NegDelta32, CIEDeltaFieldOffset, *CIEInfo->CIESymbol, 0);
   }
 
   // Process the PC-Begin field.
   LLVM_DEBUG({
-    dbgs() << "        Processing PC-begin at "
+    dbgs() << "      Processing PC-begin at "
            << (RecordAddress + RecordReader.getOffset()) << "\n";
   });
   if (auto PCBegin = getOrCreateEncodedPointerEdge(
@@ -360,14 +337,14 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
       // Add a keep-alive edge from the FDE target to the FDE to ensure that the
       // FDE is kept alive if its target is.
       LLVM_DEBUG({
-        dbgs() << "        Adding keep-alive edge from target at "
+        dbgs() << "      Adding keep-alive edge from target at "
                << (*PCBegin)->getBlock().getAddress() << " to FDE at "
                << RecordAddress << "\n";
       });
       (*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
     } else {
       LLVM_DEBUG({
-        dbgs() << "        WARNING: Not adding keep-alive edge to FDE at "
+        dbgs() << "      WARNING: Not adding keep-alive edge to FDE at "
                << RecordAddress << ", which points to "
                << ((*PCBegin)->isExternal() ? "external" : "absolute")
                << " symbol \"" << (*PCBegin)->getName()
@@ -394,7 +371,7 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
                          .takeError())
         return Err;
   } else {
-    LLVM_DEBUG(dbgs() << "        Record does not have LSDA field.\n");
+    LLVM_DEBUG(dbgs() << "      Record does not have LSDA field.\n");
   }
 
   return Error::success();
@@ -519,7 +496,7 @@ Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
     auto EdgeI = BlockEdges.find(PointerFieldOffset);
     if (EdgeI != BlockEdges.end()) {
       LLVM_DEBUG({
-        dbgs() << "        Existing edge at "
+        dbgs() << "      Existing edge at "
                << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
                << FieldName << " at " << EdgeI->second.Target->getAddress();
         if (EdgeI->second.Target->hasName())
@@ -581,7 +558,7 @@ Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
   BlockToFix.addEdge(PtrEdgeKind, PointerFieldOffset, *TargetSym, 0);
 
   LLVM_DEBUG({
-    dbgs() << "        Adding edge at "
+    dbgs() << "      Adding edge at "
            << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
            << FieldName << " at " << TargetSym->getAddress();
     if (TargetSym->hasName())
diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
index 55cf7fc63ee7957..cc3c24cc85ead03 100644
--- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
+++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
@@ -81,11 +81,9 @@ class EHFrameEdgeFixer {
   };
 
   Error processBlock(ParseContext &PC, Block &B);
-  Error processCIE(ParseContext &PC, Block &B, size_t RecordOffset,
-                   size_t RecordLength, size_t CIEDeltaFieldOffset,
+  Error processCIE(ParseContext &PC, Block &B, size_t CIEDeltaFieldOffset,
                    const BlockEdgeMap &BlockEdges);
-  Error processFDE(ParseContext &PC, Block &B, size_t RecordOffset,
-                   size_t RecordLength, size_t CIEDeltaFieldOffset,
+  Error processFDE(ParseContext &PC, Block &B, size_t CIEDeltaFieldOffset,
                    uint32_t CIEDelta, const BlockEdgeMap &BlockEdges);
 
   Expected<AugmentationInfo>
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_ehframe.s b/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_ehframe.s
index 770cd60a1d70d76..716c4e5abd3fb9d 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_ehframe.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch64/ELF_ehframe.s
@@ -13,20 +13,17 @@
 # CHECK:      Extracted {{.*}} section = .eh_frame
 # CHECK: EHFrameEdgeFixer: Processing .eh_frame in "{{.*}}"...
 # CHECK:   Processing block at
-# CHECK:     Processing CFI record at
-# CHECK:       Record is CIE
+# CHECK:     Record is CIE
 # CHECK:   Processing block at
-# CHECK:     Processing CFI record at
-# CHECK:       Record is FDE
-# CHECK:         Adding edge at {{.*}} to CIE at: {{.*}}
-# CHECK:         Existing edge at {{.*}} to PC begin at {{.*}}
-# CHECK:         Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
+# CHECK:     Record is FDE
+# CHECK:       Adding edge at {{.*}} to CIE at: {{.*}}
+# CHECK:       Existing edge at {{.*}} to PC begin at {{.*}}
+# CHECK:       Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
 # CHECK:   Processing block at
-# CHECK:     Processing CFI record at
-# CHECK:       Record is FDE
-# CHECK:         Adding edge at {{.*}} to CIE at: {{.*}}
-# CHECK:         Existing edge at {{.*}} to PC begin at {{.*}}
-# CHECK:         Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
+# CHECK:     Record is FDE
+# CHECK:       Adding edge at {{.*}} to CIE at: {{.*}}
+# CHECK:       Existing edge at {{.*}} to PC begin at {{.*}}
+# CHECK:       Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
 
 	.text
 	.globl	main
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_ehframe.s b/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_ehframe.s
index 5f821276288617c..4bc006a9a7a2a9a 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_ehframe.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_ehframe.s
@@ -13,15 +13,13 @@
 # CHECK:      Extracted {{.*}} section = __TEXT,__eh_frame
 # CHECK: EHFrameEdgeFixer: Processing __TEXT,__eh_frame in "{{.*}}"...
 # CHECK:   Processing block at
-# CHECK:     Processing CFI record at
-# CHECK:       Record is CIE
+# CHECK:     Record is CIE
 # CHECK:   Processing block at
-# CHECK:     Processing CFI record at
-# CHECK:       Record is FDE
-# CHECK:         Adding edge at {{.*}} to CIE at: {{.*}}
-# CHECK:         Existing edge at {{.*}} to PC begin at {{.*}}
-# CHECK:         Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
-# CHECK:         Existing edge at {{.*}} to LSDA at {{.*}}
+# CHECK:     Record is FDE
+# CHECK:       Adding edge at {{.*}} to CIE at: {{.*}}
+# CHECK:       Existing edge at {{.*}} to PC begin at {{.*}}
+# CHECK:       Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
+# CHECK:       Existing edge at {{.*}} to LSDA at {{.*}}
 
 	.section	__TEXT,__text,regular,pure_instructions
  	.globl	_main
diff --git a/llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_loongarch64_ehframe.s b/llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_loongarch64_ehframe.s
index 4a1a1649508eb62..3eb3cba11da262b 100644
--- a/llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_loongarch64_ehframe.s
+++ b/llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_loongarch64_ehframe.s
@@ -13,20 +13,17 @@
 # CHECK:      Extracted {{.*}} section = .eh_frame
 # CHECK: EHFrameEdgeFixer: Processing .eh_frame in "{{.*}}"...
 # CHECK:   Processing block at
-# CHECK:     Processing CFI record at
-# CHECK:       Record is CIE
+# CHECK:     Record is CIE
 # CHECK:   Processing block at
-# CHECK:     Processing CFI record at
-# CHECK:       Record is FDE
-# CHECK:         Adding edge at {{.*}} to CIE at: {{.*}}
-# CHECK:         Existing edge at {{.*}} to PC begin at {{.*}}
-# CHECK:         Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
+# CHECK:     Record is FDE
+# CHECK:       Adding edge at {{.*}} to CIE at: {{.*}}
+# CHECK:       Existing edge at {{.*}} to PC begin at {{.*}}
+# CHECK:       Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
 # CHECK:   Processing block at
-# CHECK:     Processing CFI record at
-# CHECK:       Record is FDE
-# CHECK:         Adding edge at {{.*}} to CIE at: {{.*}}
-# CHECK:         Existing edge at {{.*}} to PC begin at {{.*}}
-# CHECK:         Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
+# CHECK:     Record is FDE
+# CHECK:       Adding edge at {{.*}} to CIE at: {{.*}}
+# CHECK:       Existing edge at {{.*}} to PC begin at {{.*}}
+# CHECK:       Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
 
  .text
  .globl main
diff --git a/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64_ehframe.s b/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64_ehframe.s
index 3b84768ce786654..13e9006b7a8a817 100644
--- a/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64_ehframe.s
+++ b/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64_ehframe.s
@@ -16,15 +16,13 @@
 # CHECK:       Extracted {{.*}} section = .eh_frame
 # CHECK: EHFrameEdgeFixer: Processing .eh_frame in "{{.*}}"...
 # CHECK:   Processing block at
-# CHECK:     Processing CFI record at
-# CHECK:       Record is CIE
+# CHECK:     Record is CIE
 # CHECK:   Processing block at
-# CHECK:     Processing CFI record at
-# CHECK:       Record is FDE
-# CHECK:         Adding edge at {{.*}} to CIE at: {{.*}}
-# CHECK:         Processing PC-begin at
-# CHECK:         Existing edge at {{.*}} to PC begin at {{.*}}
-# CHECK:         Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
+# CHECK:     Record is FDE
+# CHECK:       Adding edge at {{.*}} to CIE at: {{.*}}
+# CHECK:       Processing PC-begin at
+# CHECK:       Existing edge at {{.*}} to PC begin at {{.*}}
+# CHECK:       Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
 
 	.text
 	.abiversion 2

>From a9d51108f86fed6c799aa6bd1d7055e0eddb3b8d Mon Sep 17 00:00:00 2001
From: Jonas Hahnfeld <hahnjo at hahnjo.de>
Date: Wed, 4 Oct 2023 21:09:46 +0200
Subject: [PATCH 4/4] [JITLink] Allow multiple relocations at same offset in
 EHFrameEdgeFixer

The pass only requires that it can determine a uniquely identified
target at some offsets. Multiple relocations at the same offset are
fine otherwise and will be required when adding exception handling
support for RISC-V.
---
 .../JITLink/EHFrameSupport.cpp                | 45 ++++++++++++-------
 .../JITLink/EHFrameSupportImpl.h              | 16 ++++---
 2 files changed, 40 insertions(+), 21 deletions(-)

diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
index c095b13e8c30c56..f036445497cafd5 100644
--- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
@@ -126,16 +126,23 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
   }
 
   // Find the offsets of any existing edges from this block.
-  BlockEdgeMap BlockEdges;
+  BlockEdgesInfo BlockEdges;
   for (auto &E : B.edges())
     if (E.isRelocation()) {
-      if (BlockEdges.count(E.getOffset()))
-        return make_error<JITLinkError>(
-            "Multiple relocations at offset " +
-            formatv("{0:x16}", E.getOffset()) + " in " + EHFrameSectionName +
-            " block at address " + formatv("{0:x16}", B.getAddress()));
-
-      BlockEdges[E.getOffset()] = EdgeTarget(E);
+      // Check if we already saw more than one relocation at this offset.
+      if (BlockEdges.Multiple.contains(E.getOffset()))
+        continue;
+
+      // Otherwise check if we previously had exactly one relocation at this
+      // offset. If so, we now have a second one and move it from the TargetMap
+      // into the Multiple set.
+      auto It = BlockEdges.TargetMap.find(E.getOffset());
+      if (It != BlockEdges.TargetMap.end()) {
+        BlockEdges.TargetMap.erase(It);
+        BlockEdges.Multiple.insert(E.getOffset());
+      } else {
+        BlockEdges.TargetMap[E.getOffset()] = EdgeTarget(E);
+      }
     }
 
   BinaryStreamReader BlockReader(
@@ -172,7 +179,7 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
 
 Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
                                    size_t CIEDeltaFieldOffset,
-                                   const BlockEdgeMap &BlockEdges) {
+                                   const BlockEdgesInfo &BlockEdges) {
 
   LLVM_DEBUG(dbgs() << "    Record is CIE\n");
 
@@ -285,7 +292,7 @@ Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
 Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
                                    size_t CIEDeltaFieldOffset,
                                    uint32_t CIEDelta,
-                                   const BlockEdgeMap &BlockEdges) {
+                                   const BlockEdgesInfo &BlockEdges) {
   LLVM_DEBUG(dbgs() << "    Record is FDE\n");
 
   orc::ExecutorAddr RecordAddress = B.getAddress();
@@ -303,11 +310,15 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
 
   {
     // Process the CIE pointer field.
-    auto CIEEdgeItr = BlockEdges.find(CIEDeltaFieldOffset);
-    if (CIEEdgeItr != BlockEdges.end())
+    auto CIEEdgeItr = BlockEdges.TargetMap.find(CIEDeltaFieldOffset);
+    if (CIEEdgeItr != BlockEdges.TargetMap.end())
       return make_error<JITLinkError>(
           "CIE pointer field already has edge at " +
           formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset));
+    if (BlockEdges.Multiple.contains(CIEDeltaFieldOffset))
+      return make_error<JITLinkError>(
+          "CIE pointer field already has multiple edges at " +
+          formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset));
 
     orc::ExecutorAddr CIEAddress =
         RecordAddress + orc::ExecutorAddrDiff(CIEDeltaFieldOffset) -
@@ -482,7 +493,7 @@ Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding,
 }
 
 Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
-    ParseContext &PC, const BlockEdgeMap &BlockEdges, uint8_t PointerEncoding,
+    ParseContext &PC, const BlockEdgesInfo &BlockEdges, uint8_t PointerEncoding,
     BinaryStreamReader &RecordReader, Block &BlockToFix,
     size_t PointerFieldOffset, const char *FieldName) {
   using namespace dwarf;
@@ -493,8 +504,8 @@ Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
   // If there's already an edge here then just skip the encoded pointer and
   // return the edge's target.
   {
-    auto EdgeI = BlockEdges.find(PointerFieldOffset);
-    if (EdgeI != BlockEdges.end()) {
+    auto EdgeI = BlockEdges.TargetMap.find(PointerFieldOffset);
+    if (EdgeI != BlockEdges.TargetMap.end()) {
       LLVM_DEBUG({
         dbgs() << "      Existing edge at "
                << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
@@ -507,6 +518,10 @@ Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
         return std::move(Err);
       return EdgeI->second.Target;
     }
+
+    if (BlockEdges.Multiple.contains(PointerFieldOffset))
+      return make_error<JITLinkError>("Multiple relocations at offset " +
+                                      formatv("{0:x16}", PointerFieldOffset));
   }
 
   // Switch absptr to corresponding udata encoding.
diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
index cc3c24cc85ead03..49fbf650e7a775e 100644
--- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
+++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
@@ -60,7 +60,11 @@ class EHFrameEdgeFixer {
     Edge::AddendT Addend = 0;
   };
 
-  using BlockEdgeMap = DenseMap<Edge::OffsetT, EdgeTarget>;
+  struct BlockEdgesInfo {
+    DenseMap<Edge::OffsetT, EdgeTarget> TargetMap;
+    DenseSet<Edge::OffsetT> Multiple;
+  };
+
   using CIEInfosMap = DenseMap<orc::ExecutorAddr, CIEInformation>;
 
   struct ParseContext {
@@ -82,9 +86,9 @@ class EHFrameEdgeFixer {
 
   Error processBlock(ParseContext &PC, Block &B);
   Error processCIE(ParseContext &PC, Block &B, size_t CIEDeltaFieldOffset,
-                   const BlockEdgeMap &BlockEdges);
+                   const BlockEdgesInfo &BlockEdges);
   Error processFDE(ParseContext &PC, Block &B, size_t CIEDeltaFieldOffset,
-                   uint32_t CIEDelta, const BlockEdgeMap &BlockEdges);
+                   uint32_t CIEDelta, const BlockEdgesInfo &BlockEdges);
 
   Expected<AugmentationInfo>
   parseAugmentationString(BinaryStreamReader &RecordReader);
@@ -94,9 +98,9 @@ class EHFrameEdgeFixer {
   Error skipEncodedPointer(uint8_t PointerEncoding,
                            BinaryStreamReader &RecordReader);
   Expected<Symbol *> getOrCreateEncodedPointerEdge(
-      ParseContext &PC, const BlockEdgeMap &BlockEdges, uint8_t PointerEncoding,
-      BinaryStreamReader &RecordReader, Block &BlockToFix,
-      size_t PointerFieldOffset, const char *FieldName);
+      ParseContext &PC, const BlockEdgesInfo &BlockEdges,
+      uint8_t PointerEncoding, BinaryStreamReader &RecordReader,
+      Block &BlockToFix, size_t PointerFieldOffset, const char *FieldName);
 
   Expected<Symbol &> getOrCreateSymbol(ParseContext &PC,
                                        orc::ExecutorAddr Addr);



More information about the llvm-commits mailing list