diff options
Diffstat (limited to 'include/llvm/Object/ELF.h')
-rw-r--r-- | include/llvm/Object/ELF.h | 101 |
1 files changed, 71 insertions, 30 deletions
diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index 3b0c548..cc27185 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -16,6 +16,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntervalMap.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" @@ -139,6 +140,7 @@ public: typedef Elf_Verneed_Impl<ELFT> Elf_Verneed; typedef Elf_Vernaux_Impl<ELFT> Elf_Vernaux; typedef Elf_Versym_Impl<ELFT> Elf_Versym; + typedef Elf_Hash_Impl<ELFT> Elf_Hash; typedef ELFEntityIterator<const Elf_Dyn> Elf_Dyn_Iter; typedef iterator_range<Elf_Dyn_Iter> Elf_Dyn_Range; typedef ELFEntityIterator<const Elf_Rela> Elf_Rela_Iter; @@ -174,8 +176,8 @@ private: StringRef DotShstrtab; // Section header string table. StringRef DotStrtab; // Symbol header string table. const Elf_Shdr *dot_symtab_sec = nullptr; // Symbol table section. - StringRef DynSymStrTab; // Dynnamic symbol string table. const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section. + const Elf_Hash *HashTable = nullptr; const Elf_Shdr *SymbolTableSectionHeaderIndex = nullptr; DenseMap<const Elf_Sym *, ELF::Elf64_Word> ExtendedSymbolTable; @@ -197,6 +199,7 @@ private: DynRegionInfo DynamicRegion; DynRegionInfo DynHashRegion; + DynRegionInfo DynStrRegion; DynRegionInfo DynRelaRegion; // Pointer to SONAME entry in dynamic string table @@ -229,6 +232,8 @@ private: void LoadVersionNeeds(const Elf_Shdr *ec) const; void LoadVersionMap() const; + void scanDynamicTable(); + public: template<typename T> const T *getEntry(uint32_t Section, uint32_t Entry) const; @@ -237,6 +242,7 @@ public: const Elf_Shdr *getDotSymtabSec() const { return dot_symtab_sec; } const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; } + const Elf_Hash *getHashTable() const { return HashTable; } ErrorOr<StringRef> getStringTable(const Elf_Shdr *Section) const; const char *getDynamicString(uintX_t Offset) const; @@ -578,8 +584,10 @@ ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &EC) Header = reinterpret_cast<const Elf_Ehdr *>(base()); - if (Header->e_shoff == 0) + if (Header->e_shoff == 0) { + scanDynamicTable(); return; + } const uint64_t SectionTableOffset = Header->e_shoff; @@ -604,6 +612,13 @@ ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &EC) for (const Elf_Shdr &Sec : sections()) { switch (Sec.sh_type) { + case ELF::SHT_HASH: + if (HashTable) { + EC = object_error::parse_failed; + return; + } + HashTable = reinterpret_cast<const Elf_Hash *>(base() + Sec.sh_offset); + break; case ELF::SHT_SYMTAB_SHNDX: if (SymbolTableSectionHeaderIndex) { // More than one .symtab_shndx! @@ -640,7 +655,9 @@ ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &EC) ErrorOr<StringRef> SymtabOrErr = getStringTable(*SectionOrErr); if ((EC = SymtabOrErr.getError())) return; - DynSymStrTab = *SymtabOrErr; + DynStrRegion.Addr = SymtabOrErr->data(); + DynStrRegion.Size = SymtabOrErr->size(); + DynStrRegion.EntSize = 1; break; } case ELF::SHT_DYNAMIC: @@ -701,7 +718,23 @@ ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &EC) } } - // Scan program headers. + scanDynamicTable(); + + EC = std::error_code(); +} + +template <class ELFT> +void ELFFile<ELFT>::scanDynamicTable() { + // Build load-address to file-offset map. + typedef IntervalMap< + uintX_t, uintptr_t, + IntervalMapImpl::NodeSizer<uintX_t, uintptr_t>::LeafSize, + IntervalMapHalfOpenInfo<uintX_t>> LoadMapT; + typename LoadMapT::Allocator Alloc; + // Allocate the IntervalMap on the heap to work around MSVC bug where the + // stack doesn't get realigned despite LoadMap having alignment 8 (PR24113). + std::unique_ptr<LoadMapT> LoadMap(new LoadMapT(Alloc)); + for (Elf_Phdr_Iter PhdrI = program_header_begin(), PhdrE = program_header_end(); PhdrI != PhdrE; ++PhdrI) { @@ -709,34 +742,44 @@ ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &EC) DynamicRegion.Addr = base() + PhdrI->p_offset; DynamicRegion.Size = PhdrI->p_filesz; DynamicRegion.EntSize = sizeof(Elf_Dyn); - break; + continue; } + if (PhdrI->p_type != ELF::PT_LOAD) + continue; + if (PhdrI->p_filesz == 0) + continue; + LoadMap->insert(PhdrI->p_vaddr, PhdrI->p_vaddr + PhdrI->p_filesz, + PhdrI->p_offset); } - // Scan dynamic table. + auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { + auto I = LoadMap->find(VAddr); + if (I == LoadMap->end()) + return nullptr; + return this->base() + I.value() + (VAddr - I.start()); + }; + for (Elf_Dyn_Iter DynI = dynamic_table_begin(), DynE = dynamic_table_end(); DynI != DynE; ++DynI) { switch (DynI->d_tag) { - case ELF::DT_RELA: { - uint64_t VBase = 0; - const uint8_t *FBase = nullptr; - for (Elf_Phdr_Iter PhdrI = program_header_begin(), - PhdrE = program_header_end(); - PhdrI != PhdrE; ++PhdrI) { - if (PhdrI->p_type != ELF::PT_LOAD) - continue; - if (DynI->getPtr() >= PhdrI->p_vaddr && - DynI->getPtr() < PhdrI->p_vaddr + PhdrI->p_memsz) { - VBase = PhdrI->p_vaddr; - FBase = base() + PhdrI->p_offset; - break; - } - } - if (!VBase) - return; - DynRelaRegion.Addr = FBase + DynI->getPtr() - VBase; + case ELF::DT_HASH: + if (HashTable) + continue; + HashTable = + reinterpret_cast<const Elf_Hash *>(toMappedAddr(DynI->getPtr())); + break; + case ELF::DT_STRTAB: + if (!DynStrRegion.Addr) + DynStrRegion.Addr = toMappedAddr(DynI->getPtr()); + break; + case ELF::DT_STRSZ: + if (!DynStrRegion.Size) + DynStrRegion.Size = DynI->getVal(); + break; + case ELF::DT_RELA: + if (!DynRelaRegion.Addr) + DynRelaRegion.Addr = toMappedAddr(DynI->getPtr()); break; - } case ELF::DT_RELASZ: DynRelaRegion.Size = DynI->getVal(); break; @@ -744,8 +787,6 @@ ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &EC) DynRelaRegion.EntSize = DynI->getVal(); } } - - EC = std::error_code(); } template <class ELFT> @@ -868,9 +909,9 @@ ELFFile<ELFT>::getStringTable(const Elf_Shdr *Section) const { template <class ELFT> const char *ELFFile<ELFT>::getDynamicString(uintX_t Offset) const { - if (!DotDynSymSec || Offset >= DynSymStrTab.size()) + if (Offset >= DynStrRegion.Size) return nullptr; - return (const char *)DynSymStrTab.begin() + Offset; + return (const char *)DynStrRegion.Addr + Offset; } template <class ELFT> @@ -983,7 +1024,7 @@ ErrorOr<StringRef> ELFFile<ELFT>::getSymbolVersion(const Elf_Shdr *section, IsDefault = false; } - if (name_offset >= DynSymStrTab.size()) + if (name_offset >= DynStrRegion.Size) return object_error::parse_failed; return StringRef(getDynamicString(name_offset)); } |