[llvm] 2f37a22 - [llvm-objdump] -r: support CREL

via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 8 09:14:38 PDT 2024


Author: Fangrui Song
Date: 2024-07-08T09:14:34-07:00
New Revision: 2f37a22f10a1128c695bc469871a9101edce853e

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

LOG: [llvm-objdump] -r: support CREL

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<ELFT>.

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

Pull Request: https://github.com/llvm/llvm-project/pull/97382

Added: 
    llvm/test/tools/llvm-objdump/ELF/crel.test

Modified: 
    llvm/include/llvm/Object/ELF.h
    llvm/include/llvm/Object/ELFObjectFile.h
    llvm/lib/Object/ELF.cpp
    llvm/lib/Object/ELFObjectFile.cpp
    llvm/test/tools/llvm-objdump/X86/elf-disassemble-relocs.test
    llvm/tools/llvm-objdump/ELFDump.cpp
    llvm/tools/llvm-objdump/llvm-objdump.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h
index 0986379ce76f5e..6bf42de89e1c4f 100644
--- a/llvm/include/llvm/Object/ELF.h
+++ b/llvm/include/llvm/Object/ELF.h
@@ -21,11 +21,13 @@
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/Object/ELFTypes.h"
 #include "llvm/Object/Error.h"
+#include "llvm/Support/DataExtractor.h"
 #include "llvm/Support/Error.h"
 #include <cassert>
 #include <cstddef>
 #include <cstdint>
 #include <limits>
+#include <type_traits>
 #include <utility>
 
 namespace llvm {
@@ -207,6 +209,47 @@ bool isSectionInSegment(const typename ELFT::Phdr &Phdr,
          checkSectionVMA<ELFT>(Phdr, Sec);
 }
 
+// HdrHandler is called once with the number of relocations and whether the
+// relocations have addends. EntryHandler is called once per decoded relocation.
+template <bool Is64>
+Error decodeCrel(
+    ArrayRef<uint8_t> Content,
+    function_ref<void(uint64_t /*relocation count*/, bool /*explicit addends*/)>
+        HdrHandler,
+    function_ref<void(Elf_Crel_Impl<Is64>)> EntryHandler) {
+  DataExtractor Data(Content, true, 8); // endian and address size are unused
+  DataExtractor::Cursor Cur(0);
+  const uint64_t Hdr = Data.getULEB128(Cur);
+  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;
+  using uint = typename Elf_Crel_Impl<Is64>::uint;
+  uint Offset = 0, Addend = 0;
+  HdrHandler(Count, Hdr & ELF::CREL_HDR_ADDEND);
+  uint32_t SymIdx = 0, Type = 0;
+  for (; Count; --Count) {
+    // The delta offset and flags member may be larger than uint64_t. Special
+    // case the first byte (2 or 3 flag bits; the rest are offset bits). Other
+    // ULEB128 bytes encode the remaining delta offset bits.
+    const uint8_t B = Data.getU8(Cur);
+    Offset += B >> FlagBits;
+    if (B >= 0x80)
+      Offset += (Data.getULEB128(Cur) << (7 - FlagBits)) - (0x80 >> FlagBits);
+    // Delta symidx/type/addend members (SLEB128).
+    if (B & 1)
+      SymIdx += Data.getSLEB128(Cur);
+    if (B & 2)
+      Type += Data.getSLEB128(Cur);
+    if (B & 4 & Hdr)
+      Addend += Data.getSLEB128(Cur);
+    if (!Cur)
+      break;
+    EntryHandler(
+        {Offset << Shift, SymIdx, Type, std::make_signed_t<uint>(Addend)});
+  }
+  return Cur.takeError();
+}
+
 template <class ELFT>
 class ELFFile {
 public:

diff  --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h
index 8cc09e7fd7d551..811943dcd70887 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 getCrelDecodeProblem(SectionRef Sec) const;
 };
 
 class ELFSectionRef : public SectionRef {
@@ -292,6 +295,10 @@ 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;
+  mutable SmallVector<std::string, 0> CrelDecodeProblems;
+
   Error initContent() override;
 
   void moveSymbolNext(DataRefImpl &Symb) const override;
@@ -446,6 +453,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 +507,8 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
   bool isRelocatableObject() const override;
 
   void createFakeSections() { EF.createFakeSections(); }
+
+  StringRef getCrelDecodeProblem(DataRefImpl Sec) const;
 };
 
 using ELF32LEObjectFile = ELFObjectFile<ELF32LE>;
@@ -1022,6 +1032,24 @@ 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);
+    auto &Crel = Crels[RelData.d.a];
+    if (Crel.empty()) {
+      ArrayRef<uint8_t> Content = cantFail(getSectionContents(Sec));
+      size_t I = 0;
+      Error Err = decodeCrel<ELFT::Is64Bits>(
+          Content, [&](uint64_t Count, bool) { Crel.resize(Count); },
+          [&](Elf_Crel Crel) { Crels[RelData.d.a][I++] = Crel; });
+      if (Err) {
+        Crel.assign(1, Elf_Crel{0, 0, 0, 0});
+        if (RelData.d.a + 1 > CrelDecodeProblems.size())
+          CrelDecodeProblems.resize(RelData.d.a + 1);
+        CrelDecodeProblems[RelData.d.a] = toString(std::move(Err));
+      }
+    }
+  }
   return relocation_iterator(RelocationRef(RelData, this));
 }
 
@@ -1030,9 +1058,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 +1082,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 +1102,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 +1121,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 +1132,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 +1155,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("Relocation section does not have addends");
 }
 
 template <class ELFT>
@@ -1142,6 +1182,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 +1501,15 @@ template <class ELFT> bool ELFObjectFile<ELFT>::isRelocatableObject() const {
   return EF.getHeader().e_type == ELF::ET_REL;
 }
 
+template <class ELFT>
+StringRef ELFObjectFile<ELFT>::getCrelDecodeProblem(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 < CrelDecodeProblems.size())
+    return CrelDecodeProblems[I];
+  return "";
+}
+
 } // end namespace object
 } // end namespace llvm
 

diff  --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index 18a116754f4566..e47a40b8715dd5 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -408,46 +408,31 @@ ELFFile<ELFT>::getCrelHeader(ArrayRef<uint8_t> Content) const {
 template <class ELFT>
 Expected<typename ELFFile<ELFT>::RelsOrRelas>
 ELFFile<ELFT>::decodeCrel(ArrayRef<uint8_t> Content) const {
-  DataExtractor Data(Content, isLE(), 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;
   std::vector<Elf_Rel> Rels;
   std::vector<Elf_Rela> Relas;
-  if (Hdr & ELF::CREL_HDR_ADDEND)
-    Relas.resize(Count);
-  else
-    Rels.resize(Count);
-  typename ELFT::uint Offset = 0, Addend = 0;
-  uint32_t SymIdx = 0, Type = 0;
-  for (size_t I = 0; I != Count; ++I) {
-    // The delta offset and flags member may be larger than uint64_t. Special
-    // case the first byte (2 or 3 flag bits; the rest are offset bits). Other
-    // ULEB128 bytes encode the remaining delta offset bits.
-    const uint8_t B = Data.getU8(Cur);
-    Offset += B >> FlagBits;
-    if (B >= 0x80)
-      Offset += (Data.getULEB128(Cur) << (7 - FlagBits)) - (0x80 >> FlagBits);
-    // Delta symidx/type/addend members (SLEB128).
-    if (B & 1)
-      SymIdx += Data.getSLEB128(Cur);
-    if (B & 2)
-      Type += Data.getSLEB128(Cur);
-    if (B & 4 & Hdr)
-      Addend += Data.getSLEB128(Cur);
-    if (Hdr & ELF::CREL_HDR_ADDEND) {
-      Relas[I].r_offset = Offset << Shift;
-      Relas[I].setSymbolAndType(SymIdx, Type, false);
-      Relas[I].r_addend = Addend;
-    } else {
-      Rels[I].r_offset = Offset << Shift;
-      Rels[I].setSymbolAndType(SymIdx, Type, false);
-    }
-  }
-  if (!Cur)
-    return std::move(Cur.takeError());
+  size_t I = 0;
+  bool HasAddend;
+  Error Err = object::decodeCrel<ELFT::Is64Bits>(
+      Content,
+      [&](uint64_t Count, bool HasA) {
+        HasAddend = HasA;
+        if (HasAddend)
+          Relas.resize(Count);
+        else
+          Rels.resize(Count);
+      },
+      [&](Elf_Crel Crel) {
+        if (HasAddend) {
+          Relas[I].r_offset = Crel.r_offset;
+          Relas[I].setSymbolAndType(Crel.r_symidx, Crel.r_type, false);
+          Relas[I++].r_addend = Crel.r_addend;
+        } else {
+          Rels[I].r_offset = Crel.r_offset;
+          Rels[I++].setSymbolAndType(Crel.r_symidx, Crel.r_type, false);
+        }
+      });
+  if (Err)
+    return std::move(Err);
   return std::make_pair(std::move(Rels), std::move(Relas));
 }
 

diff  --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp
index cbc55a145e0e6f..53c3de06d118cc 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::getCrelDecodeProblem(SectionRef Sec) const {
+  auto Data = Sec.getRawDataRefImpl();
+  if (const auto *Obj = dyn_cast<ELF32LEObjectFile>(this))
+    return Obj->getCrelDecodeProblem(Data);
+  if (const auto *Obj = dyn_cast<ELF32BEObjectFile>(this))
+    return Obj->getCrelDecodeProblem(Data);
+  if (const auto *Obj = dyn_cast<ELF64LEObjectFile>(this))
+    return Obj->getCrelDecodeProblem(Data);
+  return cast<ELF64BEObjectFile>(this)->getCrelDecodeProblem(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 00000000000000..ef3c4b011135c1
--- /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)
+# ERR2-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 cce0712e8fa0d9..a6bd09ce3fa241 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 8c184fc1fbb66a..5ac13495662faf 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 6249be4f332b78..d1240025625ca4 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -2687,6 +2687,16 @@ void Dumper::printRelocations() {
            << "VALUE\n";
 
     for (SectionRef Section : P.second) {
+      // CREL sections require decoding, each section may have its own specific
+      // decode problems.
+      if (O.isELF() && ELFSectionRef(Section).getType() == ELF::SHT_CREL) {
+        StringRef Err =
+            cast<const ELFObjectFileBase>(O).getCrelDecodeProblem(Section);
+        if (!Err.empty()) {
+          reportUniqueWarning(Err);
+          continue;
+        }
+      }
       for (const RelocationRef &Reloc : Section.relocations()) {
         uint64_t Address = Reloc.getOffset();
         SmallString<32> RelocName;


        


More information about the llvm-commits mailing list