From: Benjamin Kramer Date: Thu, 8 Sep 2011 20:52:17 +0000 (+0000) Subject: Add support for relocations to ObjectFile. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=0fcab076f0358890e2f1b213f4303c780e05d99d;p=oota-llvm.git Add support for relocations to ObjectFile. Patch by Danil Malyshev! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@139314 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h index 121f9e85045..1663caf60b5 100644 --- a/include/llvm/Object/COFF.h +++ b/include/llvm/Object/COFF.h @@ -67,6 +67,12 @@ struct coff_section { support::ulittle32_t Characteristics; }; +struct coff_relocation { + support::ulittle32_t VirtualAddress; + support::ulittle32_t SymbolTableIndex; + support::ulittle16_t Type; +}; + class COFFObjectFile : public ObjectFile { private: const coff_file_header *Header; @@ -81,6 +87,7 @@ private: const coff_symbol *toSymb(DataRefImpl Symb) const; const coff_section *toSec(DataRefImpl Sec) const; + const coff_relocation *toRel(DataRefImpl Rel) const; protected: virtual error_code getSymbolNext(DataRefImpl Symb, SymbolRef &Res) const; @@ -99,12 +106,24 @@ protected: virtual error_code sectionContainsSymbol(DataRefImpl Sec, DataRefImpl Symb, bool &Result) const; + virtual error_code getRelocationNext(DataRefImpl Rel, + RelocationRef &Res) const; + virtual error_code getRelocationAddress(DataRefImpl Rel, + uint64_t &Res) const; + virtual error_code getRelocationSymbol(DataRefImpl Rel, + SymbolRef &Res) const; + virtual error_code getRelocationType(DataRefImpl Rel, + uint32_t &Res) const; + virtual error_code getRelocationAdditionalInfo(DataRefImpl Rel, + int64_t &Res) const; public: COFFObjectFile(MemoryBuffer *Object, error_code &ec); virtual symbol_iterator begin_symbols() const; virtual symbol_iterator end_symbols() const; virtual section_iterator begin_sections() const; virtual section_iterator end_sections() const; + virtual relocation_iterator begin_relocations() const; + virtual relocation_iterator end_relocations() const; virtual uint8_t getBytesInAddress() const; virtual StringRef getFileFormatName() const; diff --git a/include/llvm/Object/ObjectFile.h b/include/llvm/Object/ObjectFile.h index 98ac0672796..24c868ed16d 100644 --- a/include/llvm/Object/ObjectFile.h +++ b/include/llvm/Object/ObjectFile.h @@ -39,22 +39,6 @@ static bool operator ==(const DataRefImpl &a, const DataRefImpl &b) { return std::memcmp(&a, &b, sizeof(DataRefImpl)) == 0; } -class RelocationRef { - DataRefImpl RelocationPimpl; - const ObjectFile *OwningObject; - -public: - RelocationRef() : OwningObject(NULL) { - std::memset(&RelocationPimpl, 0, sizeof(RelocationPimpl)); - } - - RelocationRef(DataRefImpl RelocationP, const ObjectFile *Owner); - - bool operator==(const RelocationRef &Other) const; - - error_code getNext(RelocationRef &Result); -}; - /// SymbolRef - This is a value type class that represents a single symbol in /// the list of symbols in the object file. class SymbolRef { @@ -86,6 +70,29 @@ public: error_code isInternal(bool &Result) const; }; +/// RelocationRef - This is a value type class that represents a single +/// relocation in the list of relocations in the object file. +class RelocationRef { + DataRefImpl RelocationPimpl; + const ObjectFile *OwningObject; + +public: + RelocationRef() : OwningObject(NULL) { + std::memset(&RelocationPimpl, 0, sizeof(RelocationPimpl)); + } + + RelocationRef(DataRefImpl RelocationP, const ObjectFile *Owner); + + bool operator==(const RelocationRef &Other) const; + + error_code getNext(RelocationRef &Result) const; + + error_code getAddress(uint64_t &Result) const; + error_code getSymbol(SymbolRef &Result) const; + error_code getType(uint32_t &Result) const; + error_code getAdditionalInfo(int64_t &Result) const; +}; + /// SectionRef - This is a value type class that represents a single section in /// the list of sections in the object file. class SectionRef { @@ -160,6 +167,19 @@ protected: bool &Result) const = 0; + // Same as above for RelocationRef. + friend class RelocationRef; + virtual error_code getRelocationNext(DataRefImpl Rel, + RelocationRef &Res) const = 0; + virtual error_code getRelocationAddress(DataRefImpl Rel, + uint64_t &Res) const =0; + virtual error_code getRelocationSymbol(DataRefImpl Rel, + SymbolRef &Res) const = 0; + virtual error_code getRelocationType(DataRefImpl Rel, + uint32_t &Res) const = 0; + virtual error_code getRelocationAdditionalInfo(DataRefImpl Rel, + int64_t &Res) const = 0; + public: template class content_iterator { @@ -196,6 +216,7 @@ public: typedef content_iterator symbol_iterator; typedef content_iterator section_iterator; + typedef content_iterator relocation_iterator; virtual symbol_iterator begin_symbols() const = 0; virtual symbol_iterator end_symbols() const = 0; @@ -203,6 +224,9 @@ public: virtual section_iterator begin_sections() const = 0; virtual section_iterator end_sections() const = 0; + virtual relocation_iterator begin_relocations() const = 0; + virtual relocation_iterator end_relocations() const = 0; + /// @brief The number of bytes used to represent an address in this object /// file format. virtual uint8_t getBytesInAddress() const = 0; @@ -302,6 +326,37 @@ inline error_code SectionRef::containsSymbol(SymbolRef S, bool &Result) const { Result); } + +/// RelocationRef +inline RelocationRef::RelocationRef(DataRefImpl RelocationP, + const ObjectFile *Owner) + : RelocationPimpl(RelocationP) + , OwningObject(Owner) {} + +inline bool RelocationRef::operator==(const RelocationRef &Other) const { + return RelocationPimpl == Other.RelocationPimpl; +} + +inline error_code RelocationRef::getNext(RelocationRef &Result) const { + return OwningObject->getRelocationNext(RelocationPimpl, Result); +} + +inline error_code RelocationRef::getAddress(uint64_t &Result) const { + return OwningObject->getRelocationAddress(RelocationPimpl, Result); +} + +inline error_code RelocationRef::getSymbol(SymbolRef &Result) const { + return OwningObject->getRelocationSymbol(RelocationPimpl, Result); +} + +inline error_code RelocationRef::getType(uint32_t &Result) const { + return OwningObject->getRelocationType(RelocationPimpl, Result); +} + +inline error_code RelocationRef::getAdditionalInfo(int64_t &Result) const { + return OwningObject->getRelocationAdditionalInfo(RelocationPimpl, Result); +} + } // end namespace object } // end namespace llvm diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp index 07de6bc9997..594fcd16981 100644 --- a/lib/Object/COFFObjectFile.cpp +++ b/lib/Object/COFFObjectFile.cpp @@ -327,7 +327,7 @@ COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &ec) Header = reinterpret_cast(base() + HeaderStart); if (!checkAddr(Data, ec, uintptr_t(Header), sizeof(coff_file_header))) return; - + SectionTable = reinterpret_cast( base() + HeaderStart @@ -360,7 +360,7 @@ COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &ec) ec = object_error::parse_failed; return; } - + ec = object_error::success; } @@ -445,6 +445,77 @@ error_code COFFObjectFile::getString(uint32_t offset, return object_error::success; } +const coff_relocation *COFFObjectFile::toRel(DataRefImpl Rel) const { + assert(Rel.d.b < Header->NumberOfSections && "Section index out of range!"); + const coff_section *Sect; + getSection(Rel.d.b, Sect); + assert(Rel.d.a < Sect->NumberOfRelocations && "Relocation index out of range!"); + return + reinterpret_cast(base() + + Sect->PointerToRelocations) + + Rel.d.a; +} +error_code COFFObjectFile::getRelocationNext(DataRefImpl Rel, + RelocationRef &Res) const { + const coff_section *Sect = NULL; + if (error_code ec = getSection(Rel.d.b, Sect)) + return ec; + if (++Rel.d.a >= Sect->NumberOfRelocations) { + Rel.d.a = 0; + while (++Rel.d.b < Header->NumberOfSections) { + const coff_section *Sect; + getSection(Rel.d.b, Sect); + if (Sect->NumberOfRelocations > 0) + break; + } + } + Res = RelocationRef(Rel, this); + return object_error::success; +} +error_code COFFObjectFile::getRelocationAddress(DataRefImpl Rel, + uint64_t &Res) const { + const coff_section *Sect; + if (error_code ec = getSection(Rel.d.b, Sect)) + return ec; + const coff_relocation* R = toRel(Rel); + Res = reinterpret_cast(base() + + Sect->PointerToRawData + + R->VirtualAddress); + return object_error::success; +} +error_code COFFObjectFile::getRelocationSymbol(DataRefImpl Rel, + SymbolRef &Res) const { + const coff_relocation* R = toRel(Rel); + DataRefImpl Symb; + Symb.p = reinterpret_cast(SymbolTable + R->SymbolTableIndex); + Res = SymbolRef(Symb, this); + return object_error::success; +} +error_code COFFObjectFile::getRelocationType(DataRefImpl Rel, + uint32_t &Res) const { + const coff_relocation* R = toRel(Rel); + Res = R->Type; + return object_error::success; +} +error_code COFFObjectFile::getRelocationAdditionalInfo(DataRefImpl Rel, + int64_t &Res) const { + Res = 0; + return object_error::success; +} +ObjectFile::relocation_iterator COFFObjectFile::begin_relocations() const { + DataRefImpl ret; + ret.d.a = 0; + ret.d.b = 1; + return relocation_iterator(RelocationRef(ret, this)); +} +ObjectFile::relocation_iterator COFFObjectFile::end_relocations() const { + DataRefImpl ret; + ret.d.a = 0; + ret.d.b = Header->NumberOfSections; + return relocation_iterator(RelocationRef(ret, this)); +} + + namespace llvm { ObjectFile *ObjectFile::createCOFFObjectFile(MemoryBuffer *Object) { diff --git a/lib/Object/ELFObjectFile.cpp b/lib/Object/ELFObjectFile.cpp index e2ff4dfc038..15e76527744 100644 --- a/lib/Object/ELFObjectFile.cpp +++ b/lib/Object/ELFObjectFile.cpp @@ -14,6 +14,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" @@ -175,6 +176,81 @@ struct Elf_Sym_Impl : Elf_Sym_Base { }; } +namespace { +template +struct Elf_Rel_Base; + +template +struct Elf_Rel_Base { + LLVM_ELF_IMPORT_TYPES(target_endianness, false) + Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) + Elf_Word r_info; // Symbol table index and type of relocation to apply +}; + +template +struct Elf_Rel_Base { + LLVM_ELF_IMPORT_TYPES(target_endianness, true) + Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) + Elf_Xword r_info; // Symbol table index and type of relocation to apply +}; + +template +struct Elf_Rel_Base { + LLVM_ELF_IMPORT_TYPES(target_endianness, false) + Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) + Elf_Word r_info; // Symbol table index and type of relocation to apply + Elf_Sword r_addend; // Compute value for relocatable field by adding this +}; + +template +struct Elf_Rel_Base { + LLVM_ELF_IMPORT_TYPES(target_endianness, true) + Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) + Elf_Xword r_info; // Symbol table index and type of relocation to apply + Elf_Sxword r_addend; // Compute value for relocatable field by adding this. +}; + +template +struct Elf_Rel_Impl; + +template +struct Elf_Rel_Impl + : Elf_Rel_Base { + using Elf_Rel_Base::r_info; + LLVM_ELF_IMPORT_TYPES(target_endianness, true) + + // These accessors and mutators correspond to the ELF64_R_SYM, ELF64_R_TYPE, + // and ELF64_R_INFO macros defined in the ELF specification: + uint64_t getSymbol() const { return (r_info >> 32); } + unsigned char getType() const { + return (unsigned char) (r_info & 0xffffffffL); + } + void setSymbol(uint64_t s) { setSymbolAndType(s, getType()); } + void setType(unsigned char t) { setSymbolAndType(getSymbol(), t); } + void setSymbolAndType(uint64_t s, unsigned char t) { + r_info = (s << 32) + (t&0xffffffffL); + } +}; + +template +struct Elf_Rel_Impl + : Elf_Rel_Base { + using Elf_Rel_Base::r_info; + LLVM_ELF_IMPORT_TYPES(target_endianness, false) + + // These accessors and mutators correspond to the ELF32_R_SYM, ELF32_R_TYPE, + // and ELF32_R_INFO macros defined in the ELF specification: + uint32_t getSymbol() const { return (r_info >> 8); } + unsigned char getType() const { return (unsigned char) (r_info & 0x0ff); } + void setSymbol(uint32_t s) { setSymbolAndType(s, getType()); } + void setType(unsigned char t) { setSymbolAndType(getSymbol(), t); } + void setSymbolAndType(uint32_t s, unsigned char t) { + r_info = (s << 8) + t; + } +}; + +} + namespace { template class ELFObjectFile : public ObjectFile { @@ -182,6 +258,8 @@ class ELFObjectFile : public ObjectFile { typedef Elf_Shdr_Impl Elf_Shdr; typedef Elf_Sym_Impl Elf_Sym; + typedef Elf_Rel_Impl Elf_Rel; + typedef Elf_Rel_Impl Elf_Rela; struct Elf_Ehdr { unsigned char e_ident[ELF::EI_NIDENT]; // ELF Identification bytes @@ -206,18 +284,26 @@ class ELFObjectFile : public ObjectFile { unsigned char getDataEncoding() const { return e_ident[ELF::EI_DATA]; } }; - typedef SmallVector SymbolTableSections_t; + typedef SmallVector Sections_t; + typedef DenseMap IndexMap_t; const Elf_Ehdr *Header; const Elf_Shdr *SectionHeaderTable; const Elf_Shdr *dot_shstrtab_sec; // Section header string table. const Elf_Shdr *dot_strtab_sec; // Symbol header string table. - SymbolTableSections_t SymbolTableSections; + Sections_t SymbolTableSections; + IndexMap_t SymbolTableSectionsIndexMap; + Sections_t RelocationTableSections; void validateSymbol(DataRefImpl Symb) const; + bool isRelocationHasAddend(DataRefImpl Rel) const; + template + const T *getEntry(DataRefImpl Entry, Sections_t Sections) const; const Elf_Sym *getSymbol(DataRefImpl Symb) const; const Elf_Shdr *getSection(DataRefImpl index) const; const Elf_Shdr *getSection(uint16_t index) const; + const Elf_Rel *getRel(DataRefImpl Rel) const; + const Elf_Rela *getRela(DataRefImpl Rela) const; const char *getString(uint16_t section, uint32_t offset) const; const char *getString(const Elf_Shdr *section, uint32_t offset) const; @@ -238,12 +324,25 @@ protected: virtual error_code sectionContainsSymbol(DataRefImpl Sec, DataRefImpl Symb, bool &Result) const; + virtual error_code getRelocationNext(DataRefImpl Rel, + RelocationRef &Res) const; + virtual error_code getRelocationAddress(DataRefImpl Rel, + uint64_t &Res) const; + virtual error_code getRelocationSymbol(DataRefImpl Rel, + SymbolRef &Res) const; + virtual error_code getRelocationType(DataRefImpl Rel, + uint32_t &Res) const; + virtual error_code getRelocationAdditionalInfo(DataRefImpl Rel, + int64_t &Res) const; + public: ELFObjectFile(MemoryBuffer *Object, error_code &ec); virtual symbol_iterator begin_symbols() const; virtual symbol_iterator end_symbols() const; virtual section_iterator begin_sections() const; virtual section_iterator end_sections() const; + virtual relocation_iterator begin_relocations() const; + virtual relocation_iterator end_relocations() const; virtual uint8_t getBytesInAddress() const; virtual StringRef getFileFormatName() const; @@ -416,7 +515,8 @@ error_code ELFObjectFile return ec; Result = StringSwitch(name) .StartsWith(".debug", 'N') - .StartsWith(".note", 'n'); + .StartsWith(".note", 'n') + .Default('?'); return object_error::success; } @@ -507,6 +607,121 @@ error_code ELFObjectFile return object_error::success; } +// Relocations +template +error_code ELFObjectFile + ::getRelocationNext(DataRefImpl Rel, + RelocationRef &Result) const { + const Elf_Shdr *RelocationTableSection = RelocationTableSections[Rel.d.b]; + + // Check to see if we are at the end of this relocation table. + if (++Rel.d.a >= RelocationTableSection->getEntityCount()) { + // We are at the end. If there are other relocation tables, jump to them. + Rel.d.a = 0; + // Otherwise return the terminator. + if (++Rel.d.b >= SymbolTableSections.size()) { + Rel.d.a = std::numeric_limits::max(); + Rel.d.b = std::numeric_limits::max(); + } + } + + Result = RelocationRef(Rel, this); + return object_error::success; +} + +template +error_code ELFObjectFile + ::getRelocationSymbol(DataRefImpl Rel, + SymbolRef &Result) const { + uint32_t symbolIdx; + const Elf_Shdr *sec = RelocationTableSections[Rel.d.b]; + switch (sec->sh_type) { + default : + report_fatal_error("Invalid section type in Rel!"); + case ELF::SHT_REL : { + symbolIdx = getRel(Rel)->getSymbol(); + break; + } + case ELF::SHT_RELA : { + symbolIdx = getRela(Rel)->getSymbol(); + break; + } + } + DataRefImpl SymbolData; + IndexMap_t::const_iterator it = SymbolTableSectionsIndexMap.find(sec->sh_link); + if (it == SymbolTableSectionsIndexMap.end()) + report_fatal_error("Relocation symbol table not found!"); + SymbolData.d.a = symbolIdx; + SymbolData.d.b = it->second; + Result = SymbolRef(SymbolData, this); + return object_error::success; +} + +template +error_code ELFObjectFile + ::getRelocationAddress(DataRefImpl Rel, + uint64_t &Result) const { + uint64_t offset; + const Elf_Shdr *sec = RelocationTableSections[Rel.d.b]; + switch (sec->sh_type) { + default : + report_fatal_error("Invalid section type in Rel!"); + case ELF::SHT_REL : { + offset = getRel(Rel)->r_offset; + break; + } + case ELF::SHT_RELA : { + offset = getRela(Rel)->r_offset; + break; + } + } + + const Elf_Shdr *secAddr = getSection(sec->sh_info); + Result = offset + reinterpret_cast(base() + secAddr->sh_offset); + return object_error::success; +} + +template +error_code ELFObjectFile + ::getRelocationType(DataRefImpl Rel, + uint32_t &Result) const { + const Elf_Shdr *sec = RelocationTableSections[Rel.d.b]; + switch (sec->sh_type) { + default : + report_fatal_error("Invalid section type in Rel!"); + case ELF::SHT_REL : { + Result = getRel(Rel)->getType(); + break; + } + case ELF::SHT_RELA : { + Result = getRela(Rel)->getType(); + break; + } + } + return object_error::success; +} + +template +error_code ELFObjectFile + ::getRelocationAdditionalInfo(DataRefImpl Rel, + int64_t &Result) const { + const Elf_Shdr *sec = RelocationTableSections[Rel.d.b]; + switch (sec->sh_type) { + default : + report_fatal_error("Invalid section type in Rel!"); + case ELF::SHT_REL : { + Result = 0; + return object_error::success; + } + case ELF::SHT_RELA : { + Result = getRela(Rel)->r_addend; + return object_error::success; + } + } +} + + + template ELFObjectFile::ELFObjectFile(MemoryBuffer *Object , error_code &ec) @@ -529,13 +744,17 @@ ELFObjectFile::ELFObjectFile(MemoryBuffer *Object // To find the symbol tables we walk the section table to find SHT_STMTAB. - for (const char *i = reinterpret_cast(SectionHeaderTable), - *e = i + Header->e_shnum * Header->e_shentsize; - i != e; i += Header->e_shentsize) { - const Elf_Shdr *sh = reinterpret_cast(i); + const Elf_Shdr* sh = + reinterpret_cast(SectionHeaderTable); + for (unsigned i = 0; i < Header->e_shnum; ++i) { if (sh->sh_type == ELF::SHT_SYMTAB) { + SymbolTableSectionsIndexMap[i] = SymbolTableSections.size(); SymbolTableSections.push_back(sh); } + if (sh->sh_type == ELF::SHT_REL || sh->sh_type == ELF::SHT_RELA) { + RelocationTableSections.push_back(sh); + } + ++sh; } // Get string table sections. @@ -614,6 +833,31 @@ ObjectFile::section_iterator ELFObjectFile return section_iterator(SectionRef(ret, this)); } +template +ObjectFile::relocation_iterator ELFObjectFile + ::begin_relocations() const { + DataRefImpl RelData; + memset(&RelData, 0, sizeof(RelData)); + if (RelocationTableSections.size() == 0) { + RelData.d.a = std::numeric_limits::max(); + RelData.d.b = std::numeric_limits::max(); + } else { + RelData.d.a = 0; + RelData.d.b = 0; + } + return relocation_iterator(RelocationRef(RelData, this)); +} + +template +ObjectFile::relocation_iterator ELFObjectFile + ::end_relocations() const { + DataRefImpl RelData; + memset(&RelData, 0, sizeof(RelData)); + RelData.d.a = std::numeric_limits::max(); + RelData.d.b = std::numeric_limits::max(); + return relocation_iterator(RelocationRef(RelData, this)); +} + template uint8_t ELFObjectFile::getBytesInAddress() const { return is64Bits ? 8 : 4; @@ -629,6 +873,8 @@ StringRef ELFObjectFile return "ELF32-i386"; case ELF::EM_X86_64: return "ELF32-x86-64"; + case ELF::EM_ARM: + return "ELF32-arm"; default: return "ELF32-unknown"; } @@ -654,19 +900,41 @@ unsigned ELFObjectFile::getArch() const { return Triple::x86; case ELF::EM_X86_64: return Triple::x86_64; + case ELF::EM_ARM: + return Triple::arm; default: return Triple::UnknownArch; } } template -const typename ELFObjectFile::Elf_Sym * -ELFObjectFile::getSymbol(DataRefImpl Symb) const { - const Elf_Shdr *sec = SymbolTableSections[Symb.d.b]; - return reinterpret_cast( +template +inline const T * +ELFObjectFile::getEntry(DataRefImpl Entry, + Sections_t Sections) const { + const Elf_Shdr *sec = Sections[Entry.d.b]; + return reinterpret_cast( base() + sec->sh_offset - + (Symb.d.a * sec->sh_entsize)); + + (Entry.d.a * sec->sh_entsize)); +} + +template +const typename ELFObjectFile::Elf_Sym * +ELFObjectFile::getSymbol(DataRefImpl Symb) const { + return getEntry(Symb, SymbolTableSections); +} + +template +const typename ELFObjectFile::Elf_Rel * +ELFObjectFile::getRel(DataRefImpl Rel) const { + return getEntry(Rel, RelocationTableSections); +} + +template +const typename ELFObjectFile::Elf_Rela * +ELFObjectFile::getRela(DataRefImpl Rela) const { + return getEntry(Rela, RelocationTableSections); } template diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index 26a6e136d75..ce202cfe327 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -18,6 +18,7 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MachO.h" +#include "llvm/ADT/SmallVector.h" #include #include @@ -32,15 +33,14 @@ typedef MachOObject::LoadCommandInfo LoadCommandInfo; class MachOObjectFile : public ObjectFile { public: - MachOObjectFile(MemoryBuffer *Object, MachOObject *MOO, error_code &ec) - : ObjectFile(Binary::isMachO, Object, ec), - MachOObj(MOO), - RegisteredStringTable(std::numeric_limits::max()) {} + MachOObjectFile(MemoryBuffer *Object, MachOObject *MOO, error_code &ec); virtual symbol_iterator begin_symbols() const; virtual symbol_iterator end_symbols() const; virtual section_iterator begin_sections() const; virtual section_iterator end_sections() const; + virtual relocation_iterator begin_relocations() const; + virtual relocation_iterator end_relocations() const; virtual uint8_t getBytesInAddress() const; virtual StringRef getFileFormatName() const; @@ -63,9 +63,22 @@ protected: virtual error_code sectionContainsSymbol(DataRefImpl DRI, DataRefImpl S, bool &Result) const; + virtual error_code getRelocationNext(DataRefImpl Rel, + RelocationRef &Res) const; + virtual error_code getRelocationAddress(DataRefImpl Rel, + uint64_t &Res) const; + virtual error_code getRelocationSymbol(DataRefImpl Rel, + SymbolRef &Res) const; + virtual error_code getRelocationType(DataRefImpl Rel, + uint32_t &Res) const; + virtual error_code getRelocationAdditionalInfo(DataRefImpl Rel, + int64_t &Res) const; private: MachOObject *MachOObj; mutable uint32_t RegisteredStringTable; + typedef SmallVector SectionList; + SectionList Sections; + void moveToNextSection(DataRefImpl &DRI) const; void getSymbolTableEntry(DataRefImpl DRI, @@ -76,8 +89,35 @@ private: void getSection(DataRefImpl DRI, InMemoryStruct &Res) const; void getSection64(DataRefImpl DRI, InMemoryStruct &Res) const; + void getRelocation(DataRefImpl Rel, + InMemoryStruct &Res) const; }; +MachOObjectFile::MachOObjectFile(MemoryBuffer *Object, MachOObject *MOO, + error_code &ec) + : ObjectFile(Binary::isMachO, Object, ec), + MachOObj(MOO), + RegisteredStringTable(std::numeric_limits::max()) { + DataRefImpl DRI; + DRI.d.a = DRI.d.b = 0; + moveToNextSection(DRI); + uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; + while (DRI.d.a < LoadCommandCount) { + Sections.push_back(DRI); + uint64_t Addr; + uint64_t Size; + StringRef Name; + getSectionAddress(DRI, Addr); + getSectionSize(DRI, Size); + getSectionName(DRI, Name); + InMemoryStruct Sect; + getSection(DRI, Sect); + DRI.d.b++; + moveToNextSection(DRI); + } +} + + ObjectFile *ObjectFile::createMachOObjectFile(MemoryBuffer *Buffer) { error_code ec; std::string Err; @@ -414,6 +454,125 @@ ObjectFile::section_iterator MachOObjectFile::end_sections() const { return section_iterator(SectionRef(DRI, this)); } +/*===-- Relocations -------------------------------------------------------===*/ + +void MachOObjectFile:: +getRelocation(DataRefImpl Rel, + InMemoryStruct &Res) const { + uint32_t relOffset; + if (MachOObj->is64Bit()) { + InMemoryStruct Sect; + getSection64(Sections[Rel.d.b], Sect); + relOffset = Sect->RelocationTableOffset; + } else { + InMemoryStruct Sect; + getSection(Sections[Rel.d.b], Sect); + relOffset = Sect->RelocationTableOffset; + } + MachOObj->ReadRelocationEntry(relOffset, Rel.d.a, Res); +} +error_code MachOObjectFile::getRelocationNext(DataRefImpl Rel, + RelocationRef &Res) const { + ++Rel.d.a; + while (Rel.d.b < Sections.size()) { + unsigned relocationCount; + if (MachOObj->is64Bit()) { + InMemoryStruct Sect; + getSection64(Sections[Rel.d.b], Sect); + relocationCount = Sect->NumRelocationTableEntries; + } else { + InMemoryStruct Sect; + getSection(Sections[Rel.d.b], Sect); + relocationCount = Sect->NumRelocationTableEntries; + } + if (Rel.d.a < relocationCount) + break; + + Rel.d.a = 0; + ++Rel.d.b; + } + Res = RelocationRef(Rel, this); + return object_error::success; +} +error_code MachOObjectFile::getRelocationAddress(DataRefImpl Rel, + uint64_t &Res) const { + const uint8_t* sectAddress = base(); + if (MachOObj->is64Bit()) { + InMemoryStruct Sect; + getSection64(Sections[Rel.d.b], Sect); + sectAddress += Sect->Offset; + } else { + InMemoryStruct Sect; + getSection(Sections[Rel.d.b], Sect); + sectAddress += Sect->Offset; + } + InMemoryStruct RE; + getRelocation(Rel, RE); + Res = reinterpret_cast(sectAddress + RE->Word0); + return object_error::success; +} +error_code MachOObjectFile::getRelocationSymbol(DataRefImpl Rel, + SymbolRef &Res) const { + InMemoryStruct RE; + getRelocation(Rel, RE); + uint32_t SymbolIdx = RE->Word1 & 0xffffff; + bool isExtern = (RE->Word1 >> 27) & 1; + + DataRefImpl Sym; + Sym.d.a = Sym.d.b = 0; + moveToNextSymbol(Sym); + uint32_t NumLoadCommands = MachOObj->getHeader().NumLoadCommands; + if (isExtern) { + for (unsigned i = 0; i < SymbolIdx; i++) { + Sym.d.b++; + moveToNextSymbol(Sym); + assert(Sym.d.a < NumLoadCommands && + "Relocation symbol index out of range!"); + } + } + Res = SymbolRef(Sym, this); + return object_error::success; +} +error_code MachOObjectFile::getRelocationType(DataRefImpl Rel, + uint32_t &Res) const { + InMemoryStruct RE; + getRelocation(Rel, RE); + Res = RE->Word1; + return object_error::success; +} +error_code MachOObjectFile::getRelocationAdditionalInfo(DataRefImpl Rel, + int64_t &Res) const { + InMemoryStruct RE; + getRelocation(Rel, RE); + bool isExtern = (RE->Word1 >> 27) & 1; + Res = 0; + if (!isExtern) { + const uint8_t* sectAddress = base(); + if (MachOObj->is64Bit()) { + InMemoryStruct Sect; + getSection64(Sections[Rel.d.b], Sect); + sectAddress += Sect->Offset; + } else { + InMemoryStruct Sect; + getSection(Sections[Rel.d.b], Sect); + sectAddress += Sect->Offset; + } + Res = reinterpret_cast(sectAddress); + } + return object_error::success; +} +ObjectFile::relocation_iterator MachOObjectFile::begin_relocations() const { + DataRefImpl ret; + ret.d.a = ret.d.b = 0; + return relocation_iterator(RelocationRef(ret, this)); +} +ObjectFile::relocation_iterator MachOObjectFile::end_relocations() const { + DataRefImpl ret; + ret.d.a = 0; + ret.d.b = Sections.size(); + return relocation_iterator(RelocationRef(ret, this)); +} + /*===-- Miscellaneous -----------------------------------------------------===*/ uint8_t MachOObjectFile::getBytesInAddress() const {