From 6272b8c4be263e98bc395c3a7bc81d161f031406 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Wed, 19 Nov 2014 00:18:07 +0000 Subject: [PATCH] llvm-readobj: teach it how to dump COFF base relocation table git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@222289 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/COFF.h | 39 ++++++++++ lib/Object/COFFObjectFile.cpp | 70 +++++++++++++++++- .../Inputs/basereloc.obj.coff-i386 | Bin 0 -> 2560 bytes test/tools/llvm-readobj/coff-basereloc.test | 20 +++++ tools/llvm-readobj/COFFDumper.cpp | 31 ++++++++ tools/llvm-readobj/ObjDumper.h | 1 + tools/llvm-readobj/llvm-readobj.cpp | 9 ++- 7 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 test/tools/llvm-readobj/Inputs/basereloc.obj.coff-i386 create mode 100644 test/tools/llvm-readobj/coff-basereloc.test diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h index 80078a47bbc..3368d68b8d1 100644 --- a/include/llvm/Object/COFF.h +++ b/include/llvm/Object/COFF.h @@ -28,11 +28,13 @@ class ImportDirectoryEntryRef; class DelayImportDirectoryEntryRef; class ExportDirectoryEntryRef; class ImportedSymbolRef; +class BaseRelocRef; typedef content_iterator import_directory_iterator; typedef content_iterator delay_import_directory_iterator; typedef content_iterator export_directory_iterator; typedef content_iterator imported_symbol_iterator; +typedef content_iterator base_reloc_iterator; /// The DOS compatible header at the front of all PE/COFF executables. struct dos_header { @@ -459,6 +461,17 @@ struct coff_runtime_function_x64 { support::ulittle32_t UnwindInformation; }; +struct coff_base_reloc_block_header { + support::ulittle32_t PageRVA; + support::ulittle32_t BlockSize; +}; + +struct coff_base_reloc_block_entry { + support::ulittle16_t Data; + int getType() const { return Data >> 12; } + int getOffset() const { return Data & ((1 << 12) - 1); } +}; + class COFFObjectFile : public ObjectFile { private: friend class ImportDirectoryEntryRef; @@ -478,6 +491,8 @@ private: const delay_import_directory_table_entry *DelayImportDirectory; uint32_t NumberOfDelayImportDirectory; const export_directory_table_entry *ExportDirectory; + const coff_base_reloc_block_header *BaseRelocHeader; + const coff_base_reloc_block_header *BaseRelocEnd; std::error_code getString(uint32_t offset, StringRef &Res) const; @@ -490,6 +505,7 @@ private: std::error_code initImportTablePtr(); std::error_code initDelayImportTablePtr(); std::error_code initExportTablePtr(); + std::error_code initBaseRelocPtr(); public: uintptr_t getSymbolTable() const { @@ -621,11 +637,14 @@ public: delay_import_directory_iterator delay_import_directory_end() const; export_directory_iterator export_directory_begin() const; export_directory_iterator export_directory_end() const; + base_reloc_iterator base_reloc_begin() const; + base_reloc_iterator base_reloc_end() const; iterator_range import_directories() const; iterator_range delay_import_directories() const; iterator_range export_directories() const; + iterator_range base_relocs() const; const dos_header *getDOSHeader() const { if (!PE32Header && !PE32PlusHeader) @@ -798,6 +817,26 @@ private: uint32_t Index; const COFFObjectFile *OwningObject; }; + +class BaseRelocRef { +public: + BaseRelocRef() : OwningObject(nullptr) {} + BaseRelocRef(const coff_base_reloc_block_header *Header, + const COFFObjectFile *Owner) + : Header(Header), Index(0), OwningObject(Owner) {} + + bool operator==(const BaseRelocRef &Other) const; + void moveNext(); + + std::error_code getType(uint8_t &Type) const; + std::error_code getRVA(uint32_t &Result) const; + +private: + const coff_base_reloc_block_header *Header; + uint32_t Index; + const COFFObjectFile *OwningObject; +}; + } // end namespace object } // end namespace llvm diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp index e25b63b11be..c5d7c409519 100644 --- a/lib/Object/COFFObjectFile.cpp +++ b/lib/Object/COFFObjectFile.cpp @@ -598,6 +598,23 @@ std::error_code COFFObjectFile::initExportTablePtr() { return object_error::success; } +std::error_code COFFObjectFile::initBaseRelocPtr() { + const data_directory *DataEntry; + if (getDataDirectory(COFF::BASE_RELOCATION_TABLE, DataEntry)) + return object_error::success; + if (DataEntry->RelativeVirtualAddress == 0) + return object_error::success; + + uintptr_t IntPtr = 0; + if (std::error_code EC = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr)) + return EC; + BaseRelocHeader = reinterpret_cast( + IntPtr); + BaseRelocEnd = reinterpret_cast( + IntPtr + DataEntry->Size); + return object_error::success; +} + COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC) : ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr), COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr), @@ -605,7 +622,8 @@ COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC) SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0), ImportDirectory(nullptr), NumberOfImportDirectory(0), DelayImportDirectory(nullptr), NumberOfDelayImportDirectory(0), - ExportDirectory(nullptr) { + ExportDirectory(nullptr), BaseRelocHeader(nullptr), + BaseRelocEnd(nullptr) { // Check that we at least have enough room for a header. if (!checkSize(Data, EC, sizeof(coff_file_header))) return; @@ -717,6 +735,10 @@ COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC) if ((EC = initExportTablePtr())) return; + // Initialize the pointer to the base relocation table. + if ((EC = initBaseRelocPtr())) + return; + EC = object_error::success; } @@ -783,6 +805,14 @@ section_iterator COFFObjectFile::section_end() const { return section_iterator(SectionRef(Ret, this)); } +base_reloc_iterator COFFObjectFile::base_reloc_begin() const { + return base_reloc_iterator(BaseRelocRef(BaseRelocHeader, this)); +} + +base_reloc_iterator COFFObjectFile::base_reloc_end() const { + return base_reloc_iterator(BaseRelocRef(BaseRelocEnd, this)); +} + uint8_t COFFObjectFile::getBytesInAddress() const { return getArch() == Triple::x86_64 ? 8 : 4; } @@ -829,6 +859,10 @@ COFFObjectFile::export_directories() const { return make_range(export_directory_begin(), export_directory_end()); } +iterator_range COFFObjectFile::base_relocs() const { + return make_range(base_reloc_begin(), base_reloc_end()); +} + std::error_code COFFObjectFile::getPE32Header(const pe32_header *&Res) const { Res = PE32Header; return object_error::success; @@ -1448,3 +1482,37 @@ ObjectFile::createCOFFObjectFile(MemoryBufferRef Object) { return EC; return std::move(Ret); } + +bool BaseRelocRef::operator==(const BaseRelocRef &Other) const { + return Header == Other.Header && Index == Other.Index; +} + +void BaseRelocRef::moveNext() { + // Header->BlockSize is the size of the current block, including the + // size of the header itself. + uint32_t Size = sizeof(*Header) + + sizeof(coff_base_reloc_block_entry) * Index; + if (Size == Header->BlockSize) { + // .reloc contains a list of base relocation blocks. Each block + // consists of the header followed by entries. The header contains + // how many entories will follow. When we reach the end of the + // current block, proceed to the next block. + Header = reinterpret_cast( + reinterpret_cast(Header) + Size); + Index = 0; + } else { + ++Index; + } +} + +std::error_code BaseRelocRef::getType(uint8_t &Type) const { + auto *Entry = reinterpret_cast(Header + 1); + Type = Entry[Index].getType(); + return object_error::success; +} + +std::error_code BaseRelocRef::getRVA(uint32_t &Result) const { + auto *Entry = reinterpret_cast(Header + 1); + Result = Header->PageRVA + Entry[Index].getOffset(); + return object_error::success; +} diff --git a/test/tools/llvm-readobj/Inputs/basereloc.obj.coff-i386 b/test/tools/llvm-readobj/Inputs/basereloc.obj.coff-i386 new file mode 100644 index 0000000000000000000000000000000000000000..0aeed443e33a9aee86733a95c36655b42cedfdbb GIT binary patch literal 2560 zcmeZ`n!v!!z`(!)#Q*;@Fzf)*Am9Kd@e><>(tPr}_!zcuo>knz=yO&vBqOs}p`a)~ zy(lqPAvrNGFTX?~DOI7UG*2NjPr=1MSRpq*B~_1?mrDg|w4m&w8=*C4x?wm%Pp3Ns z$dAwy0@Fd6$r&Iym`eg&85n#RnHdh=&JKZzJz!vBM0#K{~;y6I~ zKzTM07YJZ9*rQNA%nS~#V1*#PAOpZOoB|0F1_mUmCu|~Eg9hsFWDqST!HWT;z#ZU(F4087IO2L=WwIA@eG zEJGl)`^`cI1qTLZRu(YH0VHD&4@<9(dJ0PjumZ(E#REGQxly4J5CXuu1XP`{7;qT~ Mfa-x!Frq>L0CXTesQ>@~ literal 0 HcmV?d00001 diff --git a/test/tools/llvm-readobj/coff-basereloc.test b/test/tools/llvm-readobj/coff-basereloc.test new file mode 100644 index 00000000000..752e73ab2d4 --- /dev/null +++ b/test/tools/llvm-readobj/coff-basereloc.test @@ -0,0 +1,20 @@ +RUN: llvm-readobj -coff-basereloc %p/Inputs/basereloc.obj.coff-i386 | FileCheck %s + +CHECK: Format: COFF-i386 +CHECK: Arch: i386 +CHECK: AddressSize: 32bit +CHECK: BaseReloc [ +CHECK: Entry { +CHECK: Type: HIGHLOW +CHECK: Address: 0x1004 +CHECK: } +CHECK: Entry { +CHECK: Type: HIGHLOW +CHECK: Address: 0x100A +CHECK: } +CHECK: Entry { +CHECK: Type: HIGHLOW +CHECK: Address: 0x1010 +CHECK: } +CHECK: ] + diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp index fac74adbe0a..2ea3cd8a3da 100644 --- a/tools/llvm-readobj/COFFDumper.cpp +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -57,6 +57,7 @@ public: void printUnwindInfo() override; void printCOFFImports() override; void printCOFFDirectives() override; + void printCOFFBaseReloc() override; private: void printSymbol(const SymbolRef &Sym); @@ -1076,3 +1077,33 @@ void COFFDumper::printCOFFDirectives() { W.printString("Directive(s)", Contents); } } + +static StringRef getBaseRelocTypeName(uint8_t Type) { + switch (Type) { + case COFF::IMAGE_REL_BASED_ABSOLUTE: return "ABSOLUTE"; + case COFF::IMAGE_REL_BASED_HIGH: return "HIGH"; + case COFF::IMAGE_REL_BASED_LOW: return "LOW"; + case COFF::IMAGE_REL_BASED_HIGHLOW: return "HIGHLOW"; + case COFF::IMAGE_REL_BASED_HIGHADJ: return "HIGHADJ"; + case COFF::IMAGE_REL_BASED_DIR64: return "DIR64"; + default: return "unknown"; + } +} + +void COFFDumper::printCOFFBaseReloc() { + ListScope D(W, "BaseReloc"); + for (const BaseRelocRef &I : Obj->base_relocs()) { + uint8_t Type; + uint32_t RVA; + if (error(I.getRVA(RVA))) + continue; + if (error(I.getType(Type))) + continue; + // IMAGE_REL_BASED_ABSOLUTE is a NOP entry. + if (Type == COFF::IMAGE_REL_BASED_ABSOLUTE) + continue; + DictScope Import(W, "Entry"); + W.printString("Type", getBaseRelocTypeName(Type)); + W.printHex("Address", RVA); + } +} diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h index b898224a44d..a34e0912728 100644 --- a/tools/llvm-readobj/ObjDumper.h +++ b/tools/llvm-readobj/ObjDumper.h @@ -46,6 +46,7 @@ public: // Only implemented for PE/COFF. virtual void printCOFFImports() { } virtual void printCOFFDirectives() { } + virtual void printCOFFBaseReloc() { } protected: StreamWriter& W; diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 6d05658c07c..d08f18608ed 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -149,7 +149,12 @@ namespace opts { // -coff-directives cl::opt COFFDirectives("coff-directives", - cl::desc("Display the contents PE/COFF .drectve section")); + cl::desc("Display the PE/COFF .drectve section")); + + // -coff-basereloc + cl::opt + COFFBaseRelocs("coff-basereloc", + cl::desc("Display the PE/COFF .reloc section")); } // namespace opts static int ReturnValue = EXIT_SUCCESS; @@ -279,6 +284,8 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printCOFFImports(); if (opts::COFFDirectives) Dumper->printCOFFDirectives(); + if (opts::COFFBaseRelocs) + Dumper->printCOFFBaseReloc(); } -- 2.34.1