diff options
author | Alon Zakai <azakai@google.com> | 2019-12-19 09:04:08 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-12-19 09:04:08 -0800 |
commit | 4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6 (patch) | |
tree | 91bffc2d47b1fe4bba01e7ada77006ef340bd138 /third_party/llvm-project/include/llvm/Object/ELFObjectFile.h | |
parent | 0048f5b004ddf50e750aa335d0be314a73852058 (diff) | |
download | binaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.tar.gz binaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.tar.bz2 binaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.zip |
DWARF parsing and writing support using LLVM (#2520)
This imports LLVM code for DWARF handling. That code has the
Apache 2 license like us. It's also the same code used to
emit DWARF in the common toolchain, so it seems like a safe choice.
This adds two passes: --dwarfdump which runs the same code LLVM
runs for llvm-dwarfdump. This shows we can parse it ok, and will
be useful for debugging. And --dwarfupdate writes out the DWARF
sections (unchanged from what we read, so it just roundtrips - for
updating we need #2515).
This puts LLVM in thirdparty which is added here.
All the LLVM code is behind USE_LLVM_DWARF, which is on
by default, but off in JS for now, as it increases code size by 20%.
This current approach imports the LLVM files directly. This is not
how they are intended to be used, so it required a bunch of
local changes - more than I expected actually, for the platform-specific
stuff. For now this seems to work, so it may be good enough, but
in the long term we may want to switch to linking against libllvm.
A downside to doing that is that binaryen users would need to
have an LLVM build, and even in the waterfall builds we'd have a
problem - while we ship LLVM there anyhow, we constantly update
it, which means that binaryen would need to be on latest llvm all
the time too (which otherwise, given DWARF is quite stable, we
might not need to constantly update).
An even larger issue is that as I did this work I learned about how
DWARF works in LLVM, and while the reading code is easy to
reuse, the writing code is trickier. The main code path is heavily
integrated with the MC layer, which we don't have - we might want
to create a "fake MC layer" for that, but it sounds hard. Instead,
there is the YAML path which is used mostly for testing, and which
can convert DWARF to and from YAML and from binary. Using
the non-YAML parts there, we can convert binary DWARF to
the YAML layer's nice Info data, then convert that to binary. This
works, however, this is not the path LLVM uses normally, and it
supports only some basic DWARF sections - I had to add ranges
support, in fact. So if we need more complex things, we may end
up needing to use the MC layer approach, or consider some other
DWARF library. However, hopefully that should not affect the core
binaryen code which just calls a library for DWARF stuff.
Helps #2400
Diffstat (limited to 'third_party/llvm-project/include/llvm/Object/ELFObjectFile.h')
-rw-r--r-- | third_party/llvm-project/include/llvm/Object/ELFObjectFile.h | 1214 |
1 files changed, 1214 insertions, 0 deletions
diff --git a/third_party/llvm-project/include/llvm/Object/ELFObjectFile.h b/third_party/llvm-project/include/llvm/Object/ELFObjectFile.h new file mode 100644 index 000000000..8a68e4947 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/ELFObjectFile.h @@ -0,0 +1,1214 @@ +//===- ELFObjectFile.h - ELF object file implementation ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the ELFObjectFile template class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_ELFOBJECTFILE_H +#define LLVM_OBJECT_ELFOBJECTFILE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/ELF.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Object/Error.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/ARMAttributeParser.h" +#include "llvm/Support/ARMBuildAttributes.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include <cassert> +#include <cstdint> +#include <system_error> + +namespace llvm { +namespace object { + +constexpr int NumElfSymbolTypes = 16; +extern const llvm::EnumEntry<unsigned> ElfSymbolTypes[NumElfSymbolTypes]; + +class elf_symbol_iterator; + +class ELFObjectFileBase : public ObjectFile { + friend class ELFRelocationRef; + friend class ELFSectionRef; + friend class ELFSymbolRef; + +protected: + ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source); + + virtual uint64_t getSymbolSize(DataRefImpl Symb) const = 0; + virtual uint8_t getSymbolBinding(DataRefImpl Symb) const = 0; + virtual uint8_t getSymbolOther(DataRefImpl Symb) const = 0; + virtual uint8_t getSymbolELFType(DataRefImpl Symb) const = 0; + + virtual uint32_t getSectionType(DataRefImpl Sec) const = 0; + virtual uint64_t getSectionFlags(DataRefImpl Sec) const = 0; + virtual uint64_t getSectionOffset(DataRefImpl Sec) const = 0; + + virtual Expected<int64_t> getRelocationAddend(DataRefImpl Rel) const = 0; + virtual Error getBuildAttributes(ARMAttributeParser &Attributes) const = 0; + +public: + using elf_symbol_iterator_range = iterator_range<elf_symbol_iterator>; + + virtual elf_symbol_iterator_range getDynamicSymbolIterators() const = 0; + + /// Returns platform-specific object flags, if any. + virtual unsigned getPlatformFlags() const = 0; + + elf_symbol_iterator_range symbols() const; + + static bool classof(const Binary *v) { return v->isELF(); } + + SubtargetFeatures getFeatures() const override; + + SubtargetFeatures getMIPSFeatures() const; + + SubtargetFeatures getARMFeatures() const; + + SubtargetFeatures getRISCVFeatures() const; + + void setARMSubArch(Triple &TheTriple) const override; + + virtual uint16_t getEType() const = 0; + + virtual uint16_t getEMachine() const = 0; + + std::vector<std::pair<DataRefImpl, uint64_t>> getPltAddresses() const; +}; + +class ELFSectionRef : public SectionRef { +public: + ELFSectionRef(const SectionRef &B) : SectionRef(B) { + assert(isa<ELFObjectFileBase>(SectionRef::getObject())); + } + + const ELFObjectFileBase *getObject() const { + return cast<ELFObjectFileBase>(SectionRef::getObject()); + } + + uint32_t getType() const { + return getObject()->getSectionType(getRawDataRefImpl()); + } + + uint64_t getFlags() const { + return getObject()->getSectionFlags(getRawDataRefImpl()); + } + + uint64_t getOffset() const { + return getObject()->getSectionOffset(getRawDataRefImpl()); + } +}; + +class elf_section_iterator : public section_iterator { +public: + elf_section_iterator(const section_iterator &B) : section_iterator(B) { + assert(isa<ELFObjectFileBase>(B->getObject())); + } + + const ELFSectionRef *operator->() const { + return static_cast<const ELFSectionRef *>(section_iterator::operator->()); + } + + const ELFSectionRef &operator*() const { + return static_cast<const ELFSectionRef &>(section_iterator::operator*()); + } +}; + +class ELFSymbolRef : public SymbolRef { +public: + ELFSymbolRef(const SymbolRef &B) : SymbolRef(B) { + assert(isa<ELFObjectFileBase>(SymbolRef::getObject())); + } + + const ELFObjectFileBase *getObject() const { + return cast<ELFObjectFileBase>(BasicSymbolRef::getObject()); + } + + uint64_t getSize() const { + return getObject()->getSymbolSize(getRawDataRefImpl()); + } + + uint8_t getBinding() const { + return getObject()->getSymbolBinding(getRawDataRefImpl()); + } + + uint8_t getOther() const { + return getObject()->getSymbolOther(getRawDataRefImpl()); + } + + uint8_t getELFType() const { + return getObject()->getSymbolELFType(getRawDataRefImpl()); + } + + StringRef getELFTypeName() const { + uint8_t Type = getELFType(); + for (auto &EE : ElfSymbolTypes) { + if (EE.Value == Type) { + return EE.AltName; + } + } + return ""; + } +}; + +class elf_symbol_iterator : public symbol_iterator { +public: + elf_symbol_iterator(const basic_symbol_iterator &B) + : symbol_iterator(SymbolRef(B->getRawDataRefImpl(), + cast<ELFObjectFileBase>(B->getObject()))) {} + + const ELFSymbolRef *operator->() const { + return static_cast<const ELFSymbolRef *>(symbol_iterator::operator->()); + } + + const ELFSymbolRef &operator*() const { + return static_cast<const ELFSymbolRef &>(symbol_iterator::operator*()); + } +}; + +class ELFRelocationRef : public RelocationRef { +public: + ELFRelocationRef(const RelocationRef &B) : RelocationRef(B) { + assert(isa<ELFObjectFileBase>(RelocationRef::getObject())); + } + + const ELFObjectFileBase *getObject() const { + return cast<ELFObjectFileBase>(RelocationRef::getObject()); + } + + Expected<int64_t> getAddend() const { + return getObject()->getRelocationAddend(getRawDataRefImpl()); + } +}; + +class elf_relocation_iterator : public relocation_iterator { +public: + elf_relocation_iterator(const relocation_iterator &B) + : relocation_iterator(RelocationRef( + B->getRawDataRefImpl(), cast<ELFObjectFileBase>(B->getObject()))) {} + + const ELFRelocationRef *operator->() const { + return static_cast<const ELFRelocationRef *>( + relocation_iterator::operator->()); + } + + const ELFRelocationRef &operator*() const { + return static_cast<const ELFRelocationRef &>( + relocation_iterator::operator*()); + } +}; + +inline ELFObjectFileBase::elf_symbol_iterator_range +ELFObjectFileBase::symbols() const { + return elf_symbol_iterator_range(symbol_begin(), symbol_end()); +} + +template <class ELFT> class ELFObjectFile : public ELFObjectFileBase { + uint16_t getEMachine() const override; + uint16_t getEType() const override; + uint64_t getSymbolSize(DataRefImpl Sym) const override; + +public: + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + + using uintX_t = typename ELFT::uint; + + using Elf_Sym = typename ELFT::Sym; + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Ehdr = typename ELFT::Ehdr; + using Elf_Rel = typename ELFT::Rel; + using Elf_Rela = typename ELFT::Rela; + using Elf_Dyn = typename ELFT::Dyn; + + SectionRef toSectionRef(const Elf_Shdr *Sec) const { + return SectionRef(toDRI(Sec), this); + } + +private: + ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF, + const Elf_Shdr *DotDynSymSec, const Elf_Shdr *DotSymtabSec, + ArrayRef<Elf_Word> ShndxTable); + +protected: + ELFFile<ELFT> EF; + + const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section. + const Elf_Shdr *DotSymtabSec = nullptr; // Symbol table section. + ArrayRef<Elf_Word> ShndxTable; + + void moveSymbolNext(DataRefImpl &Symb) const override; + Expected<StringRef> getSymbolName(DataRefImpl Symb) const override; + Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; + uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; + uint32_t getSymbolAlignment(DataRefImpl Symb) const override; + uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; + uint32_t getSymbolFlags(DataRefImpl Symb) const override; + uint8_t getSymbolBinding(DataRefImpl Symb) const override; + uint8_t getSymbolOther(DataRefImpl Symb) const override; + uint8_t getSymbolELFType(DataRefImpl Symb) const override; + Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override; + Expected<section_iterator> getSymbolSection(const Elf_Sym *Symb, + const Elf_Shdr *SymTab) const; + Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override; + + void moveSectionNext(DataRefImpl &Sec) const override; + Expected<StringRef> getSectionName(DataRefImpl Sec) const override; + uint64_t getSectionAddress(DataRefImpl Sec) const override; + uint64_t getSectionIndex(DataRefImpl Sec) const override; + uint64_t getSectionSize(DataRefImpl Sec) const override; + Expected<ArrayRef<uint8_t>> + getSectionContents(DataRefImpl Sec) const override; + uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; + bool isSectionText(DataRefImpl Sec) const override; + bool isSectionData(DataRefImpl Sec) const override; + bool isSectionBSS(DataRefImpl Sec) const override; + bool isSectionVirtual(DataRefImpl Sec) const override; + bool isBerkeleyText(DataRefImpl Sec) const override; + bool isBerkeleyData(DataRefImpl Sec) const override; + relocation_iterator section_rel_begin(DataRefImpl Sec) const override; + relocation_iterator section_rel_end(DataRefImpl Sec) const override; + std::vector<SectionRef> dynamic_relocation_sections() const override; + Expected<section_iterator> + getRelocatedSection(DataRefImpl Sec) const override; + + void moveRelocationNext(DataRefImpl &Rel) const override; + uint64_t getRelocationOffset(DataRefImpl Rel) const override; + symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override; + uint64_t getRelocationType(DataRefImpl Rel) const override; + void getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const override; + + uint32_t getSectionType(DataRefImpl Sec) const override; + uint64_t getSectionFlags(DataRefImpl Sec) const override; + uint64_t getSectionOffset(DataRefImpl Sec) const override; + StringRef getRelocationTypeName(uint32_t Type) const; + + /// Get the relocation section that contains \a Rel. + const Elf_Shdr *getRelSection(DataRefImpl Rel) const { + auto RelSecOrErr = EF.getSection(Rel.d.a); + if (!RelSecOrErr) + report_fatal_error(errorToErrorCode(RelSecOrErr.takeError()).message()); + return *RelSecOrErr; + } + + DataRefImpl toDRI(const Elf_Shdr *SymTable, unsigned SymbolNum) const { + DataRefImpl DRI; + if (!SymTable) { + DRI.d.a = 0; + DRI.d.b = 0; + return DRI; + } + assert(SymTable->sh_type == ELF::SHT_SYMTAB || + SymTable->sh_type == ELF::SHT_DYNSYM); + + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) { + DRI.d.a = 0; + DRI.d.b = 0; + return DRI; + } + uintptr_t SHT = reinterpret_cast<uintptr_t>((*SectionsOrErr).begin()); + unsigned SymTableIndex = + (reinterpret_cast<uintptr_t>(SymTable) - SHT) / sizeof(Elf_Shdr); + + DRI.d.a = SymTableIndex; + DRI.d.b = SymbolNum; + return DRI; + } + + const Elf_Shdr *toELFShdrIter(DataRefImpl Sec) const { + return reinterpret_cast<const Elf_Shdr *>(Sec.p); + } + + DataRefImpl toDRI(const Elf_Shdr *Sec) const { + DataRefImpl DRI; + DRI.p = reinterpret_cast<uintptr_t>(Sec); + return DRI; + } + + DataRefImpl toDRI(const Elf_Dyn *Dyn) const { + DataRefImpl DRI; + DRI.p = reinterpret_cast<uintptr_t>(Dyn); + return DRI; + } + + bool isExportedToOtherDSO(const Elf_Sym *ESym) const { + unsigned char Binding = ESym->getBinding(); + unsigned char Visibility = ESym->getVisibility(); + + // A symbol is exported if its binding is either GLOBAL or WEAK, and its + // visibility is either DEFAULT or PROTECTED. All other symbols are not + // exported. + return ( + (Binding == ELF::STB_GLOBAL || Binding == ELF::STB_WEAK || + Binding == ELF::STB_GNU_UNIQUE) && + (Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_PROTECTED)); + } + + Error getBuildAttributes(ARMAttributeParser &Attributes) const override { + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return SectionsOrErr.takeError(); + + for (const Elf_Shdr &Sec : *SectionsOrErr) { + if (Sec.sh_type == ELF::SHT_ARM_ATTRIBUTES) { + auto ErrorOrContents = EF.getSectionContents(&Sec); + if (!ErrorOrContents) + return ErrorOrContents.takeError(); + + auto Contents = ErrorOrContents.get(); + if (Contents[0] != ARMBuildAttrs::Format_Version || Contents.size() == 1) + return Error::success(); + + Attributes.Parse(Contents, ELFT::TargetEndianness == support::little); + break; + } + } + return Error::success(); + } + + // This flag is used for classof, to distinguish ELFObjectFile from + // its subclass. If more subclasses will be created, this flag will + // have to become an enum. + bool isDyldELFObject; + +public: + ELFObjectFile(ELFObjectFile<ELFT> &&Other); + static Expected<ELFObjectFile<ELFT>> create(MemoryBufferRef Object); + + const Elf_Rel *getRel(DataRefImpl Rel) const; + const Elf_Rela *getRela(DataRefImpl Rela) const; + + const Elf_Sym *getSymbol(DataRefImpl Sym) const { + auto Ret = EF.template getEntry<Elf_Sym>(Sym.d.a, Sym.d.b); + if (!Ret) + report_fatal_error(errorToErrorCode(Ret.takeError()).message()); + return *Ret; + } + + const Elf_Shdr *getSection(DataRefImpl Sec) const { + return reinterpret_cast<const Elf_Shdr *>(Sec.p); + } + + basic_symbol_iterator symbol_begin() const override; + basic_symbol_iterator symbol_end() const override; + + elf_symbol_iterator dynamic_symbol_begin() const; + elf_symbol_iterator dynamic_symbol_end() const; + + section_iterator section_begin() const override; + section_iterator section_end() const override; + + Expected<int64_t> getRelocationAddend(DataRefImpl Rel) const override; + + uint8_t getBytesInAddress() const override; + StringRef getFileFormatName() const override; + Triple::ArchType getArch() const override; + Expected<uint64_t> getStartAddress() const override; + + unsigned getPlatformFlags() const override { return EF.getHeader()->e_flags; } + + const ELFFile<ELFT> *getELFFile() const { return &EF; } + + bool isDyldType() const { return isDyldELFObject; } + static bool classof(const Binary *v) { + return v->getType() == getELFType(ELFT::TargetEndianness == support::little, + ELFT::Is64Bits); + } + + elf_symbol_iterator_range getDynamicSymbolIterators() const override; + + bool isRelocatableObject() const override; +}; + +using ELF32LEObjectFile = ELFObjectFile<ELF32LE>; +using ELF64LEObjectFile = ELFObjectFile<ELF64LE>; +using ELF32BEObjectFile = ELFObjectFile<ELF32BE>; +using ELF64BEObjectFile = ELFObjectFile<ELF64BE>; + +template <class ELFT> +void ELFObjectFile<ELFT>::moveSymbolNext(DataRefImpl &Sym) const { + ++Sym.d.b; +} + +template <class ELFT> +Expected<StringRef> ELFObjectFile<ELFT>::getSymbolName(DataRefImpl Sym) const { + const Elf_Sym *ESym = getSymbol(Sym); + auto SymTabOrErr = EF.getSection(Sym.d.a); + if (!SymTabOrErr) + return SymTabOrErr.takeError(); + const Elf_Shdr *SymTableSec = *SymTabOrErr; + auto StrTabOrErr = EF.getSection(SymTableSec->sh_link); + if (!StrTabOrErr) + return StrTabOrErr.takeError(); + const Elf_Shdr *StringTableSec = *StrTabOrErr; + auto SymStrTabOrErr = EF.getStringTable(StringTableSec); + if (!SymStrTabOrErr) + return SymStrTabOrErr.takeError(); + Expected<StringRef> Name = ESym->getName(*SymStrTabOrErr); + if (Name && !Name->empty()) + return Name; + + // If the symbol name is empty use the section name. + if (ESym->getType() == ELF::STT_SECTION) { + if (Expected<section_iterator> SecOrErr = getSymbolSection(Sym)) { + consumeError(Name.takeError()); + return (*SecOrErr)->getName(); + } + } + return Name; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSectionFlags(DataRefImpl Sec) const { + return getSection(Sec)->sh_flags; +} + +template <class ELFT> +uint32_t ELFObjectFile<ELFT>::getSectionType(DataRefImpl Sec) const { + return getSection(Sec)->sh_type; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSectionOffset(DataRefImpl Sec) const { + return getSection(Sec)->sh_offset; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSymbolValueImpl(DataRefImpl Symb) const { + const Elf_Sym *ESym = getSymbol(Symb); + uint64_t Ret = ESym->st_value; + if (ESym->st_shndx == ELF::SHN_ABS) + return Ret; + + const Elf_Ehdr *Header = EF.getHeader(); + // Clear the ARM/Thumb or microMIPS indicator flag. + if ((Header->e_machine == ELF::EM_ARM || Header->e_machine == ELF::EM_MIPS) && + ESym->getType() == ELF::STT_FUNC) + Ret &= ~1; + + return Ret; +} + +template <class ELFT> +Expected<uint64_t> +ELFObjectFile<ELFT>::getSymbolAddress(DataRefImpl Symb) const { + uint64_t Result = getSymbolValue(Symb); + const Elf_Sym *ESym = getSymbol(Symb); + switch (ESym->st_shndx) { + case ELF::SHN_COMMON: + case ELF::SHN_UNDEF: + case ELF::SHN_ABS: + return Result; + } + + const Elf_Ehdr *Header = EF.getHeader(); + auto SymTabOrErr = EF.getSection(Symb.d.a); + if (!SymTabOrErr) + return SymTabOrErr.takeError(); + const Elf_Shdr *SymTab = *SymTabOrErr; + + if (Header->e_type == ELF::ET_REL) { + auto SectionOrErr = EF.getSection(ESym, SymTab, ShndxTable); + if (!SectionOrErr) + return SectionOrErr.takeError(); + const Elf_Shdr *Section = *SectionOrErr; + if (Section) + Result += Section->sh_addr; + } + + return Result; +} + +template <class ELFT> +uint32_t ELFObjectFile<ELFT>::getSymbolAlignment(DataRefImpl Symb) const { + const Elf_Sym *Sym = getSymbol(Symb); + if (Sym->st_shndx == ELF::SHN_COMMON) + return Sym->st_value; + return 0; +} + +template <class ELFT> +uint16_t ELFObjectFile<ELFT>::getEMachine() const { + return EF.getHeader()->e_machine; +} + +template <class ELFT> uint16_t ELFObjectFile<ELFT>::getEType() const { + return EF.getHeader()->e_type; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSymbolSize(DataRefImpl Sym) const { + return getSymbol(Sym)->st_size; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getCommonSymbolSizeImpl(DataRefImpl Symb) const { + return getSymbol(Symb)->st_size; +} + +template <class ELFT> +uint8_t ELFObjectFile<ELFT>::getSymbolBinding(DataRefImpl Symb) const { + return getSymbol(Symb)->getBinding(); +} + +template <class ELFT> +uint8_t ELFObjectFile<ELFT>::getSymbolOther(DataRefImpl Symb) const { + return getSymbol(Symb)->st_other; +} + +template <class ELFT> +uint8_t ELFObjectFile<ELFT>::getSymbolELFType(DataRefImpl Symb) const { + return getSymbol(Symb)->getType(); +} + +template <class ELFT> +Expected<SymbolRef::Type> +ELFObjectFile<ELFT>::getSymbolType(DataRefImpl Symb) const { + const Elf_Sym *ESym = getSymbol(Symb); + + switch (ESym->getType()) { + case ELF::STT_NOTYPE: + return SymbolRef::ST_Unknown; + case ELF::STT_SECTION: + return SymbolRef::ST_Debug; + case ELF::STT_FILE: + return SymbolRef::ST_File; + case ELF::STT_FUNC: + return SymbolRef::ST_Function; + case ELF::STT_OBJECT: + case ELF::STT_COMMON: + case ELF::STT_TLS: + return SymbolRef::ST_Data; + default: + return SymbolRef::ST_Other; + } +} + +template <class ELFT> +uint32_t ELFObjectFile<ELFT>::getSymbolFlags(DataRefImpl Sym) const { + const Elf_Sym *ESym = getSymbol(Sym); + + uint32_t Result = SymbolRef::SF_None; + + if (ESym->getBinding() != ELF::STB_LOCAL) + Result |= SymbolRef::SF_Global; + + if (ESym->getBinding() == ELF::STB_WEAK) + Result |= SymbolRef::SF_Weak; + + if (ESym->st_shndx == ELF::SHN_ABS) + Result |= SymbolRef::SF_Absolute; + + if (ESym->getType() == ELF::STT_FILE || ESym->getType() == ELF::STT_SECTION) + Result |= SymbolRef::SF_FormatSpecific; + + auto DotSymtabSecSyms = EF.symbols(DotSymtabSec); + if (DotSymtabSecSyms && ESym == (*DotSymtabSecSyms).begin()) + Result |= SymbolRef::SF_FormatSpecific; + auto DotDynSymSecSyms = EF.symbols(DotDynSymSec); + if (DotDynSymSecSyms && ESym == (*DotDynSymSecSyms).begin()) + Result |= SymbolRef::SF_FormatSpecific; + + if (EF.getHeader()->e_machine == ELF::EM_ARM) { + if (Expected<StringRef> NameOrErr = getSymbolName(Sym)) { + StringRef Name = *NameOrErr; + if (Name.startswith("$d") || Name.startswith("$t") || + Name.startswith("$a")) + Result |= SymbolRef::SF_FormatSpecific; + } else { + // TODO: Actually report errors helpfully. + consumeError(NameOrErr.takeError()); + } + if (ESym->getType() == ELF::STT_FUNC && (ESym->st_value & 1) == 1) + Result |= SymbolRef::SF_Thumb; + } + + if (ESym->st_shndx == ELF::SHN_UNDEF) + Result |= SymbolRef::SF_Undefined; + + if (ESym->getType() == ELF::STT_COMMON || ESym->st_shndx == ELF::SHN_COMMON) + Result |= SymbolRef::SF_Common; + + if (isExportedToOtherDSO(ESym)) + Result |= SymbolRef::SF_Exported; + + if (ESym->getVisibility() == ELF::STV_HIDDEN) + Result |= SymbolRef::SF_Hidden; + + return Result; +} + +template <class ELFT> +Expected<section_iterator> +ELFObjectFile<ELFT>::getSymbolSection(const Elf_Sym *ESym, + const Elf_Shdr *SymTab) const { + auto ESecOrErr = EF.getSection(ESym, SymTab, ShndxTable); + if (!ESecOrErr) + return ESecOrErr.takeError(); + + const Elf_Shdr *ESec = *ESecOrErr; + if (!ESec) + return section_end(); + + DataRefImpl Sec; + Sec.p = reinterpret_cast<intptr_t>(ESec); + return section_iterator(SectionRef(Sec, this)); +} + +template <class ELFT> +Expected<section_iterator> +ELFObjectFile<ELFT>::getSymbolSection(DataRefImpl Symb) const { + const Elf_Sym *Sym = getSymbol(Symb); + auto SymTabOrErr = EF.getSection(Symb.d.a); + if (!SymTabOrErr) + return SymTabOrErr.takeError(); + const Elf_Shdr *SymTab = *SymTabOrErr; + return getSymbolSection(Sym, SymTab); +} + +template <class ELFT> +void ELFObjectFile<ELFT>::moveSectionNext(DataRefImpl &Sec) const { + const Elf_Shdr *ESec = getSection(Sec); + Sec = toDRI(++ESec); +} + +template <class ELFT> +Expected<StringRef> ELFObjectFile<ELFT>::getSectionName(DataRefImpl Sec) const { + return EF.getSectionName(&*getSection(Sec)); +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSectionAddress(DataRefImpl Sec) const { + return getSection(Sec)->sh_addr; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSectionIndex(DataRefImpl Sec) const { + auto SectionsOrErr = EF.sections(); + handleAllErrors(std::move(SectionsOrErr.takeError()), + [](const ErrorInfoBase &) { + llvm_unreachable("unable to get section index"); + }); + const Elf_Shdr *First = SectionsOrErr->begin(); + return getSection(Sec) - First; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSectionSize(DataRefImpl Sec) const { + return getSection(Sec)->sh_size; +} + +template <class ELFT> +Expected<ArrayRef<uint8_t>> +ELFObjectFile<ELFT>::getSectionContents(DataRefImpl Sec) const { + const Elf_Shdr *EShdr = getSection(Sec); + if (EShdr->sh_type == ELF::SHT_NOBITS) + return makeArrayRef((const uint8_t *)base(), 0); + if (std::error_code EC = + checkOffset(getMemoryBufferRef(), + (uintptr_t)base() + EShdr->sh_offset, EShdr->sh_size)) + return errorCodeToError(EC); + return makeArrayRef((const uint8_t *)base() + EShdr->sh_offset, + EShdr->sh_size); +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSectionAlignment(DataRefImpl Sec) const { + return getSection(Sec)->sh_addralign; +} + +template <class ELFT> +bool ELFObjectFile<ELFT>::isSectionCompressed(DataRefImpl Sec) const { + return getSection(Sec)->sh_flags & ELF::SHF_COMPRESSED; +} + +template <class ELFT> +bool ELFObjectFile<ELFT>::isSectionText(DataRefImpl Sec) const { + return getSection(Sec)->sh_flags & ELF::SHF_EXECINSTR; +} + +template <class ELFT> +bool ELFObjectFile<ELFT>::isSectionData(DataRefImpl Sec) const { + const Elf_Shdr *EShdr = getSection(Sec); + return EShdr->sh_type == ELF::SHT_PROGBITS && + EShdr->sh_flags & ELF::SHF_ALLOC && + !(EShdr->sh_flags & ELF::SHF_EXECINSTR); +} + +template <class ELFT> +bool ELFObjectFile<ELFT>::isSectionBSS(DataRefImpl Sec) const { + const Elf_Shdr *EShdr = getSection(Sec); + return EShdr->sh_flags & (ELF::SHF_ALLOC | ELF::SHF_WRITE) && + EShdr->sh_type == ELF::SHT_NOBITS; +} + +template <class ELFT> +std::vector<SectionRef> +ELFObjectFile<ELFT>::dynamic_relocation_sections() const { + std::vector<SectionRef> Res; + std::vector<uintptr_t> Offsets; + + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return Res; + + for (const Elf_Shdr &Sec : *SectionsOrErr) { + if (Sec.sh_type != ELF::SHT_DYNAMIC) + continue; + Elf_Dyn *Dynamic = + reinterpret_cast<Elf_Dyn *>((uintptr_t)base() + Sec.sh_offset); + for (; Dynamic->d_tag != ELF::DT_NULL; Dynamic++) { + if (Dynamic->d_tag == ELF::DT_REL || Dynamic->d_tag == ELF::DT_RELA || + Dynamic->d_tag == ELF::DT_JMPREL) { + Offsets.push_back(Dynamic->d_un.d_val); + } + } + } + for (const Elf_Shdr &Sec : *SectionsOrErr) { + if (is_contained(Offsets, Sec.sh_addr)) + Res.emplace_back(toDRI(&Sec), this); + } + return Res; +} + +template <class ELFT> +bool ELFObjectFile<ELFT>::isSectionVirtual(DataRefImpl Sec) const { + return getSection(Sec)->sh_type == ELF::SHT_NOBITS; +} + +template <class ELFT> +bool ELFObjectFile<ELFT>::isBerkeleyText(DataRefImpl Sec) const { + return getSection(Sec)->sh_flags & ELF::SHF_ALLOC && + (getSection(Sec)->sh_flags & ELF::SHF_EXECINSTR || + !(getSection(Sec)->sh_flags & ELF::SHF_WRITE)); +} + +template <class ELFT> +bool ELFObjectFile<ELFT>::isBerkeleyData(DataRefImpl Sec) const { + const Elf_Shdr *EShdr = getSection(Sec); + return !isBerkeleyText(Sec) && EShdr->sh_type != ELF::SHT_NOBITS && + EShdr->sh_flags & ELF::SHF_ALLOC; +} + +template <class ELFT> +relocation_iterator +ELFObjectFile<ELFT>::section_rel_begin(DataRefImpl Sec) const { + DataRefImpl RelData; + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return relocation_iterator(RelocationRef()); + uintptr_t SHT = reinterpret_cast<uintptr_t>((*SectionsOrErr).begin()); + RelData.d.a = (Sec.p - SHT) / EF.getHeader()->e_shentsize; + RelData.d.b = 0; + return relocation_iterator(RelocationRef(RelData, this)); +} + +template <class ELFT> +relocation_iterator +ELFObjectFile<ELFT>::section_rel_end(DataRefImpl Sec) const { + const Elf_Shdr *S = reinterpret_cast<const Elf_Shdr *>(Sec.p); + relocation_iterator Begin = section_rel_begin(Sec); + if (S->sh_type != ELF::SHT_RELA && S->sh_type != ELF::SHT_REL) + return Begin; + DataRefImpl RelData = Begin->getRawDataRefImpl(); + const Elf_Shdr *RelSec = getRelSection(RelData); + + // Error check sh_link here so that getRelocationSymbol can just use it. + auto SymSecOrErr = EF.getSection(RelSec->sh_link); + if (!SymSecOrErr) + report_fatal_error(errorToErrorCode(SymSecOrErr.takeError()).message()); + + RelData.d.b += S->sh_size / S->sh_entsize; + return relocation_iterator(RelocationRef(RelData, this)); +} + +template <class ELFT> +Expected<section_iterator> +ELFObjectFile<ELFT>::getRelocatedSection(DataRefImpl Sec) const { + if (EF.getHeader()->e_type != ELF::ET_REL) + return section_end(); + + const Elf_Shdr *EShdr = getSection(Sec); + uintX_t Type = EShdr->sh_type; + if (Type != ELF::SHT_REL && Type != ELF::SHT_RELA) + return section_end(); + + Expected<const Elf_Shdr *> SecOrErr = EF.getSection(EShdr->sh_info); + if (!SecOrErr) + return SecOrErr.takeError(); + return section_iterator(SectionRef(toDRI(*SecOrErr), this)); +} + +// Relocations +template <class ELFT> +void ELFObjectFile<ELFT>::moveRelocationNext(DataRefImpl &Rel) const { + ++Rel.d.b; +} + +template <class ELFT> +symbol_iterator +ELFObjectFile<ELFT>::getRelocationSymbol(DataRefImpl Rel) const { + uint32_t symbolIdx; + const Elf_Shdr *sec = getRelSection(Rel); + if (sec->sh_type == ELF::SHT_REL) + symbolIdx = getRel(Rel)->getSymbol(EF.isMips64EL()); + else + symbolIdx = getRela(Rel)->getSymbol(EF.isMips64EL()); + if (!symbolIdx) + return symbol_end(); + + // FIXME: error check symbolIdx + DataRefImpl SymbolData; + SymbolData.d.a = sec->sh_link; + SymbolData.d.b = symbolIdx; + return symbol_iterator(SymbolRef(SymbolData, this)); +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getRelocationOffset(DataRefImpl Rel) const { + const Elf_Shdr *sec = getRelSection(Rel); + if (sec->sh_type == ELF::SHT_REL) + return getRel(Rel)->r_offset; + + return getRela(Rel)->r_offset; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getRelocationType(DataRefImpl Rel) const { + const Elf_Shdr *sec = getRelSection(Rel); + if (sec->sh_type == ELF::SHT_REL) + return getRel(Rel)->getType(EF.isMips64EL()); + else + return getRela(Rel)->getType(EF.isMips64EL()); +} + +template <class ELFT> +StringRef ELFObjectFile<ELFT>::getRelocationTypeName(uint32_t Type) const { + return getELFRelocationTypeName(EF.getHeader()->e_machine, Type); +} + +template <class ELFT> +void ELFObjectFile<ELFT>::getRelocationTypeName( + DataRefImpl Rel, SmallVectorImpl<char> &Result) const { + uint32_t type = getRelocationType(Rel); + EF.getRelocationTypeName(type, Result); +} + +template <class ELFT> +Expected<int64_t> +ELFObjectFile<ELFT>::getRelocationAddend(DataRefImpl Rel) const { + if (getRelSection(Rel)->sh_type != ELF::SHT_RELA) + return createError("Section is not SHT_RELA"); + return (int64_t)getRela(Rel)->r_addend; +} + +template <class ELFT> +const typename ELFObjectFile<ELFT>::Elf_Rel * +ELFObjectFile<ELFT>::getRel(DataRefImpl Rel) const { + assert(getRelSection(Rel)->sh_type == ELF::SHT_REL); + auto Ret = EF.template getEntry<Elf_Rel>(Rel.d.a, Rel.d.b); + if (!Ret) + report_fatal_error(errorToErrorCode(Ret.takeError()).message()); + return *Ret; +} + +template <class ELFT> +const typename ELFObjectFile<ELFT>::Elf_Rela * +ELFObjectFile<ELFT>::getRela(DataRefImpl Rela) const { + assert(getRelSection(Rela)->sh_type == ELF::SHT_RELA); + auto Ret = EF.template getEntry<Elf_Rela>(Rela.d.a, Rela.d.b); + if (!Ret) + report_fatal_error(errorToErrorCode(Ret.takeError()).message()); + return *Ret; +} + +template <class ELFT> +Expected<ELFObjectFile<ELFT>> +ELFObjectFile<ELFT>::create(MemoryBufferRef Object) { + auto EFOrErr = ELFFile<ELFT>::create(Object.getBuffer()); + if (Error E = EFOrErr.takeError()) + return std::move(E); + auto EF = std::move(*EFOrErr); + + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return SectionsOrErr.takeError(); + + const Elf_Shdr *DotDynSymSec = nullptr; + const Elf_Shdr *DotSymtabSec = nullptr; + ArrayRef<Elf_Word> ShndxTable; + for (const Elf_Shdr &Sec : *SectionsOrErr) { + switch (Sec.sh_type) { + case ELF::SHT_DYNSYM: { + if (!DotDynSymSec) + DotDynSymSec = &Sec; + break; + } + case ELF::SHT_SYMTAB: { + if (!DotSymtabSec) + DotSymtabSec = &Sec; + break; + } + case ELF::SHT_SYMTAB_SHNDX: { + auto TableOrErr = EF.getSHNDXTable(Sec); + if (!TableOrErr) + return TableOrErr.takeError(); + ShndxTable = *TableOrErr; + break; + } + } + } + return ELFObjectFile<ELFT>(Object, EF, DotDynSymSec, DotSymtabSec, + ShndxTable); +} + +template <class ELFT> +ELFObjectFile<ELFT>::ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF, + const Elf_Shdr *DotDynSymSec, + const Elf_Shdr *DotSymtabSec, + ArrayRef<Elf_Word> ShndxTable) + : ELFObjectFileBase( + getELFType(ELFT::TargetEndianness == support::little, ELFT::Is64Bits), + Object), + EF(EF), DotDynSymSec(DotDynSymSec), DotSymtabSec(DotSymtabSec), + ShndxTable(ShndxTable) {} + +template <class ELFT> +ELFObjectFile<ELFT>::ELFObjectFile(ELFObjectFile<ELFT> &&Other) + : ELFObjectFile(Other.Data, Other.EF, Other.DotDynSymSec, + Other.DotSymtabSec, Other.ShndxTable) {} + +template <class ELFT> +basic_symbol_iterator ELFObjectFile<ELFT>::symbol_begin() const { + DataRefImpl Sym = + toDRI(DotSymtabSec, + DotSymtabSec && DotSymtabSec->sh_size >= sizeof(Elf_Sym) ? 1 : 0); + return basic_symbol_iterator(SymbolRef(Sym, this)); +} + +template <class ELFT> +basic_symbol_iterator ELFObjectFile<ELFT>::symbol_end() const { + const Elf_Shdr *SymTab = DotSymtabSec; + if (!SymTab) + return symbol_begin(); + DataRefImpl Sym = toDRI(SymTab, SymTab->sh_size / sizeof(Elf_Sym)); + return basic_symbol_iterator(SymbolRef(Sym, this)); +} + +template <class ELFT> +elf_symbol_iterator ELFObjectFile<ELFT>::dynamic_symbol_begin() const { + DataRefImpl Sym = toDRI(DotDynSymSec, 0); + return symbol_iterator(SymbolRef(Sym, this)); +} + +template <class ELFT> +elf_symbol_iterator ELFObjectFile<ELFT>::dynamic_symbol_end() const { + const Elf_Shdr *SymTab = DotDynSymSec; + if (!SymTab) + return dynamic_symbol_begin(); + DataRefImpl Sym = toDRI(SymTab, SymTab->sh_size / sizeof(Elf_Sym)); + return basic_symbol_iterator(SymbolRef(Sym, this)); +} + +template <class ELFT> +section_iterator ELFObjectFile<ELFT>::section_begin() const { + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return section_iterator(SectionRef()); + return section_iterator(SectionRef(toDRI((*SectionsOrErr).begin()), this)); +} + +template <class ELFT> +section_iterator ELFObjectFile<ELFT>::section_end() const { + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return section_iterator(SectionRef()); + return section_iterator(SectionRef(toDRI((*SectionsOrErr).end()), this)); +} + +template <class ELFT> +uint8_t ELFObjectFile<ELFT>::getBytesInAddress() const { + return ELFT::Is64Bits ? 8 : 4; +} + +template <class ELFT> +StringRef ELFObjectFile<ELFT>::getFileFormatName() const { + bool IsLittleEndian = ELFT::TargetEndianness == support::little; + switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) { + case ELF::ELFCLASS32: + switch (EF.getHeader()->e_machine) { + case ELF::EM_386: + return "ELF32-i386"; + case ELF::EM_IAMCU: + return "ELF32-iamcu"; + case ELF::EM_X86_64: + return "ELF32-x86-64"; + case ELF::EM_ARM: + return (IsLittleEndian ? "ELF32-arm-little" : "ELF32-arm-big"); + case ELF::EM_AVR: + return "ELF32-avr"; + case ELF::EM_HEXAGON: + return "ELF32-hexagon"; + case ELF::EM_LANAI: + return "ELF32-lanai"; + case ELF::EM_MIPS: + return "ELF32-mips"; + case ELF::EM_MSP430: + return "ELF32-msp430"; + case ELF::EM_PPC: + return "ELF32-ppc"; + case ELF::EM_RISCV: + return "ELF32-riscv"; + case ELF::EM_SPARC: + case ELF::EM_SPARC32PLUS: + return "ELF32-sparc"; + case ELF::EM_AMDGPU: + return "ELF32-amdgpu"; + default: + return "ELF32-unknown"; + } + case ELF::ELFCLASS64: + switch (EF.getHeader()->e_machine) { + case ELF::EM_386: + return "ELF64-i386"; + case ELF::EM_X86_64: + return "ELF64-x86-64"; + case ELF::EM_AARCH64: + return (IsLittleEndian ? "ELF64-aarch64-little" : "ELF64-aarch64-big"); + case ELF::EM_PPC64: + return "ELF64-ppc64"; + case ELF::EM_RISCV: + return "ELF64-riscv"; + case ELF::EM_S390: + return "ELF64-s390"; + case ELF::EM_SPARCV9: + return "ELF64-sparc"; + case ELF::EM_MIPS: + return "ELF64-mips"; + case ELF::EM_AMDGPU: + return "ELF64-amdgpu"; + case ELF::EM_BPF: + return "ELF64-BPF"; + default: + return "ELF64-unknown"; + } + default: + // FIXME: Proper error handling. + report_fatal_error("Invalid ELFCLASS!"); + } +} + +template <class ELFT> Triple::ArchType ELFObjectFile<ELFT>::getArch() const { + bool IsLittleEndian = ELFT::TargetEndianness == support::little; + switch (EF.getHeader()->e_machine) { + case ELF::EM_386: + case ELF::EM_IAMCU: + return Triple::x86; + case ELF::EM_X86_64: + return Triple::x86_64; + case ELF::EM_AARCH64: + return IsLittleEndian ? Triple::aarch64 : Triple::aarch64_be; + case ELF::EM_ARM: + return Triple::arm; + case ELF::EM_AVR: + return Triple::avr; + case ELF::EM_HEXAGON: + return Triple::hexagon; + case ELF::EM_LANAI: + return Triple::lanai; + case ELF::EM_MIPS: + switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) { + case ELF::ELFCLASS32: + return IsLittleEndian ? Triple::mipsel : Triple::mips; + case ELF::ELFCLASS64: + return IsLittleEndian ? Triple::mips64el : Triple::mips64; + default: + report_fatal_error("Invalid ELFCLASS!"); + } + case ELF::EM_MSP430: + return Triple::msp430; + case ELF::EM_PPC: + return Triple::ppc; + case ELF::EM_PPC64: + return IsLittleEndian ? Triple::ppc64le : Triple::ppc64; + case ELF::EM_RISCV: + switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) { + case ELF::ELFCLASS32: + return Triple::riscv32; + case ELF::ELFCLASS64: + return Triple::riscv64; + default: + report_fatal_error("Invalid ELFCLASS!"); + } + case ELF::EM_S390: + return Triple::systemz; + + case ELF::EM_SPARC: + case ELF::EM_SPARC32PLUS: + return IsLittleEndian ? Triple::sparcel : Triple::sparc; + case ELF::EM_SPARCV9: + return Triple::sparcv9; + + case ELF::EM_AMDGPU: { + if (!IsLittleEndian) + return Triple::UnknownArch; + + unsigned MACH = EF.getHeader()->e_flags & ELF::EF_AMDGPU_MACH; + if (MACH >= ELF::EF_AMDGPU_MACH_R600_FIRST && + MACH <= ELF::EF_AMDGPU_MACH_R600_LAST) + return Triple::r600; + if (MACH >= ELF::EF_AMDGPU_MACH_AMDGCN_FIRST && + MACH <= ELF::EF_AMDGPU_MACH_AMDGCN_LAST) + return Triple::amdgcn; + + return Triple::UnknownArch; + } + + case ELF::EM_BPF: + return IsLittleEndian ? Triple::bpfel : Triple::bpfeb; + + default: + return Triple::UnknownArch; + } +} + +template <class ELFT> +Expected<uint64_t> ELFObjectFile<ELFT>::getStartAddress() const { + return EF.getHeader()->e_entry; +} + +template <class ELFT> +ELFObjectFileBase::elf_symbol_iterator_range +ELFObjectFile<ELFT>::getDynamicSymbolIterators() const { + return make_range(dynamic_symbol_begin(), dynamic_symbol_end()); +} + +template <class ELFT> bool ELFObjectFile<ELFT>::isRelocatableObject() const { + return EF.getHeader()->e_type == ELF::ET_REL; +} + +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_ELFOBJECTFILE_H |