forked from OSchip/llvm-project
[llvm-readobj][ELF] Teach llvm-readobj to show dynamic relocation in REL format
MIPS 32-bit ABI uses REL relocation record format to save dynamic relocations. The patch teaches llvm-readobj to show dynamic relocations in this format. Differential Revision: http://reviews.llvm.org/D16114 llvm-svn: 258001
This commit is contained in:
parent
20f31fa31a
commit
72155c33b1
Binary file not shown.
|
@ -0,0 +1,71 @@
|
|||
// Check that 'llvm-readobj -dyn-relocations' shows dynamic relocations
|
||||
// if they have REL record format.
|
||||
|
||||
// dyn-rel.so.elf-mips
|
||||
// % cat test.s
|
||||
// .globl __start
|
||||
// __start:
|
||||
// nop
|
||||
//
|
||||
// .data
|
||||
// .type v1,@object
|
||||
// .size v1,4
|
||||
// v1:
|
||||
// .word 0
|
||||
//
|
||||
// .globl v2
|
||||
// .type v2,@object
|
||||
// .size v2,8
|
||||
// v2:
|
||||
// .word v2+4 # R_MIPS_32 target v2 addend 4
|
||||
// .word v1 # R_MIPS_32 target v1 addend 0
|
||||
//
|
||||
// % llvm-mc -filetype=obj -triple=mips-unknown-linux -o test.o test.s
|
||||
// % ld -m elf32btsmip -shared -o dyn-rel.so.elf-mips test.o
|
||||
|
||||
RUN: llvm-readobj -relocations -dyn-relocations -expand-relocs \
|
||||
RUN: %p/Inputs/dyn-rel.so.elf-mips | FileCheck %s
|
||||
|
||||
// CHECK: Relocations [
|
||||
// CHECK-NEXT: Section (6) .rel.dyn {
|
||||
// CHECK-NEXT: Relocation {
|
||||
// CHECK-NEXT: Offset: 0x0
|
||||
// CHECK-NEXT: Type: R_MIPS_NONE (0)
|
||||
// CHECK-NEXT: Symbol: - (0)
|
||||
// CHECK-NEXT: Addend: 0x0
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: Relocation {
|
||||
// CHECK-NEXT: Offset: 0x102F8
|
||||
// CHECK-NEXT: Type: R_MIPS_REL32 (3)
|
||||
// CHECK-NEXT: Symbol: - (0)
|
||||
// CHECK-NEXT: Addend: 0x0
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: Relocation {
|
||||
// CHECK-NEXT: Offset: 0x102F4
|
||||
// CHECK-NEXT: Type: R_MIPS_REL32 (3)
|
||||
// CHECK-NEXT: Symbol: v2 (9)
|
||||
// CHECK-NEXT: Addend: 0x0
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
|
||||
// CHECK: Dynamic Relocations {
|
||||
// CHECK-NEXT: Relocation {
|
||||
// CHECK-NEXT: Offset: 0x0
|
||||
// CHECK-NEXT: Type: R_MIPS_NONE (0)
|
||||
// CHECK-NEXT: Symbol: -
|
||||
// CHECK-NEXT: Addend: 0x0
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: Relocation {
|
||||
// CHECK-NEXT: Offset: 0x102F8
|
||||
// CHECK-NEXT: Type: R_MIPS_REL32 (3)
|
||||
// CHECK-NEXT: Symbol: -
|
||||
// CHECK-NEXT: Addend: 0x0
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: Relocation {
|
||||
// CHECK-NEXT: Offset: 0x102F4
|
||||
// CHECK-NEXT: Type: R_MIPS_REL32 (3)
|
||||
// CHECK-NEXT: Symbol: v2
|
||||
// CHECK-NEXT: Addend: 0x0
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
|
@ -75,6 +75,7 @@ private:
|
|||
typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range;
|
||||
typedef typename ELFO::Elf_Rel Elf_Rel;
|
||||
typedef typename ELFO::Elf_Rela Elf_Rela;
|
||||
typedef typename ELFO::Elf_Rel_Range Elf_Rel_Range;
|
||||
typedef typename ELFO::Elf_Rela_Range Elf_Rela_Range;
|
||||
typedef typename ELFO::Elf_Phdr Elf_Phdr;
|
||||
typedef typename ELFO::Elf_Half Elf_Half;
|
||||
|
@ -104,12 +105,16 @@ private:
|
|||
void printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab,
|
||||
StringRef StrTable, bool IsDynamic);
|
||||
|
||||
void printDynamicRelocation(Elf_Rela Rel);
|
||||
void printRelocations(const Elf_Shdr *Sec);
|
||||
void printRelocation(Elf_Rela Rel, const Elf_Shdr *SymTab);
|
||||
void printValue(uint64_t Type, uint64_t Value);
|
||||
|
||||
const Elf_Rela *dyn_rela_begin() const;
|
||||
const Elf_Rela *dyn_rela_end() const;
|
||||
template <typename RELA>
|
||||
static const RELA *dyn_rela_begin(const DynRegionInfo ®ion);
|
||||
template <typename RELA>
|
||||
static const RELA *dyn_rela_end(const DynRegionInfo ®ion);
|
||||
Elf_Rel_Range dyn_rels() const;
|
||||
Elf_Rela_Range dyn_relas() const;
|
||||
StringRef getDynamicString(uint64_t Offset) const;
|
||||
const Elf_Dyn *dynamic_table_begin() const {
|
||||
|
@ -129,6 +134,7 @@ private:
|
|||
void LoadVersionDefs(const Elf_Shdr *sec) const;
|
||||
|
||||
const ELFO *Obj;
|
||||
DynRegionInfo DynRelRegion;
|
||||
DynRegionInfo DynRelaRegion;
|
||||
const Elf_Phdr *DynamicProgHeader = nullptr;
|
||||
StringRef DynamicStringTable;
|
||||
|
@ -944,6 +950,15 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer)
|
|||
GnuHashTable =
|
||||
reinterpret_cast<const Elf_GnuHash *>(toMappedAddr(Dyn.getPtr()));
|
||||
break;
|
||||
case ELF::DT_REL:
|
||||
DynRelRegion.Addr = toMappedAddr(Dyn.getPtr());
|
||||
break;
|
||||
case ELF::DT_RELSZ:
|
||||
DynRelRegion.Size = Dyn.getVal();
|
||||
break;
|
||||
case ELF::DT_RELENT:
|
||||
DynRelRegion.EntSize = Dyn.getVal();
|
||||
break;
|
||||
case ELF::DT_RELA:
|
||||
DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr());
|
||||
break;
|
||||
|
@ -1011,25 +1026,32 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer)
|
|||
}
|
||||
|
||||
template <typename ELFT>
|
||||
const typename ELFDumper<ELFT>::Elf_Rela *
|
||||
ELFDumper<ELFT>::dyn_rela_begin() const {
|
||||
if (DynRelaRegion.Size && DynRelaRegion.EntSize != sizeof(Elf_Rela))
|
||||
template <typename RELA>
|
||||
const RELA *ELFDumper<ELFT>::dyn_rela_begin(const DynRegionInfo &Region) {
|
||||
if (Region.Size && Region.EntSize != sizeof(RELA))
|
||||
report_fatal_error("Invalid relocation entry size");
|
||||
return reinterpret_cast<const Elf_Rela *>(DynRelaRegion.Addr);
|
||||
return reinterpret_cast<const RELA *>(Region.Addr);
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
const typename ELFDumper<ELFT>::Elf_Rela *
|
||||
ELFDumper<ELFT>::dyn_rela_end() const {
|
||||
uint64_t Size = DynRelaRegion.Size;
|
||||
if (Size % sizeof(Elf_Rela))
|
||||
template <typename RELA>
|
||||
const RELA *ELFDumper<ELFT>::dyn_rela_end(const DynRegionInfo &Region) {
|
||||
uint64_t Size = Region.Size;
|
||||
if (Size % sizeof(RELA))
|
||||
report_fatal_error("Invalid relocation table size");
|
||||
return dyn_rela_begin() + Size / sizeof(Elf_Rela);
|
||||
return dyn_rela_begin<RELA>(Region) + Size / sizeof(RELA);
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
typename ELFDumper<ELFT>::Elf_Rel_Range ELFDumper<ELFT>::dyn_rels() const {
|
||||
return make_range(dyn_rela_begin<Elf_Rel>(DynRelRegion),
|
||||
dyn_rela_end<Elf_Rel>(DynRelRegion));
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
typename ELFDumper<ELFT>::Elf_Rela_Range ELFDumper<ELFT>::dyn_relas() const {
|
||||
return make_range(dyn_rela_begin(), dyn_rela_end());
|
||||
return make_range(dyn_rela_begin<Elf_Rela>(DynRelaRegion),
|
||||
dyn_rela_end<Elf_Rela>(DynRelaRegion));
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
|
@ -1158,31 +1180,22 @@ void ELFDumper<ELFT>::printRelocations() {
|
|||
}
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printDynamicRelocations() {
|
||||
template <class ELFT> void ELFDumper<ELFT>::printDynamicRelocations() {
|
||||
if (DynRelRegion.Size && DynRelaRegion.Size)
|
||||
report_fatal_error("There are both REL and RELA dynamic relocations");
|
||||
W.startLine() << "Dynamic Relocations {\n";
|
||||
W.indent();
|
||||
for (const Elf_Rela &Rel : dyn_relas()) {
|
||||
SmallString<32> RelocName;
|
||||
Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);
|
||||
StringRef SymbolName;
|
||||
uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL());
|
||||
const Elf_Sym *Sym = DynSymStart + SymIndex;
|
||||
SymbolName = errorOrDefault(Sym->getName(DynamicStringTable));
|
||||
if (opts::ExpandRelocs) {
|
||||
DictScope Group(W, "Relocation");
|
||||
W.printHex("Offset", Rel.r_offset);
|
||||
W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL()));
|
||||
W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-");
|
||||
W.printHex("Addend", Rel.r_addend);
|
||||
if (DynRelaRegion.Size > 0)
|
||||
for (const Elf_Rela &Rela : dyn_relas())
|
||||
printDynamicRelocation(Rela);
|
||||
else
|
||||
for (const Elf_Rel &Rel : dyn_rels()) {
|
||||
Elf_Rela Rela;
|
||||
Rela.r_offset = Rel.r_offset;
|
||||
Rela.r_info = Rel.r_info;
|
||||
Rela.r_addend = 0;
|
||||
printDynamicRelocation(Rela);
|
||||
}
|
||||
else {
|
||||
raw_ostream& OS = W.startLine();
|
||||
OS << W.hex(Rel.r_offset) << " " << RelocName << " "
|
||||
<< (SymbolName.size() > 0 ? SymbolName : "-") << " "
|
||||
<< W.hex(Rel.r_addend) << "\n";
|
||||
}
|
||||
}
|
||||
W.unindent();
|
||||
W.startLine() << "}\n";
|
||||
}
|
||||
|
@ -1243,6 +1256,28 @@ void ELFDumper<ELFT>::printRelocation(Elf_Rela Rel, const Elf_Shdr *SymTab) {
|
|||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void ELFDumper<ELFT>::printDynamicRelocation(Elf_Rela Rel) {
|
||||
SmallString<32> RelocName;
|
||||
Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);
|
||||
StringRef SymbolName;
|
||||
uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL());
|
||||
const Elf_Sym *Sym = DynSymStart + SymIndex;
|
||||
SymbolName = errorOrDefault(Sym->getName(DynamicStringTable));
|
||||
if (opts::ExpandRelocs) {
|
||||
DictScope Group(W, "Relocation");
|
||||
W.printHex("Offset", Rel.r_offset);
|
||||
W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL()));
|
||||
W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-");
|
||||
W.printHex("Addend", Rel.r_addend);
|
||||
} else {
|
||||
raw_ostream &OS = W.startLine();
|
||||
OS << W.hex(Rel.r_offset) << " " << RelocName << " "
|
||||
<< (SymbolName.size() > 0 ? SymbolName : "-") << " "
|
||||
<< W.hex(Rel.r_addend) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) {
|
||||
const Elf_Shdr *Symtab = (IsDynamic) ? DotDynSymSec : DotSymtabSec;
|
||||
|
|
Loading…
Reference in New Issue