Skip to content

[llvm-objdump] -r: support CREL #97382

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 8, 2024

Conversation

MaskRay
Copy link
Member

@MaskRay MaskRay commented Jul 2, 2024

Extract the llvm-readelf decoder to decodeCrel (#91280) and reuse it
for llvm-objdump.

Because the section representation of LLVMObject (SectionRef) is
64-bit, insufficient to hold all decoder states, section_rel_begin is
modified to decode CREL eagerly and hold the decoded relocations inside
ELFObjectFile.

The test is adapted from llvm/test/tools/llvm-readobj/ELF/crel.test.

MaskRay added 2 commits July 1, 2024 22:02
Created using spr 1.3.5-bogner

[skip ci]
Created using spr 1.3.5-bogner
@llvmbot
Copy link
Member

llvmbot commented Jul 2, 2024

@llvm/pr-subscribers-llvm-binary-utilities

Author: Fangrui Song (MaskRay)

Changes

The decoder code is similar to that for llvm-readelf -r (#91280).

Because the section representation of LLVMObject (SectionRef) is
64-bit, insufficient to hold all decoder states, section_rel_begin is
modified to decode CREL eagerly and hold the decoded relocations inside
ELFObjectFile<ELFT>.

The test is adapted from llvm/test/tools/llvm-readobj/ELF/crel.test.


Full diff: https://github.com/llvm/llvm-project/pull/97382.diff

6 Files Affected:

  • (modified) llvm/include/llvm/Object/ELFObjectFile.h (+87-6)
  • (modified) llvm/lib/Object/ELFObjectFile.cpp (+11)
  • (added) llvm/test/tools/llvm-objdump/ELF/crel.test (+213)
  • (modified) llvm/test/tools/llvm-objdump/X86/elf-disassemble-relocs.test (+4)
  • (modified) llvm/tools/llvm-objdump/ELFDump.cpp (+5-1)
  • (modified) llvm/tools/llvm-objdump/llvm-objdump.cpp (+9)
diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h
index 8cc09e7fd7d55..665d848d5b607 100644
--- a/llvm/include/llvm/Object/ELFObjectFile.h
+++ b/llvm/include/llvm/Object/ELFObjectFile.h
@@ -29,6 +29,7 @@
 #include "llvm/Support/ELFAttributes.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/LEB128.h"
 #include "llvm/Support/MemoryBufferRef.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/TargetParser/SubtargetFeature.h"
@@ -122,6 +123,8 @@ class ELFObjectFileBase : public ObjectFile {
   Expected<std::vector<BBAddrMap>>
   readBBAddrMap(std::optional<unsigned> TextSectionIndex = std::nullopt,
                 std::vector<PGOAnalysisMap> *PGOAnalyses = nullptr) const;
+
+  StringRef getCrelError(SectionRef Sec) const;
 };
 
 class ELFSectionRef : public SectionRef {
@@ -292,6 +295,11 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
   const Elf_Shdr *DotSymtabSec = nullptr; // Symbol table section.
   const Elf_Shdr *DotSymtabShndxSec = nullptr; // SHT_SYMTAB_SHNDX section.
 
+  // Hold CREL relocations for SectionRef::relocations().
+  mutable SmallVector<SmallVector<Elf_Crel, 0>, 0> Crels;
+  // Hold CREL decoding errors.
+  mutable SmallVector<std::string, 0> CrelErrs;
+
   Error initContent() override;
 
   void moveSymbolNext(DataRefImpl &Symb) const override;
@@ -446,6 +454,7 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
 
   const Elf_Rel *getRel(DataRefImpl Rel) const;
   const Elf_Rela *getRela(DataRefImpl Rela) const;
+  Elf_Crel getCrel(DataRefImpl Crel) const;
 
   Expected<const Elf_Sym *> getSymbol(DataRefImpl Sym) const {
     return EF.template getEntry<Elf_Sym>(Sym.d.a, Sym.d.b);
@@ -499,6 +508,8 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
   bool isRelocatableObject() const override;
 
   void createFakeSections() { EF.createFakeSections(); }
+
+  StringRef getCrelError(DataRefImpl Sec) const;
 };
 
 using ELF32LEObjectFile = ELFObjectFile<ELF32LE>;
@@ -1022,6 +1033,47 @@ ELFObjectFile<ELFT>::section_rel_begin(DataRefImpl Sec) const {
   uintptr_t SHT = reinterpret_cast<uintptr_t>((*SectionsOrErr).begin());
   RelData.d.a = (Sec.p - SHT) / EF.getHeader().e_shentsize;
   RelData.d.b = 0;
+  if (reinterpret_cast<const Elf_Shdr *>(Sec.p)->sh_type == ELF::SHT_CREL) {
+    if (RelData.d.a + 1 > Crels.size()) {
+      Crels.resize(RelData.d.a + 1);
+      CrelErrs.resize(RelData.d.a + 1);
+    }
+    if (Crels[RelData.d.a].empty()) {
+      // Decode SHT_CREL. See ELFFile<ELFT>::decodeCrel.
+      ArrayRef<uint8_t> Content = cantFail(getSectionContents(Sec));
+      DataExtractor Data(Content, ELFT::Endianness == endianness::little,
+                         sizeof(typename ELFT::Addr));
+      DataExtractor::Cursor Cur(0);
+      const uint64_t Hdr = Data.getULEB128(Cur);
+      const size_t Count = Hdr / 8;
+      const size_t FlagBits = Hdr & ELF::CREL_HDR_ADDEND ? 3 : 2;
+      const size_t Shift = Hdr % ELF::CREL_HDR_ADDEND;
+      uintX_t Offset = 0, Addend = 0;
+      uint32_t Symidx = 0, Type = 0;
+      for (size_t i = 0; i != Count; ++i) {
+        const uint8_t B = Data.getU8(Cur);
+        Offset += B >> FlagBits;
+        if (B >= 0x80)
+          Offset +=
+              (Data.getULEB128(Cur) << (7 - FlagBits)) - (0x80 >> FlagBits);
+        if (B & 1)
+          Symidx += Data.getSLEB128(Cur);
+        if (B & 2)
+          Type += Data.getSLEB128(Cur);
+        if (B & 4 && FlagBits == 3)
+          Addend += Data.getSLEB128(Cur);
+        if (!Cur)
+          break;
+        Crels[RelData.d.a].push_back(
+            Elf_Crel{Offset << Shift, uint32_t(Symidx), Type,
+                     std::make_signed_t<typename ELFT::uint>(Addend)});
+      }
+      if (!Cur) {
+        Crels[RelData.d.a].assign(1, Elf_Crel{0, 0, 0, 0});
+        CrelErrs[RelData.d.a] = toString(Cur.takeError());
+      }
+    }
+  }
   return relocation_iterator(RelocationRef(RelData, this));
 }
 
@@ -1030,9 +1082,13 @@ relocation_iterator
 ELFObjectFile<ELFT>::section_rel_end(DataRefImpl Sec) const {
   const Elf_Shdr *S = reinterpret_cast<const Elf_Shdr *>(Sec.p);
   relocation_iterator Begin = section_rel_begin(Sec);
+  DataRefImpl RelData = Begin->getRawDataRefImpl();
+  if (S->sh_type == ELF::SHT_CREL) {
+    RelData.d.b = Crels[RelData.d.a].size();
+    return relocation_iterator(RelocationRef(RelData, this));
+  }
   if (S->sh_type != ELF::SHT_RELA && S->sh_type != ELF::SHT_REL)
     return Begin;
-  DataRefImpl RelData = Begin->getRawDataRefImpl();
   const Elf_Shdr *RelSec = getRelSection(RelData);
 
   // Error check sh_link here so that getRelocationSymbol can just use it.
@@ -1050,7 +1106,7 @@ Expected<section_iterator>
 ELFObjectFile<ELFT>::getRelocatedSection(DataRefImpl Sec) const {
   const Elf_Shdr *EShdr = getSection(Sec);
   uintX_t Type = EShdr->sh_type;
-  if (Type != ELF::SHT_REL && Type != ELF::SHT_RELA)
+  if (Type != ELF::SHT_REL && Type != ELF::SHT_RELA && Type != ELF::SHT_CREL)
     return section_end();
 
   Expected<const Elf_Shdr *> SecOrErr = EF.getSection(EShdr->sh_info);
@@ -1070,7 +1126,9 @@ symbol_iterator
 ELFObjectFile<ELFT>::getRelocationSymbol(DataRefImpl Rel) const {
   uint32_t symbolIdx;
   const Elf_Shdr *sec = getRelSection(Rel);
-  if (sec->sh_type == ELF::SHT_REL)
+  if (sec->sh_type == ELF::SHT_CREL)
+    symbolIdx = getCrel(Rel).r_symidx;
+  else if (sec->sh_type == ELF::SHT_REL)
     symbolIdx = getRel(Rel)->getSymbol(EF.isMips64EL());
   else
     symbolIdx = getRela(Rel)->getSymbol(EF.isMips64EL());
@@ -1087,6 +1145,8 @@ ELFObjectFile<ELFT>::getRelocationSymbol(DataRefImpl Rel) const {
 template <class ELFT>
 uint64_t ELFObjectFile<ELFT>::getRelocationOffset(DataRefImpl Rel) const {
   const Elf_Shdr *sec = getRelSection(Rel);
+  if (sec->sh_type == ELF::SHT_CREL)
+    return getCrel(Rel).r_offset;
   if (sec->sh_type == ELF::SHT_REL)
     return getRel(Rel)->r_offset;
 
@@ -1096,6 +1156,8 @@ uint64_t ELFObjectFile<ELFT>::getRelocationOffset(DataRefImpl Rel) const {
 template <class ELFT>
 uint64_t ELFObjectFile<ELFT>::getRelocationType(DataRefImpl Rel) const {
   const Elf_Shdr *sec = getRelSection(Rel);
+  if (sec->sh_type == ELF::SHT_CREL)
+    return getCrel(Rel).r_type;
   if (sec->sh_type == ELF::SHT_REL)
     return getRel(Rel)->getType(EF.isMips64EL());
   else
@@ -1117,9 +1179,11 @@ void ELFObjectFile<ELFT>::getRelocationTypeName(
 template <class ELFT>
 Expected<int64_t>
 ELFObjectFile<ELFT>::getRelocationAddend(DataRefImpl Rel) const {
-  if (getRelSection(Rel)->sh_type != ELF::SHT_RELA)
-    return createError("Section is not SHT_RELA");
-  return (int64_t)getRela(Rel)->r_addend;
+  if (getRelSection(Rel)->sh_type == ELF::SHT_RELA)
+    return (int64_t)getRela(Rel)->r_addend;
+  if (getRelSection(Rel)->sh_type == ELF::SHT_CREL)
+    return (int64_t)getCrel(Rel).r_addend;
+  return createError("Section is not SHT_RELA");
 }
 
 template <class ELFT>
@@ -1142,6 +1206,14 @@ ELFObjectFile<ELFT>::getRela(DataRefImpl Rela) const {
   return *Ret;
 }
 
+template <class ELFT>
+typename ELFObjectFile<ELFT>::Elf_Crel
+ELFObjectFile<ELFT>::getCrel(DataRefImpl Crel) const {
+  assert(getRelSection(Crel)->sh_type == ELF::SHT_CREL);
+  assert(Crel.d.a < Crels.size());
+  return Crels[Crel.d.a][Crel.d.b];
+}
+
 template <class ELFT>
 Expected<ELFObjectFile<ELFT>>
 ELFObjectFile<ELFT>::create(MemoryBufferRef Object, bool InitContent) {
@@ -1453,6 +1525,15 @@ template <class ELFT> bool ELFObjectFile<ELFT>::isRelocatableObject() const {
   return EF.getHeader().e_type == ELF::ET_REL;
 }
 
+template <class ELFT>
+StringRef ELFObjectFile<ELFT>::getCrelError(DataRefImpl Sec) const {
+  uintptr_t SHT = reinterpret_cast<uintptr_t>(cantFail(EF.sections()).begin());
+  auto I = (Sec.p - SHT) / EF.getHeader().e_shentsize;
+  if (I < CrelErrs.size())
+    return CrelErrs[I];
+  return "";
+}
+
 } // end namespace object
 } // end namespace llvm
 
diff --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp
index cbc55a145e0e6..3da7da759a145 100644
--- a/llvm/lib/Object/ELFObjectFile.cpp
+++ b/llvm/lib/Object/ELFObjectFile.cpp
@@ -1013,3 +1013,14 @@ Expected<std::vector<BBAddrMap>> ELFObjectFileBase::readBBAddrMap(
   return readBBAddrMapImpl(cast<ELF64BEObjectFile>(this)->getELFFile(),
                            TextSectionIndex, PGOAnalyses);
 }
+
+StringRef ELFObjectFileBase::getCrelError(SectionRef Sec) const {
+  auto Data = Sec.getRawDataRefImpl();
+  if (const auto *Obj = dyn_cast<ELF32LEObjectFile>(this))
+    return Obj->getCrelError(Data);
+  if (const auto *Obj = dyn_cast<ELF32BEObjectFile>(this))
+    return Obj->getCrelError(Data);
+  if (const auto *Obj = dyn_cast<ELF64LEObjectFile>(this))
+    return Obj->getCrelError(Data);
+  return cast<ELF64BEObjectFile>(this)->getCrelError(Data);
+}
diff --git a/llvm/test/tools/llvm-objdump/ELF/crel.test b/llvm/test/tools/llvm-objdump/ELF/crel.test
new file mode 100644
index 0000000000000..7eb435e232ae4
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/ELF/crel.test
@@ -0,0 +1,213 @@
+# RUN: yaml2obj --docnum=1 %s -o %t
+# RUN: llvm-objdump -r %t | FileCheck %s --strict-whitespace --match-full-lines
+
+#      CHECK:RELOCATION RECORDS FOR [.text]:
+# CHECK-NEXT:OFFSET           TYPE                     VALUE
+# CHECK-NEXT:0000000000000001 R_X86_64_32              g1+0x1
+# CHECK-NEXT:0000000000000002 R_X86_64_64              l1+0x2
+# CHECK-NEXT:0000000000000000 R_X86_64_32S             g1-0x1
+# CHECK-NEXT:0000000000000004 R_X86_64_32S             .text-0x8000000000000000
+#CHECK-EMPTY:
+# CHECK-NEXT:RELOCATION RECORDS FOR [nonalloc]:
+# CHECK-NEXT:OFFSET           TYPE                     VALUE
+# CHECK-NEXT:0000000000000010 R_X86_64_64              g1+0x1
+# CHECK-NEXT:0000000000000020 R_X86_64_64              g2+0x2
+# CHECK-NEXT:0000000000000030 R_X86_64_64              *ABS*
+#  CHECK-NOT:{{.}}
+
+--- !ELF
+FileHeader: !FileHeader
+  Class: ELFCLASS64
+  Data: ELFDATA2LSB
+  Type: ET_REL
+  Machine: EM_X86_64
+
+Sections:
+- Name: .text
+  Type: SHT_PROGBITS
+  Content: "0000000000000000"
+  Flags: [SHF_ALLOC]
+- Name: .crel.text
+  Type: SHT_CREL
+  Info: .text
+  Link: .symtab
+  Relocations:
+    - Offset: 0x1
+      Symbol: g1
+      Type:   R_X86_64_32
+      Addend: 1
+    - Offset: 0x2
+      Symbol: l1
+      Type:   R_X86_64_64
+      Addend: 2
+    - Offset: 0x0
+      Symbol: g1
+      Type:   R_X86_64_32S
+      Addend: 0xffffffffffffffff
+    - Offset: 0x4
+      Symbol: .text
+      Type:   R_X86_64_32S
+      Addend: 0x8000000000000000
+- Name: nonalloc
+  Type: SHT_PROGBITS
+  Size: 0x30
+- Name: .crelnonalloc
+  Type: SHT_CREL
+  Info: nonalloc
+  Link: .symtab
+  Relocations:
+    - Offset: 0x10
+      Symbol: g1
+      Type:   R_X86_64_64
+      Addend: 1
+    - Offset: 0x20
+      Symbol: g2
+      Type:   R_X86_64_64
+      Addend: 2
+    - Offset: 0x30
+      Symbol: 0
+      Type:   R_X86_64_64
+
+Symbols:
+  - Name: .text
+    Type: STT_SECTION
+    Section: .text
+  - Name:    l1
+  - Name:    g1
+    Section: .text
+    Value:   0x0
+    Size:    4
+    Binding: STB_GLOBAL
+  - Name:    g2
+    Binding: STB_GLOBAL
+
+## Check relocation formatting on ELFCLASS32 as well.
+# RUN: yaml2obj --docnum=2 %s > %t2
+# RUN: llvm-objdump -r %t2 | FileCheck %s --check-prefix=ELF32 --strict-whitespace --match-full-lines
+
+#      ELF32:RELOCATION RECORDS FOR [.text]:
+# ELF32-NEXT:OFFSET   TYPE                     VALUE
+# ELF32-NEXT:00000008 R_ARM_REL32              l1+0x1
+# ELF32-NEXT:00000004 R_ARM_ABS32              g1
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2MSB
+  Type:    ET_REL
+  Machine: EM_ARM
+Sections:
+- Name: .text
+  Type: SHT_PROGBITS
+  Size: 0x10
+- Name: .crel.text
+  Type: SHT_CREL
+  Info: .text
+  Link: .symtab
+  Relocations:
+    - Offset: 0x8
+      Symbol: l1
+      Type:   R_ARM_REL32
+      Addend: 1
+    - Offset: 0x4
+      Symbol: g1
+      Type:   R_ARM_ABS32
+Symbols:
+  - Name:    l1
+  - Name:    g1
+    Binding: STB_GLOBAL
+
+## Check CREL with implicit addends.
+# RUN: yaml2obj --docnum=3 %s -o %t3
+# RUN: llvm-objdump -r %t3 | FileCheck %s --check-prefix=IMPLICIT --strict-whitespace --match-full-lines
+#      IMPLICIT:RELOCATION RECORDS FOR [.data]:
+# IMPLICIT-NEXT:OFFSET           TYPE                     VALUE
+# IMPLICIT-NEXT:000000000000001f R_X86_64_32              g1
+# IMPLICIT-NEXT:000000000000003f R_X86_64_64              g1
+# IMPLICIT-NEXT:0000000000000000 R_X86_64_32S             l1
+--- !ELF
+FileHeader:
+  Class:     ELFCLASS64
+  Data:      ELFDATA2LSB
+  Type:      ET_REL
+  Machine:   EM_X86_64
+Sections:
+  - Name:    .text
+    Type:    SHT_PROGBITS
+  - Name:    .data
+    Type:    SHT_PROGBITS
+  - Name:    .crel.data
+    Type:    SHT_CREL
+    Flags:   [ SHF_INFO_LINK ]
+    Link:    .symtab
+    Info:    .data
+    Content: 187f030a82017787feffffffffffffff077f0a
+Symbols:
+  - Name:    .text
+    Type:    STT_SECTION
+    Section: .text
+  - Name:    l1
+    Section: .text
+  - Name:    g1
+    Section: .text
+    Binding: STB_GLOBAL
+
+## Test errors.
+# RUN: yaml2obj --docnum=4 %s -o %t.err
+# RUN: llvm-objdump -r %t.err 2>&1 | FileCheck %s --check-prefix=ERR -DFILE=%t.err
+
+#      ERR:RELOCATION RECORDS FOR [.data]:
+# ERR-NEXT:OFFSET           TYPE                     VALUE
+# ERR-NEXT:warning: '[[FILE]]': unable to decode LEB128 at offset 0x00000000: malformed uleb128, extends past end
+#  ERR-NOT:{{.}}
+
+--- !ELF
+FileHeader:
+  Class:     ELFCLASS64
+  Data:      ELFDATA2LSB
+  Type:      ET_REL
+  Machine:   EM_X86_64
+Sections:
+  - Name:    .text
+    Type:    SHT_PROGBITS
+  - Name:    .data
+    Type:    SHT_PROGBITS
+  - Name:    .crel.data
+    Type:    SHT_CREL
+    Flags:   []
+    Link:    .symtab
+    Info:    .data
+Symbols:
+  - Name:    .text
+    Type:    STT_SECTION
+    Section: .text
+
+# RUN: yaml2obj --docnum=5 %s -o %t.err2
+# RUN: llvm-objdump -r %t.err2 2>&1 | FileCheck %s --check-prefix=ERR2 -DFILE=%t.err2
+
+#      ERR2:RELOCATION RECORDS FOR [.data]:
+# ERR2-NEXT:OFFSET           TYPE                     VALUE
+# ERR2-NEXT:warning: '[[FILE]]': unexpected end of data at offset 0x1 while reading [0x1, 0x2)
+#  ERR-NOT:{{.}}
+
+--- !ELF
+FileHeader:
+  Class:     ELFCLASS32
+  Data:      ELFDATA2MSB
+  Type:      ET_REL
+  Machine:   EM_ARM
+Sections:
+  - Name:    .text
+    Type:    SHT_PROGBITS
+  - Name:    .data
+    Type:    SHT_PROGBITS
+  - Name:    .crel.data
+    Type:    SHT_CREL
+    Flags:   []
+    Link:    .symtab
+    Info:    .data
+    Content: 08
+Symbols:
+  - Name:    .text
+    Type:    STT_SECTION
+    Section: .text
diff --git a/llvm/test/tools/llvm-objdump/X86/elf-disassemble-relocs.test b/llvm/test/tools/llvm-objdump/X86/elf-disassemble-relocs.test
index cce0712e8fa0d..a6bd09ce3fa24 100644
--- a/llvm/test/tools/llvm-objdump/X86/elf-disassemble-relocs.test
+++ b/llvm/test/tools/llvm-objdump/X86/elf-disassemble-relocs.test
@@ -6,6 +6,10 @@
 # RUN: llvm-objdump 1.o -d -r | FileCheck %s --implicit-check-not="RELOCATION RECORDS"
 # RUN: llvm-objdump 1.o -r --disassemble-symbols=x2,x4 | FileCheck %s --check-prefix=CHECK2
 
+# RUN: llvm-mc -filetype=obj -triple=x86_64 -crel 1.s -o 1leb.o
+# RUN: llvm-objdump 1leb.o -d -r | FileCheck %s --implicit-check-not="RELOCATION RECORDS"
+# RUN: llvm-objdump 1leb.o -r --disassemble-symbols=x2,x4 | FileCheck %s --check-prefix=CHECK2
+
 #--- 1.s
 # CHECK:       0000000000000000 <x1>:
 # CHECK-NEXT:    0: e8 00 00 00 00                callq   0x5 <x1+0x5>
diff --git a/llvm/tools/llvm-objdump/ELFDump.cpp b/llvm/tools/llvm-objdump/ELFDump.cpp
index 8c184fc1fbb66..5ac13495662fa 100644
--- a/llvm/tools/llvm-objdump/ELFDump.cpp
+++ b/llvm/tools/llvm-objdump/ELFDump.cpp
@@ -104,7 +104,11 @@ static Error getRelocationValueString(const ELFObjectFile<ELFT> *Obj,
   // In SHT_REL case we would need to read the addend from section data.
   // GNU objdump does not do that and we just follow for simplicity atm.
   bool Undef = false;
-  if ((*SecOrErr)->sh_type == ELF::SHT_RELA) {
+  if ((*SecOrErr)->sh_type == ELF::SHT_CREL) {
+    auto ERela = Obj->getCrel(Rel);
+    Addend = ERela.r_addend;
+    Undef = ERela.getSymbol(false) == 0;
+  } else if ((*SecOrErr)->sh_type == ELF::SHT_RELA) {
     const typename ELFT::Rela *ERela = Obj->getRela(Rel);
     Addend = ERela->r_addend;
     Undef = ERela->getSymbol(false) == 0;
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 6249be4f332b7..792a27f8d3d3d 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -2687,6 +2687,15 @@ void Dumper::printRelocations() {
            << "VALUE\n";
 
     for (SectionRef Section : P.second) {
+      // CREL requires decoding and has its specific errors.
+      if (O.isELF() && ELFSectionRef(Section).getType() == ELF::SHT_CREL) {
+        const ELFObjectFileBase *ELF = cast<const ELFObjectFileBase>(&O);
+        StringRef Err = ELF->getCrelError(Section);
+        if (!Err.empty()) {
+          reportUniqueWarning(Err);
+          continue;
+        }
+      }
       for (const RelocationRef &Reloc : Section.relocations()) {
         uint64_t Address = Reloc.getOffset();
         SmallString<32> RelocName;

@MaskRay MaskRay requested review from dwblaikie and smithp35 July 2, 2024 05:02
const size_t Shift = Hdr % ELF::CREL_HDR_ADDEND;
uintX_t Offset = 0, Addend = 0;
uint32_t Symidx = 0, Type = 0;
for (size_t i = 0; i != Count; ++i) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It really doesn't feel right that this whole algorithm is duplicated from the version in ELF.cpp. Surely they can be folded together into shared code somewhere?

Copy link
Collaborator

@smithp35 smithp35 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with jh7370 that it would be good to extract the decoding logic, it seems like each tool needs some way of passing in a way to step through the data, return the decoded data, and a way of storing errors. It is possible that this will end up being more code than just inlining the algorithm, however I'm hoping that this additional code is simpler and less error prone than copying the logic.

May be worth a try to see what it looks like.

@@ -2687,6 +2687,15 @@ void Dumper::printRelocations() {
<< "VALUE\n";

for (SectionRef Section : P.second) {
// CREL requires decoding and has its specific errors.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend

// CREL sections require decoding, each section may have its own specific errors.

MaskRay added 2 commits July 2, 2024 20:55
Created using spr 1.3.5-bogner

[skip ci]
Created using spr 1.3.5-bogner
# ERR2:RELOCATION RECORDS FOR [.data]:
# ERR2-NEXT:OFFSET TYPE VALUE
# ERR2-NEXT:warning: '[[FILE]]': unexpected end of data at offset 0x1 while reading [0x1, 0x2)
# ERR-NOT:{{.}}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change this to # ERR2-NOT:{{.}} in the next update.

Copy link
Collaborator

@smithp35 smithp35 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates. Only a couple of small suggestions.

Will be out of office till Monday next week. I'm fine with others approving.

@@ -207,6 +209,43 @@ bool isSectionInSegment(const typename ELFT::Phdr &Phdr,
checkSectionVMA<ELFT>(Phdr, Sec);
}

template <bool Is64>
Error decodeCrel(ArrayRef<uint8_t> Content,
function_ref<void(uint64_t, bool)> HdrHandler,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be worth

uint64_t /* relocation count */, bool /* explicit addends */

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx for the suggestion. adopted

MaskRay added 2 commits July 3, 2024 10:45
Created using spr 1.3.5-bogner

[skip ci]
Created using spr 1.3.5-bogner
return (int64_t)getRela(Rel)->r_addend;
if (getRelSection(Rel)->sh_type == ELF::SHT_CREL)
return (int64_t)getCrel(Rel).r_addend;
return createError("Section is not SHT_RELA");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this error quite makes sense anymore. Probably needs to say something about addends.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error message adjusted. I think this line is dynamically unreachable.

MaskRay added 2 commits July 5, 2024 14:33
Created using spr 1.3.5-bogner

[skip ci]
Created using spr 1.3.5-bogner
Copy link
Collaborator

@jh7370 jh7370 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Collaborator

@smithp35 smithp35 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM too, thanks for the updates.

@MaskRay MaskRay changed the base branch from users/MaskRay/spr/main.llvm-objdump-r-support-crel to main July 8, 2024 16:14
@MaskRay MaskRay merged commit 2f37a22 into main Jul 8, 2024
8 checks passed
@MaskRay MaskRay deleted the users/MaskRay/spr/llvm-objdump-r-support-crel branch July 8, 2024 16:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants