blob: 92fb46e8e93515befbb5bae3b433e4d086df075b [file] [log] [blame]
//===- ELF.h - ELF object file implementation -------------------*- C++ -*-===//
// The LLVM Compiler Infrastructure
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// This file declares the ELFFile template class.
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Object/ELFTypes.h"
#include "llvm/Object/Error.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <utility>
namespace llvm {
namespace object {
StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type);
StringRef getELFSectionTypeName(uint32_t Machine, uint32_t Type);
// Subclasses of ELFFile may need this for template instantiation
inline std::pair<unsigned char, unsigned char>
getElfArchType(StringRef Object) {
if (Object.size() < ELF::EI_NIDENT)
return std::make_pair((uint8_t)ELF::ELFCLASSNONE,
return std::make_pair((uint8_t)Object[ELF::EI_CLASS],
static inline Error createError(StringRef Err) {
return make_error<StringError>(Err, object_error::parse_failed);
template <class ELFT>
class ELFFile {
using uintX_t = typename ELFT::uint;
using Elf_Ehdr = typename ELFT::Ehdr;
using Elf_Shdr = typename ELFT::Shdr;
using Elf_Sym = typename ELFT::Sym;
using Elf_Dyn = typename ELFT::Dyn;
using Elf_Phdr = typename ELFT::Phdr;
using Elf_Rel = typename ELFT::Rel;
using Elf_Rela = typename ELFT::Rela;
using Elf_Verdef = typename ELFT::Verdef;
using Elf_Verdaux = typename ELFT::Verdaux;
using Elf_Verneed = typename ELFT::Verneed;
using Elf_Vernaux = typename ELFT::Vernaux;
using Elf_Versym = typename ELFT::Versym;
using Elf_Hash = typename ELFT::Hash;
using Elf_GnuHash = typename ELFT::GnuHash;
using Elf_Dyn_Range = typename ELFT::DynRange;
using Elf_Shdr_Range = typename ELFT::ShdrRange;
using Elf_Sym_Range = typename ELFT::SymRange;
using Elf_Rel_Range = typename ELFT::RelRange;
using Elf_Rela_Range = typename ELFT::RelaRange;
using Elf_Phdr_Range = typename ELFT::PhdrRange;
const uint8_t *base() const {
return reinterpret_cast<const uint8_t *>(;
size_t getBufSize() const { return Buf.size(); }
StringRef Buf;
ELFFile(StringRef Object);
const Elf_Ehdr *getHeader() const {
return reinterpret_cast<const Elf_Ehdr *>(base());
template <typename T>
Expected<const T *> getEntry(uint32_t Section, uint32_t Entry) const;
template <typename T>
Expected<const T *> getEntry(const Elf_Shdr *Section, uint32_t Entry) const;
Expected<StringRef> getStringTable(const Elf_Shdr *Section) const;
Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section) const;
Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section,
Elf_Shdr_Range Sections) const;
Expected<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section) const;
Expected<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section,
Elf_Shdr_Range Sections) const;
StringRef getRelocationTypeName(uint32_t Type) const;
void getRelocationTypeName(uint32_t Type,
SmallVectorImpl<char> &Result) const;
/// \brief Get the symbol for a given relocation.
Expected<const Elf_Sym *> getRelocationSymbol(const Elf_Rel *Rel,
const Elf_Shdr *SymTab) const;
static Expected<ELFFile> create(StringRef Object);
bool isMipsELF64() const {
return getHeader()->e_machine == ELF::EM_MIPS &&
getHeader()->getFileClass() == ELF::ELFCLASS64;
bool isMips64EL() const {
return isMipsELF64() &&
getHeader()->getDataEncoding() == ELF::ELFDATA2LSB;
Expected<Elf_Shdr_Range> sections() const;
Expected<Elf_Sym_Range> symbols(const Elf_Shdr *Sec) const {
if (!Sec)
return makeArrayRef<Elf_Sym>(nullptr, nullptr);
return getSectionContentsAsArray<Elf_Sym>(Sec);
Expected<Elf_Rela_Range> relas(const Elf_Shdr *Sec) const {
return getSectionContentsAsArray<Elf_Rela>(Sec);
Expected<Elf_Rel_Range> rels(const Elf_Shdr *Sec) const {
return getSectionContentsAsArray<Elf_Rel>(Sec);
Expected<std::vector<Elf_Rela>> android_relas(const Elf_Shdr *Sec) const;
/// \brief Iterate over program header table.
Expected<Elf_Phdr_Range> program_headers() const {
if (getHeader()->e_phnum && getHeader()->e_phentsize != sizeof(Elf_Phdr))
return createError("invalid e_phentsize");
if (getHeader()->e_phoff +
(getHeader()->e_phnum * getHeader()->e_phentsize) >
return createError("program headers longer than binary");
auto *Begin =
reinterpret_cast<const Elf_Phdr *>(base() + getHeader()->e_phoff);
return makeArrayRef(Begin, Begin + getHeader()->e_phnum);
Expected<StringRef> getSectionStringTable(Elf_Shdr_Range Sections) const;
Expected<uint32_t> getSectionIndex(const Elf_Sym *Sym, Elf_Sym_Range Syms,
ArrayRef<Elf_Word> ShndxTable) const;
Expected<const Elf_Shdr *> getSection(const Elf_Sym *Sym,
const Elf_Shdr *SymTab,
ArrayRef<Elf_Word> ShndxTable) const;
Expected<const Elf_Shdr *> getSection(const Elf_Sym *Sym,
Elf_Sym_Range Symtab,
ArrayRef<Elf_Word> ShndxTable) const;
Expected<const Elf_Shdr *> getSection(uint32_t Index) const;
Expected<const Elf_Sym *> getSymbol(const Elf_Shdr *Sec,
uint32_t Index) const;
Expected<StringRef> getSectionName(const Elf_Shdr *Section) const;
Expected<StringRef> getSectionName(const Elf_Shdr *Section,
StringRef DotShstrtab) const;
template <typename T>
Expected<ArrayRef<T>> getSectionContentsAsArray(const Elf_Shdr *Sec) const;
Expected<ArrayRef<uint8_t>> getSectionContents(const Elf_Shdr *Sec) const;
using ELF32LEFile = ELFFile<ELFType<support::little, false>>;
using ELF64LEFile = ELFFile<ELFType<support::little, true>>;
using ELF32BEFile = ELFFile<ELFType<support::big, false>>;
using ELF64BEFile = ELFFile<ELFType<support::big, true>>;
template <class ELFT>
inline Expected<const typename ELFT::Shdr *>
getSection(typename ELFT::ShdrRange Sections, uint32_t Index) {
if (Index >= Sections.size())
return createError("invalid section index");
return &Sections[Index];
template <class ELFT>
inline Expected<uint32_t>
getExtendedSymbolTableIndex(const typename ELFT::Sym *Sym,
const typename ELFT::Sym *FirstSym,
ArrayRef<typename ELFT::Word> ShndxTable) {
assert(Sym->st_shndx == ELF::SHN_XINDEX);
unsigned Index = Sym - FirstSym;
if (Index >= ShndxTable.size())
return createError("index past the end of the symbol table");
// The size of the table was checked in getSHNDXTable.
return ShndxTable[Index];
template <class ELFT>
inline Expected<const typename ELFT::Sym *>
getSymbol(typename ELFT::SymRange Symbols, uint32_t Index) {
if (Index >= Symbols.size())
return createError("invalid symbol index");
return &Symbols[Index];
template <class ELFT>
template <typename T>
ELFFile<ELFT>::getSectionContentsAsArray(const Elf_Shdr *Sec) const {
if (Sec->sh_entsize != sizeof(T) && sizeof(T) != 1)
return createError("invalid sh_entsize");
uintX_t Offset = Sec->sh_offset;
uintX_t Size = Sec->sh_size;
if (Size % sizeof(T))
return createError("size is not a multiple of sh_entsize");
if ((std::numeric_limits<uintX_t>::max() - Offset < Size) ||
Offset + Size > Buf.size())
return createError("invalid section offset");
const T *Start = reinterpret_cast<const T *>(base() + Offset);
return makeArrayRef(Start, Size / sizeof(T));
template <class ELFT>
template <typename T>
Expected<const T *> ELFFile<ELFT>::getEntry(uint32_t Section,
uint32_t Entry) const {
auto SecOrErr = getSection(Section);
if (!SecOrErr)
return SecOrErr.takeError();
return getEntry<T>(*SecOrErr, Entry);
template <class ELFT>
template <typename T>
Expected<const T *> ELFFile<ELFT>::getEntry(const Elf_Shdr *Section,
uint32_t Entry) const {
if (sizeof(T) != Section->sh_entsize)
return createError("invalid sh_entsize");
size_t Pos = Section->sh_offset + Entry * sizeof(T);
if (Pos + sizeof(T) > Buf.size())
return createError("invalid section offset");
return reinterpret_cast<const T *>(base() + Pos);
/// This function returns the hash value for a symbol in the .dynsym section
/// Name of the API remains consistent as specified in the libelf
/// REF :
inline unsigned hashSysV(StringRef SymbolName) {
unsigned h = 0, g;
for (char C : SymbolName) {
h = (h << 4) + C;
g = h & 0xf0000000L;
if (g != 0)
h ^= g >> 24;
h &= ~g;
return h;
} // end namespace object
} // end namespace llvm