Index: include/llvm/Object/ELFObjectFile.h =================================================================== --- include/llvm/Object/ELFObjectFile.h +++ include/llvm/Object/ELFObjectFile.h @@ -15,6 +15,7 @@ #define LLVM_OBJECT_ELFOBJECTFILE_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" @@ -83,6 +84,8 @@ SubtargetFeatures getRISCVFeatures() const; void setARMSubArch(Triple &TheTriple) const override; + + virtual uint16_t getEType() const = 0; }; class ELFSectionRef : public SectionRef { @@ -200,6 +203,7 @@ template class ELFObjectFile : public ELFObjectFileBase { uint16_t getEMachine() const override; + uint16_t getEType() const override; uint64_t getSymbolSize(DataRefImpl Sym) const override; public: @@ -256,6 +260,7 @@ bool isSectionVirtual(DataRefImpl Sec) const override; relocation_iterator section_rel_begin(DataRefImpl Sec) const override; relocation_iterator section_rel_end(DataRefImpl Sec) const override; + std::vector dynamic_relocation_sections() const override; section_iterator getRelocatedSection(DataRefImpl Sec) const override; void moveRelocationNext(DataRefImpl &Rel) const override; @@ -507,6 +512,10 @@ return EF.getHeader()->e_machine; } +template uint16_t ELFObjectFile::getEType() const { + return EF.getHeader()->e_type; +} + template uint64_t ELFObjectFile::getSymbolSize(DataRefImpl Sym) const { return getSymbol(Sym)->st_size; @@ -711,6 +720,34 @@ EShdr->sh_type == ELF::SHT_NOBITS; } +template +std::vector +ELFObjectFile::dynamic_relocation_sections() const { + std::vector Res; + std::vector Offsets; + + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return Res; + + for (const Elf_Shdr &Sec : *SectionsOrErr) { + if (Sec.sh_type != ELF::SHT_DYNAMIC) + continue; + Elf_Dyn *Dynamic = + reinterpret_cast((uintptr_t)base() + Sec.sh_offset); + for (; Dynamic->d_tag != ELF::DT_NULL; Dynamic++) { + if (Dynamic->d_tag == ELF::DT_REL || Dynamic->d_tag == ELF::DT_RELA) { + Offsets.push_back(Dynamic->d_un.d_val); + } + } + } + for (const Elf_Shdr &Sec : *SectionsOrErr) { + if (is_contained(Offsets, Sec.sh_offset)) + Res.emplace_back(toDRI(&Sec), this); + } + return Res; +} + template bool ELFObjectFile::isSectionVirtual(DataRefImpl Sec) const { return getSection(Sec)->sh_type == ELF::SHT_NOBITS; @@ -792,8 +829,6 @@ template uint64_t ELFObjectFile::getRelocationOffset(DataRefImpl Rel) const { - assert(EF.getHeader()->e_type == ELF::ET_REL && - "Only relocatable object files have relocation offsets"); const Elf_Shdr *sec = getRelSection(Rel); if (sec->sh_type == ELF::SHT_REL) return getRel(Rel)->r_offset; Index: include/llvm/Object/ObjectFile.h =================================================================== --- include/llvm/Object/ObjectFile.h +++ include/llvm/Object/ObjectFile.h @@ -262,6 +262,10 @@ return getCommonSymbolSizeImpl(Symb); } + virtual std::vector dynamic_relocation_sections() const { + return std::vector(); + } + using symbol_iterator_range = iterator_range; symbol_iterator_range symbols() const { return symbol_iterator_range(symbol_begin(), symbol_end()); Index: tools/llvm-objdump/llvm-objdump.h =================================================================== --- tools/llvm-objdump/llvm-objdump.h +++ tools/llvm-objdump/llvm-objdump.h @@ -56,6 +56,7 @@ extern cl::opt DisSymName; extern cl::opt NonVerbose; extern cl::opt Relocations; +extern cl::opt DynamicRelocations; extern cl::opt SectionHeaders; extern cl::opt SectionContents; extern cl::opt SymbolTable; @@ -88,6 +89,7 @@ void printWeakBindTable(object::ObjectFile *o); void printRawClangAST(const object::ObjectFile *o); void PrintRelocations(const object::ObjectFile *o); +void PrintDynamicRelocations(const object::ObjectFile *o); void PrintSectionHeaders(const object::ObjectFile *o); void PrintSectionContents(const object::ObjectFile *o); void PrintSymbolTable(const object::ObjectFile *o, StringRef ArchiveName, Index: tools/llvm-objdump/llvm-objdump.cpp =================================================================== --- tools/llvm-objdump/llvm-objdump.cpp +++ tools/llvm-objdump/llvm-objdump.cpp @@ -93,6 +93,9 @@ cl::opt llvm::Relocations("r", cl::desc("Display the relocation entries in the file")); +cl::opt +llvm::DynamicRelocations("R", cl::desc("Display the dynamic relocation entries in the file")); + cl::opt llvm::SectionContents("s", cl::desc("Display the content of each section")); @@ -431,6 +434,7 @@ return errorToErrorCode(StrTabOrErr.takeError()); StringRef StrTab = *StrTabOrErr; int64_t addend = 0; + bool undef = false; switch (Sec->sh_type) { default: return object_error::parse_failed; @@ -441,27 +445,31 @@ case ELF::SHT_RELA: { const Elf_Rela *ERela = Obj->getRela(Rel); addend = ERela->r_addend; + undef = ERela->getSymbol(false) == 0; break; } } - symbol_iterator SI = RelRef.getSymbol(); - const Elf_Sym *symb = Obj->getSymbol(SI->getRawDataRefImpl()); StringRef Target; - if (symb->getType() == ELF::STT_SECTION) { - Expected SymSI = SI->getSection(); - if (!SymSI) - return errorToErrorCode(SymSI.takeError()); - const Elf_Shdr *SymSec = Obj->getSection((*SymSI)->getRawDataRefImpl()); - auto SecName = EF.getSectionName(SymSec); - if (!SecName) - return errorToErrorCode(SecName.takeError()); - Target = *SecName; - } else { - Expected SymName = symb->getName(StrTab); - if (!SymName) - return errorToErrorCode(SymName.takeError()); - Target = *SymName; - } + if (!undef) { + symbol_iterator SI = RelRef.getSymbol(); + const Elf_Sym *symb = Obj->getSymbol(SI->getRawDataRefImpl()); + if (symb->getType() == ELF::STT_SECTION) { + Expected SymSI = SI->getSection(); + if (!SymSI) + return errorToErrorCode(SymSI.takeError()); + const Elf_Shdr *SymSec = Obj->getSection((*SymSI)->getRawDataRefImpl()); + auto SecName = EF.getSectionName(SymSec); + if (!SecName) + return errorToErrorCode(SecName.takeError()); + Target = *SecName; + } else { + Expected SymName = symb->getName(StrTab); + if (!SymName) + return errorToErrorCode(SymName.takeError()); + Target = *SymName; + } + } else + Target = "*ABS*"; // Default scheme is to print Target, as well as "+ " for nonzero // addend. Should be acceptable for all normal purposes. @@ -1727,6 +1735,42 @@ } } +void llvm::PrintDynamicRelocations(const ObjectFile *Obj) { + + // For the moment, this option is for ELF only + if (!Obj->isELF()) + return; + + const auto *Elf = dyn_cast(Obj); + + if (!Elf || Elf->getEType() != ELF::ET_DYN) { + error("not a dynamic object"); + return; + } + + StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64; + + // TODO: ensure the relocation is a dynamic relocation + std::vector DynRelSec = Obj->dynamic_relocation_sections(); + if (DynRelSec.empty()) + return; + + outs() << "DYNAMIC RELOCATION RECORDS\n"; + for (const SectionRef &Section : DynRelSec) { + if (Section.relocation_begin() == Section.relocation_end()) + continue; + for (const RelocationRef &Reloc : Section.relocations()) { + uint64_t address = Reloc.getOffset(); + SmallString<32> relocname; + SmallString<32> valuestr; + Reloc.getTypeName(relocname); + error(getRelocationValueString(Reloc, valuestr)); + outs() << format(Fmt.data(), address) << " " << relocname << " " + << valuestr << "\n"; + } + } +} + void llvm::PrintSectionHeaders(const ObjectFile *Obj) { outs() << "Sections:\n" "Idx Name Size Address Type\n"; @@ -2069,6 +2113,8 @@ DisassembleObject(o, Relocations); if (Relocations && !Disassemble) PrintRelocations(o); + if (DynamicRelocations) + PrintDynamicRelocations(o); if (SectionHeaders) PrintSectionHeaders(o); if (SectionContents) @@ -2186,6 +2232,7 @@ Disassemble = true; if (!Disassemble && !Relocations + && !DynamicRelocations && !SectionHeaders && !SectionContents && !SymbolTable