[llvm-branch-commits] [llvm-objdump] -r: support CREL (PR #97382)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Jul 1 22:03:04 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-binary-utilities
Author: Fangrui Song (MaskRay)
<details>
<summary>Changes</summary>
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
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;
``````````
</details>
https://github.com/llvm/llvm-project/pull/97382
More information about the llvm-branch-commits
mailing list