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 3b0c548ffe15..cc271851e6b0 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));  } | 
