[llvm] [Object][GOFF] Support RLD records (PR #216780)

Shimin Cui via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 26 06:34:30 PDT 2026


https://github.com/scui-ibm updated https://github.com/llvm/llvm-project/pull/216780

>From 17b495f4549040849ae0e1a645578ebbe5b7042d Mon Sep 17 00:00:00 2001
From: Shimin Cui <scui at ca.ibm.com>
Date: Fri, 14 Aug 2026 22:05:09 +0000
Subject: [PATCH 1/3] [Object][GOFF] Support RLD records

---
 llvm/include/llvm/Object/GOFF.h              |  10 ++
 llvm/include/llvm/Object/GOFFObjectFile.h    |  65 +++++++---
 llvm/lib/Object/GOFFObjectFile.cpp           | 123 ++++++++++++++++++-
 llvm/unittests/Object/GOFFObjectFileTest.cpp |  25 ++++
 4 files changed, 208 insertions(+), 15 deletions(-)

diff --git a/llvm/include/llvm/Object/GOFF.h b/llvm/include/llvm/Object/GOFF.h
index bae7d6d2aba46..145c354a307cc 100644
--- a/llvm/include/llvm/Object/GOFF.h
+++ b/llvm/include/llvm/Object/GOFF.h
@@ -290,6 +290,16 @@ class ESDRecord : public Record {
   }
 };
 
+class RLDRecord : public Record {
+public:
+  LLVM_ABI static Error getData(const uint8_t *Record,
+                                SmallString<256> &CompleteData);
+
+  static void getDataLength(const uint8_t *Record, uint16_t &Length) {
+    get<uint16_t>(Record, 4, Length);
+  }
+};
+
 class ENDRecord : public Record {
 public:
   LLVM_ABI static Error getData(const uint8_t *Record,
diff --git a/llvm/include/llvm/Object/GOFFObjectFile.h b/llvm/include/llvm/Object/GOFFObjectFile.h
index a07f3edf17d07..0bfbbc8d7acd6 100644
--- a/llvm/include/llvm/Object/GOFFObjectFile.h
+++ b/llvm/include/llvm/Object/GOFFObjectFile.h
@@ -29,11 +29,51 @@ namespace llvm {
 
 namespace object {
 
+// RLD entry with all populated fields.
+struct GOFFRelEntry {
+  uint32_t REsdId;
+  uint32_t PEsdId;
+  uint64_t POffset;
+  uint64_t RelType;
+
+  DataRefImpl RefSymb; // Symbol referred to.
+};
+
+// GOFFRelEntry::RelType is computed based on RLD fields at offset 1, 2, 4,
+// and 5.
+inline uint64_t getRldType(uint8_t *Rld) {
+  return Rld[1] + (Rld[2] << 8) + (Rld[4] << 16) + (Rld[5] << 24);
+}
+
+// Getters for RLD fields based on GOFFRelEntry::RelType.
+inline GOFF::RLDReferenceType getRLDReferenceType(uint64_t RelType) {
+  return static_cast<GOFF::RLDReferenceType>((RelType >> 4) & 0x0000000F);
+}
+inline GOFF::RLDReferentType getRLDReferentType(uint64_t RelType) {
+  return static_cast<GOFF::RLDReferentType>((RelType) & 0x0000000F);
+}
+inline GOFF::RLDAction getRLDAction(uint64_t RelType) {
+  return static_cast<GOFF::RLDAction>((RelType >> (8 + 1)) & 0x0000007F);
+}
+inline GOFF::RLDFetchStore getRLDFetchStore(uint64_t RelType) {
+  return static_cast<GOFF::RLDFetchStore>((RelType >> 8) & 0x00000001);
+}
+inline uint8_t getRLDTargetLength(uint64_t RelType) {
+  return static_cast<uint8_t>((RelType >> 16) & 0x000000FF);
+}
+inline uint8_t getRLDBitLength(uint64_t RelType) {
+  return static_cast<uint8_t>((RelType >> (24 + 5)) & 0x00000007);
+}
+inline uint8_t getRLDBitOffset(uint64_t RelType) {
+  return static_cast<uint8_t>((RelType >> 24) & 0x00000007);
+}
+
 class LLVM_ABI GOFFObjectFile : public ObjectFile {
   friend class GOFFSymbolRef;
 
   IndexedMap<const uint8_t *> EsdPtrs; // Indexed by EsdId.
   SmallVector<const uint8_t *, 256> TextPtrs;
+  SmallVector<GOFFRelEntry, 256> RelEntries;
 
   mutable DenseMap<uint32_t, std::pair<size_t, std::unique_ptr<char[]>>>
       EsdNamesCache;
@@ -58,6 +98,8 @@ class LLVM_ABI GOFFObjectFile : public ObjectFile {
                                        int DataIndex, uint16_t DataLength,
                                        const uint8_t *Record) const;
 
+  void setRelocationData(const uint8_t *RldRecord);
+
 public:
   // Get the flattened data structure
   const SmallVector<std::pair<GOFF::RecordType, SmallVector<uint8_t>>> &
@@ -123,12 +165,8 @@ class LLVM_ABI GOFFObjectFile : public ObjectFile {
   bool isSectionData(DataRefImpl Sec) const override;
   bool isSectionBSS(DataRefImpl Sec) const override { return false; }
   bool isSectionVirtual(DataRefImpl Sec) const override { return false; }
-  relocation_iterator section_rel_begin(DataRefImpl Sec) const override {
-    return relocation_iterator(RelocationRef(Sec, this));
-  }
-  relocation_iterator section_rel_end(DataRefImpl Sec) const override {
-    return relocation_iterator(RelocationRef(Sec, this));
-  }
+  relocation_iterator section_rel_begin(DataRefImpl Sec) const override;
+  relocation_iterator section_rel_end(DataRefImpl Sec) const override;
 
   const uint8_t *getSectionEdEsdRecord(DataRefImpl &Sec) const;
   const uint8_t *getSectionPrEsdRecord(DataRefImpl &Sec) const;
@@ -137,15 +175,12 @@ class LLVM_ABI GOFFObjectFile : public ObjectFile {
   uint32_t getSectionDefEsdId(DataRefImpl &Sec) const;
 
   // RelocationRef.
-  void moveRelocationNext(DataRefImpl &Rel) const override {}
-  uint64_t getRelocationOffset(DataRefImpl Rel) const override { return 0; }
-  symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override {
-    DataRefImpl Temp;
-    return basic_symbol_iterator(SymbolRef(Temp, this));
-  }
-  uint64_t getRelocationType(DataRefImpl Rel) const override { return 0; }
+  void moveRelocationNext(DataRefImpl &Rel) const override;
+  uint64_t getRelocationOffset(DataRefImpl Rel) const override;
+  symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override;
+  uint64_t getRelocationType(DataRefImpl Rel) const override;
   void getRelocationTypeName(DataRefImpl Rel,
-                             SmallVectorImpl<char> &Result) const override {}
+                             SmallVectorImpl<char> &Result) const override;
 };
 
 class GOFFSymbolRef : public SymbolRef {
@@ -158,6 +193,8 @@ class GOFFSymbolRef : public SymbolRef {
     return cast<GOFFObjectFile>(BasicSymbolRef::getObject());
   }
 
+  uint32_t getSymbolGOFFEsdId() const { return getRawDataRefImpl().d.a; }
+
   Expected<uint32_t> getSymbolGOFFFlags() const {
     return getObject()->getSymbolFlags(getRawDataRefImpl());
   }
diff --git a/llvm/lib/Object/GOFFObjectFile.cpp b/llvm/lib/Object/GOFFObjectFile.cpp
index e18fcfa0f880c..4960aeaae8440 100644
--- a/llvm/lib/Object/GOFFObjectFile.cpp
+++ b/llvm/lib/Object/GOFFObjectFile.cpp
@@ -261,6 +261,11 @@ GOFFObjectFile::GOFFObjectFile(MemoryBufferRef Object, Error &Err)
   SectionEntryImpl DummySection;
   SectionList.emplace_back(DummySection); // Dummy entry at index 0.
 
+  // Dummy relocation entry at index 0.
+  GOFFRelEntry DummyRelEntry;
+  DummyRelEntry.PEsdId = 0;
+  RelEntries.emplace_back(DummyRelEntry);
+
   for (const auto &[RecordType, Data] : FlattenedData) {
     const uint8_t *I = Data.data();
     switch (RecordType) {
@@ -323,7 +328,8 @@ GOFFObjectFile::GOFFObjectFile(MemoryBufferRef Object, Error &Err)
       LLVM_DEBUG(dbgs() << "  --  TXT\n");
       break;
     case GOFF::RT_RLD:
-      LLVM_DEBUG(dbgs() << "  --  RLD (GOFF record type) unhandled\n");
+      setRelocationData(I);
+      LLVM_DEBUG(dbgs() << "  --  RLD\n");
       break;
     case GOFF::RT_LEN:
       LLVM_DEBUG(dbgs() << "  --  LEN (GOFF record type) unhandled\n");
@@ -759,3 +765,118 @@ basic_symbol_iterator GOFFObjectFile::symbol_end() const {
   DataRefImpl Symb;
   return basic_symbol_iterator(SymbolRef(Symb, this));
 }
+
+// Populate the relocation entries.
+void GOFFObjectFile::setRelocationData(const uint8_t *RldRecord) {
+  SmallVector<uint8_t, 8> RelocationData;
+  int DataIndex = 6;
+  uint16_t DataLength;
+  RLDRecord::getDataLength(RldRecord, DataLength);
+  Expected<unsigned> BlocksConsumed =
+      getContinuousData(RelocationData, DataIndex, DataLength, RldRecord);
+  if (!BlocksConsumed)
+    llvm::handleAllErrors(BlocksConsumed.takeError(),
+                          [](const llvm::ErrorInfoBase &EIB) {
+                            llvm::errs() << "ERROR: " << EIB.message() << "\n";
+                          });
+  assert(static_cast<size_t>(DataLength + DataIndex) == RelocationData.size() &&
+         "Inconsistent rld size");
+
+  uint8_t *RldI = reinterpret_cast<uint8_t *>(RelocationData.data());
+  uint8_t *RldE = RldI + RelocationData.size();
+  for (uint8_t *Rld = RldI + DataIndex; Rld < RldE;) {
+    GOFFRelEntry RelEntry;
+    uint8_t Flags = Rld[0];
+
+#define SAME_R_ID 0x80
+#define SAME_P_ID 0x40
+#define SAME_OFFSET 0x20
+#define EXT_ATTR_PRESENT 0x04
+#define BYTE_OFFSET_8 0x02
+
+    int32_t Length = 8;
+    if (!(Flags & SAME_R_ID)) {
+      RelEntry.REsdId = support::endian::read32be(&Rld[Length]);
+      Length += 4;
+    }
+    if (!(Flags & SAME_P_ID)) {
+      RelEntry.PEsdId = support::endian::read32be(&Rld[Length]);
+      Length += 4;
+    }
+    if (!(Flags & SAME_OFFSET)) {
+      if (Flags & BYTE_OFFSET_8) {
+        RelEntry.POffset = support::endian::read64be(&Rld[Length]);
+        Length += 8;
+      } else {
+        RelEntry.POffset = support::endian::read32be(&Rld[Length]);
+        Length += 4;
+      }
+    }
+    if (Flags & EXT_ATTR_PRESENT)
+      Length += 8;
+
+    RelEntry.RelType = getRldType(Rld);
+    RelEntry.RefSymb.d.a = RelEntry.REsdId;
+
+    RelEntries.emplace_back(RelEntry);
+
+    Rld += Length;
+    assert(Rld <= RldE && "RLD length?");
+  }
+}
+
+void GOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
+  for (size_t I = Rel.d.b + 1, E = RelEntries.size(); I < E; ++I) {
+    const GOFFRelEntry &RelEntry = RelEntries[I];
+    if (Rel.d.a == RelEntry.PEsdId) {
+      Rel.d.b = I;
+      return;
+    }
+  }
+
+  Rel.d.b = 0;
+}
+
+uint64_t GOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
+  assert(Rel.d.b > 0 && Rel.d.b < RelEntries.size() &&
+         "Rel Index out of boundary");
+  const GOFFRelEntry &RelEntry = RelEntries[Rel.d.b];
+  return RelEntry.POffset;
+}
+
+symbol_iterator GOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
+  assert(Rel.d.b > 0 && Rel.d.b < RelEntries.size() &&
+         "Rel Index out of boundary");
+  const GOFFRelEntry &RelEntry = RelEntries[Rel.d.b];
+  return basic_symbol_iterator(SymbolRef(RelEntry.RefSymb, this));
+}
+
+uint64_t GOFFObjectFile::getRelocationType(DataRefImpl Rel) const {
+  assert(Rel.d.b > 0 && Rel.d.b < RelEntries.size() &&
+         "Rel Index out of boundary");
+  const GOFFRelEntry &RelEntry = RelEntries[Rel.d.b];
+  return RelEntry.RelType;
+}
+
+void GOFFObjectFile::getRelocationTypeName(
+    DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
+  uint64_t RelType = getRelocationType(Rel);
+  char Buf[16];
+  sprintf(Buf, "R_%08lx", RelType);
+  Result.append(Buf, Buf + strlen(Buf));
+}
+
+relocation_iterator GOFFObjectFile::section_rel_begin(DataRefImpl Sec) const {
+  DataRefImpl Rel;
+  Rel.d.a = getSectionDefEsdId(Sec);
+  Rel.d.b = 0;
+  moveRelocationNext(Rel);
+  return relocation_iterator(RelocationRef(Rel, this));
+}
+
+relocation_iterator GOFFObjectFile::section_rel_end(DataRefImpl Sec) const {
+  DataRefImpl Rel;
+  Rel.d.a = getSectionDefEsdId(Sec);
+  Rel.d.b = 0;
+  return relocation_iterator(RelocationRef(Rel, this));
+}
diff --git a/llvm/unittests/Object/GOFFObjectFileTest.cpp b/llvm/unittests/Object/GOFFObjectFileTest.cpp
index 89096a87618cc..555487a87dcb5 100644
--- a/llvm/unittests/Object/GOFFObjectFileTest.cpp
+++ b/llvm/unittests/Object/GOFFObjectFileTest.cpp
@@ -604,6 +604,16 @@ TEST_F(GOFFObjectFileTest, TXTConstruct) {
   GOFFData[Pos + 30] = (char)0xde;
   GOFFData[Pos + 31] = (char)0xf0;
 
+  // RLD record.
+  Pos = addNewRecord();
+  GOFFData[Pos] = (char)0x03;
+  GOFFData[Pos + 1] = (char)0x20;
+  GOFFData[Pos + 5] = (char)0x14;  // Length.
+  GOFFData[Pos + 10] = (char)0x04; // Target Length.
+  GOFFData[Pos + 17] = (char)0x03; // R-id.
+  GOFFData[Pos + 21] = (char)0x02; // P-id.
+  GOFFData[Pos + 25] = (char)0x04; // Offset.
+
   // END record.
   addEndRecord();
 
@@ -632,6 +642,21 @@ TEST_F(GOFFObjectFileTest, TXTConstruct) {
   ASSERT_THAT_EXPECTED(SectionContent, Succeeded());
   StringRef Contents = SectionContent.get();
   EXPECT_EQ(Contents, "\x12\x34\x56\x78\x9a\xbc\xde\xf0");
+
+  auto Relocations = Section.relocations();
+  ASSERT_EQ(std::distance(Relocations.begin(), Relocations.end()), 1);
+  RelocationRef Relocation = *Relocations.begin();
+  SymbolRef TargetSymbol = *Relocation.getSymbol();
+  Expected<StringRef> TargetSymbolNameOrErr =
+      GOFFObj->getSymbolName(TargetSymbol);
+  ASSERT_THAT_EXPECTED(TargetSymbolNameOrErr, Succeeded());
+  StringRef TargetSymbolName = TargetSymbolNameOrErr.get();
+  EXPECT_EQ(TargetSymbolName, "var#c");
+  SmallString<16> RelTypeName;
+  Relocation.getTypeName(RelTypeName);
+  EXPECT_EQ(RelTypeName, "R_00040000");
+  uint64_t Offset = Relocation.getOffset();
+  EXPECT_EQ(Offset, 4u);
 }
 
 TEST_F(GOFFObjectFileTest, GlobalSymbols) {

>From 00fa22db5cb4abce6872a0ade6c9277dacedf26e Mon Sep 17 00:00:00 2001
From: Shimin Cui <scui at ca.ibm.com>
Date: Tue, 25 Aug 2026 19:55:07 +0000
Subject: [PATCH 2/3] To address comments (fix RelEntry population + unittest)

---
 llvm/include/llvm/Object/GOFFObjectFile.h    |  4 ---
 llvm/lib/Object/GOFFObjectFile.cpp           | 33 +++++++++++---------
 llvm/unittests/Object/GOFFObjectFileTest.cpp | 33 ++++++++++++++++----
 3 files changed, 46 insertions(+), 24 deletions(-)

diff --git a/llvm/include/llvm/Object/GOFFObjectFile.h b/llvm/include/llvm/Object/GOFFObjectFile.h
index 0bfbbc8d7acd6..a1553f578a71d 100644
--- a/llvm/include/llvm/Object/GOFFObjectFile.h
+++ b/llvm/include/llvm/Object/GOFFObjectFile.h
@@ -35,8 +35,6 @@ struct GOFFRelEntry {
   uint32_t PEsdId;
   uint64_t POffset;
   uint64_t RelType;
-
-  DataRefImpl RefSymb; // Symbol referred to.
 };
 
 // GOFFRelEntry::RelType is computed based on RLD fields at offset 1, 2, 4,
@@ -193,8 +191,6 @@ class GOFFSymbolRef : public SymbolRef {
     return cast<GOFFObjectFile>(BasicSymbolRef::getObject());
   }
 
-  uint32_t getSymbolGOFFEsdId() const { return getRawDataRefImpl().d.a; }
-
   Expected<uint32_t> getSymbolGOFFFlags() const {
     return getObject()->getSymbolFlags(getRawDataRefImpl());
   }
diff --git a/llvm/lib/Object/GOFFObjectFile.cpp b/llvm/lib/Object/GOFFObjectFile.cpp
index 4960aeaae8440..1b03fd8c68199 100644
--- a/llvm/lib/Object/GOFFObjectFile.cpp
+++ b/llvm/lib/Object/GOFFObjectFile.cpp
@@ -766,6 +766,12 @@ basic_symbol_iterator GOFFObjectFile::symbol_end() const {
   return basic_symbol_iterator(SymbolRef(Symb, this));
 }
 
+inline constexpr uint8_t SAME_R_ID = 0x80;
+inline constexpr uint8_t SAME_P_ID = 0x40;
+inline constexpr uint8_t SAME_OFFSET = 0x20;
+inline constexpr uint8_t EXT_ATTR_PRESENT = 0x04;
+inline constexpr uint8_t BYTE_OFFSET_8 = 0x02;
+
 // Populate the relocation entries.
 void GOFFObjectFile::setRelocationData(const uint8_t *RldRecord) {
   SmallVector<uint8_t, 8> RelocationData;
@@ -784,40 +790,37 @@ void GOFFObjectFile::setRelocationData(const uint8_t *RldRecord) {
 
   uint8_t *RldI = reinterpret_cast<uint8_t *>(RelocationData.data());
   uint8_t *RldE = RldI + RelocationData.size();
+  uint32_t CurREsdId = 0;
+  uint32_t CurPEsdId = 0;
+  uint64_t CurPOffset = 0;
   for (uint8_t *Rld = RldI + DataIndex; Rld < RldE;) {
     GOFFRelEntry RelEntry;
     uint8_t Flags = Rld[0];
-
-#define SAME_R_ID 0x80
-#define SAME_P_ID 0x40
-#define SAME_OFFSET 0x20
-#define EXT_ATTR_PRESENT 0x04
-#define BYTE_OFFSET_8 0x02
-
     int32_t Length = 8;
     if (!(Flags & SAME_R_ID)) {
-      RelEntry.REsdId = support::endian::read32be(&Rld[Length]);
+      CurREsdId = support::endian::read32be(&Rld[Length]);
       Length += 4;
     }
     if (!(Flags & SAME_P_ID)) {
-      RelEntry.PEsdId = support::endian::read32be(&Rld[Length]);
+      CurPEsdId = support::endian::read32be(&Rld[Length]);
       Length += 4;
     }
     if (!(Flags & SAME_OFFSET)) {
       if (Flags & BYTE_OFFSET_8) {
-        RelEntry.POffset = support::endian::read64be(&Rld[Length]);
+        CurPOffset = support::endian::read64be(&Rld[Length]);
         Length += 8;
       } else {
-        RelEntry.POffset = support::endian::read32be(&Rld[Length]);
+        CurPOffset = support::endian::read32be(&Rld[Length]);
         Length += 4;
       }
     }
     if (Flags & EXT_ATTR_PRESENT)
       Length += 8;
 
+    RelEntry.PEsdId = CurPEsdId;
+    RelEntry.REsdId = CurREsdId;
+    RelEntry.POffset = CurPOffset;
     RelEntry.RelType = getRldType(Rld);
-    RelEntry.RefSymb.d.a = RelEntry.REsdId;
-
     RelEntries.emplace_back(RelEntry);
 
     Rld += Length;
@@ -848,7 +851,9 @@ symbol_iterator GOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
   assert(Rel.d.b > 0 && Rel.d.b < RelEntries.size() &&
          "Rel Index out of boundary");
   const GOFFRelEntry &RelEntry = RelEntries[Rel.d.b];
-  return basic_symbol_iterator(SymbolRef(RelEntry.RefSymb, this));
+  DataRefImpl RefSym;
+  RefSym.d.a = RelEntry.REsdId;
+  return basic_symbol_iterator(SymbolRef(RefSym, this));
 }
 
 uint64_t GOFFObjectFile::getRelocationType(DataRefImpl Rel) const {
diff --git a/llvm/unittests/Object/GOFFObjectFileTest.cpp b/llvm/unittests/Object/GOFFObjectFileTest.cpp
index 555487a87dcb5..493b1fd8e9df1 100644
--- a/llvm/unittests/Object/GOFFObjectFileTest.cpp
+++ b/llvm/unittests/Object/GOFFObjectFileTest.cpp
@@ -604,15 +604,19 @@ TEST_F(GOFFObjectFileTest, TXTConstruct) {
   GOFFData[Pos + 30] = (char)0xde;
   GOFFData[Pos + 31] = (char)0xf0;
 
-  // RLD record.
+  // RLD record with 2 entries.
   Pos = addNewRecord();
   GOFFData[Pos] = (char)0x03;
   GOFFData[Pos + 1] = (char)0x20;
-  GOFFData[Pos + 5] = (char)0x14;  // Length.
+  GOFFData[Pos + 5] = (char)0x20;  // Length.
   GOFFData[Pos + 10] = (char)0x04; // Target Length.
   GOFFData[Pos + 17] = (char)0x03; // R-id.
   GOFFData[Pos + 21] = (char)0x02; // P-id.
-  GOFFData[Pos + 25] = (char)0x04; // Offset.
+  GOFFData[Pos + 25] = (char)0x00; // Offset.
+  GOFFData[Pos + 26] = (char)0xc0; // Same R-id and P-id.
+  GOFFData[Pos + 28] = (char)0x01; // Store
+  GOFFData[Pos + 30] = (char)0x04; // Target Length.
+  GOFFData[Pos + 37] = (char)0x04; // Offset.
 
   // END record.
   addEndRecord();
@@ -643,9 +647,13 @@ TEST_F(GOFFObjectFileTest, TXTConstruct) {
   StringRef Contents = SectionContent.get();
   EXPECT_EQ(Contents, "\x12\x34\x56\x78\x9a\xbc\xde\xf0");
 
-  auto Relocations = Section.relocations();
-  ASSERT_EQ(std::distance(Relocations.begin(), Relocations.end()), 1);
-  RelocationRef Relocation = *Relocations.begin();
+  iterator_range<object::relocation_iterator> Relocations =
+      Section.relocations();
+  object::relocation_iterator RelI = Relocations.begin();
+  object::relocation_iterator RelIE = Relocations.end();
+  ASSERT_EQ(std::distance(RelI, RelIE), 2);
+  // First relocation entry.
+  RelocationRef Relocation = *RelI;
   SymbolRef TargetSymbol = *Relocation.getSymbol();
   Expected<StringRef> TargetSymbolNameOrErr =
       GOFFObj->getSymbolName(TargetSymbol);
@@ -656,6 +664,19 @@ TEST_F(GOFFObjectFileTest, TXTConstruct) {
   Relocation.getTypeName(RelTypeName);
   EXPECT_EQ(RelTypeName, "R_00040000");
   uint64_t Offset = Relocation.getOffset();
+  EXPECT_EQ(Offset, 0u);
+  // Second relocation entry.
+  ++RelI;
+  Relocation = *RelI;
+  TargetSymbol = *Relocation.getSymbol();
+  TargetSymbolNameOrErr = GOFFObj->getSymbolName(TargetSymbol);
+  ASSERT_THAT_EXPECTED(TargetSymbolNameOrErr, Succeeded());
+  TargetSymbolName = TargetSymbolNameOrErr.get();
+  EXPECT_EQ(TargetSymbolName, "var#c");
+  SmallString<16> RelTypeName2;
+  Relocation.getTypeName(RelTypeName2);
+  EXPECT_EQ(RelTypeName2, "R_00040100");
+  Offset = Relocation.getOffset();
   EXPECT_EQ(Offset, 4u);
 }
 

>From 6b3d869407f5cab6d7411504bdca26530481e8af Mon Sep 17 00:00:00 2001
From: Shimin Cui <scui at ca.ibm.com>
Date: Wed, 26 Aug 2026 13:33:00 +0000
Subject: [PATCH 3/3] Fix as record is flattened now

---
 llvm/include/llvm/Object/GOFFObjectFile.h |  2 +-
 llvm/lib/Object/GOFFObjectFile.cpp        | 18 +++++-------------
 2 files changed, 6 insertions(+), 14 deletions(-)

diff --git a/llvm/include/llvm/Object/GOFFObjectFile.h b/llvm/include/llvm/Object/GOFFObjectFile.h
index a1553f578a71d..42b62ea0405ee 100644
--- a/llvm/include/llvm/Object/GOFFObjectFile.h
+++ b/llvm/include/llvm/Object/GOFFObjectFile.h
@@ -39,7 +39,7 @@ struct GOFFRelEntry {
 
 // GOFFRelEntry::RelType is computed based on RLD fields at offset 1, 2, 4,
 // and 5.
-inline uint64_t getRldType(uint8_t *Rld) {
+inline uint64_t getRldType(const uint8_t *Rld) {
   return Rld[1] + (Rld[2] << 8) + (Rld[4] << 16) + (Rld[5] << 24);
 }
 
diff --git a/llvm/lib/Object/GOFFObjectFile.cpp b/llvm/lib/Object/GOFFObjectFile.cpp
index 1b03fd8c68199..2b8e61a994838 100644
--- a/llvm/lib/Object/GOFFObjectFile.cpp
+++ b/llvm/lib/Object/GOFFObjectFile.cpp
@@ -778,22 +778,14 @@ void GOFFObjectFile::setRelocationData(const uint8_t *RldRecord) {
   int DataIndex = 6;
   uint16_t DataLength;
   RLDRecord::getDataLength(RldRecord, DataLength);
-  Expected<unsigned> BlocksConsumed =
-      getContinuousData(RelocationData, DataIndex, DataLength, RldRecord);
-  if (!BlocksConsumed)
-    llvm::handleAllErrors(BlocksConsumed.takeError(),
-                          [](const llvm::ErrorInfoBase &EIB) {
-                            llvm::errs() << "ERROR: " << EIB.message() << "\n";
-                          });
-  assert(static_cast<size_t>(DataLength + DataIndex) == RelocationData.size() &&
-         "Inconsistent rld size");
-
-  uint8_t *RldI = reinterpret_cast<uint8_t *>(RelocationData.data());
-  uint8_t *RldE = RldI + RelocationData.size();
+
+  // The record is already flattened if it's continued.
+  const uint8_t *RldI = RldRecord + DataIndex;
+  const uint8_t *RldE = RldI + DataLength;
   uint32_t CurREsdId = 0;
   uint32_t CurPEsdId = 0;
   uint64_t CurPOffset = 0;
-  for (uint8_t *Rld = RldI + DataIndex; Rld < RldE;) {
+  for (const uint8_t *Rld = RldI; Rld < RldE;) {
     GOFFRelEntry RelEntry;
     uint8_t Flags = Rld[0];
     int32_t Length = 8;



More information about the llvm-commits mailing list