[llvm-commits] [lld] r160732 - /lld/trunk/lib/ReaderWriter/ELF/ReaderELF.cpp
Nick Kledzik
kledzik at apple.com
Wed Jul 25 18:10:19 PDT 2012
Sid,
Please compile with -Wshadow. ReaderELF.cpp produces a bunch of shadow variable warnings, usually two local variables in scope with the same name.
Also, we want Readers to cleanly return with an error_code if an errors occur. This is so that the Readers can be used as a library in some other program (such as an IDE). The ReaderELF currently calls llvm::report_fatal_error() which usually terminates the program.
-Nick
On Jul 25, 2012, at 9:27 AM, Sid Manning wrote:
> Author: sidneym
> Date: Wed Jul 25 11:27:21 2012
> New Revision: 160732
>
> URL: http://llvm.org/viewvc/llvm-project?rev=160732&view=rev
> Log:
> Implement the ELF reader. The original implementation was by Hemant Kulkarni
> with subsequent changes to use lower level interfaces done by me.
>
> Modified:
> lld/trunk/lib/ReaderWriter/ELF/ReaderELF.cpp
>
> Modified: lld/trunk/lib/ReaderWriter/ELF/ReaderELF.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ReaderELF.cpp?rev=160732&r1=160731&r2=160732&view=diff
> ==============================================================================
> --- lld/trunk/lib/ReaderWriter/ELF/ReaderELF.cpp (original)
> +++ lld/trunk/lib/ReaderWriter/ELF/ReaderELF.cpp Wed Jul 25 11:27:21 2012
> @@ -6,20 +6,543 @@
> // License. See LICENSE.TXT for details.
> //
> //===----------------------------------------------------------------------===//
> +//
> +// This file contains the ELF Reader and all helper sub classes
> +// to consume an ELF file and produces atoms out of it.
> +//
> +//===----------------------------------------------------------------------===//
>
> #include "lld/ReaderWriter/ReaderELF.h"
> #include "lld/Core/File.h"
>
> +#include "llvm/ADT/ArrayRef.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/Object/ELF.h"
> +#include "llvm/Object/ObjectFile.h"
> +#include "llvm/Support/Allocator.h"
> #include "llvm/Support/Casting.h"
> +#include "llvm/Support/ELF.h"
> +#include "llvm/Support/Endian.h"
> #include "llvm/Support/ErrorHandling.h"
> +#include "llvm/Support/MathExtras.h"
> #include "llvm/Support/Memory.h"
> #include "llvm/Support/MemoryBuffer.h"
> #include "llvm/Support/raw_ostream.h"
> #include "llvm/Support/system_error.h"
>
> +
> #include <map>
> #include <vector>
>
> +using llvm::object::Elf_Sym_Impl;
> +using namespace lld;
> +
> +namespace { // anonymous
> +
> +// This atom class corresponds to absolute symbol
> +class ELFAbsoluteAtom: public AbsoluteAtom {
> +
> +public:
> + ELFAbsoluteAtom(const File &F,
> + llvm::StringRef N,
> + uint64_t V)
> + : OwningFile(F)
> + , Name(N)
> + , Value(V)
> + {}
> +
> + virtual const class File &file() const {
> + return OwningFile;
> + }
> +
> + virtual llvm::StringRef name() const {
> + return Name;
> + }
> +
> + virtual uint64_t value() const {
> + return Value;
> + }
> +
> +private:
> + const File &OwningFile;
> + llvm::StringRef Name;
> + uint64_t Value;
> +};
> +
> +
> +// This atom corresponds to undefined symbols.
> +template<llvm::support::endianness target_endianness, bool is64Bits>
> +class ELFUndefinedAtom: public UndefinedAtom {
> +
> + typedef llvm::object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
> +
> +public:
> + ELFUndefinedAtom(const File &F,
> + llvm::StringRef N,
> + const Elf_Sym *E)
> + : OwningFile(F)
> + , Name(N)
> + , Symbol(E)
> + {}
> +
> + virtual const class File &file() const {
> + return OwningFile;
> + }
> +
> + virtual llvm::StringRef name() const {
> + return Name;
> + }
> +
> + // FIXME What distinguishes a symbol in ELF that can help
> + // decide if the symbol is undefined only during build and not
> + // runtime? This will make us choose canBeNullAtBuildtime and
> + // canBeNullAtRuntime
> + //
> + virtual CanBeNull canBeNull() const {
> +
> + if (Symbol->getBinding() == llvm::ELF::STB_WEAK)
> + return CanBeNull::canBeNullAtBuildtime;
> + else
> + return CanBeNull::canBeNullNever;
> + }
> +
> +private:
> + const File &OwningFile;
> + llvm::StringRef Name;
> + const Elf_Sym *Symbol;
> +};
> +
> +
> +// This atom corresponds to defined symbols.
> +template<llvm::support::endianness target_endianness, bool is64Bits>
> +class ELFDefinedAtom: public DefinedAtom {
> +
> + typedef llvm::object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
> + typedef llvm::object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
> +
> +public:
> + ELFDefinedAtom(const File &F,
> + llvm::StringRef N,
> + llvm::StringRef SN,
> + const Elf_Sym *E,
> + const Elf_Shdr *S,
> + llvm::ArrayRef<uint8_t> D)
> + : OwningFile(F)
> + , SymbolName(N)
> + , SectionName(SN)
> + , Symbol(E)
> + , Section(S)
> + , Data(D) {
> + static uint64_t ordernumber = 0;
> + _ordinal = ++ordernumber;
> + }
> +
> + virtual const class File &file() const {
> + return OwningFile;
> + }
> +
> + virtual llvm::StringRef name() const {
> + return SymbolName;
> + }
> +
> + virtual uint64_t ordinal() const {
> + return _ordinal;
> + }
> +
> + virtual uint64_t size() const {
> +
> + // Common symbols are not allocated in object files so
> + // their size is zero.
> + if ((Symbol->getType() == llvm::ELF::STT_COMMON)
> + || Symbol->st_shndx == llvm::ELF::SHN_COMMON)
> + return (uint64_t)0;
> +
> + return Data.size();
> +
> + }
> +
> + virtual Scope scope() const {
> + if (Symbol->st_other == llvm::ELF::STV_HIDDEN)
> + return scopeLinkageUnit;
> + else if (Symbol->getBinding() != llvm::ELF::STB_LOCAL)
> + return scopeGlobal;
> + else
> + return scopeTranslationUnit;
> + }
> +
> + // FIXME Need to revisit this in future.
> +
> + virtual Interposable interposable() const {
> + return interposeNo;
> + }
> +
> + // FIXME What ways can we determine this in ELF?
> +
> + virtual Merge merge() const {
> +
> + if (Symbol->getBinding() == llvm::ELF::STB_WEAK)
> + return mergeAsWeak;
> +
> + if ((Symbol->getType() == llvm::ELF::STT_COMMON)
> + || Symbol->st_shndx == llvm::ELF::SHN_COMMON)
> + return mergeAsTentative;
> +
> + return mergeNo;
> + }
> +
> + virtual ContentType contentType() const {
> +
> + if (Symbol->getType() == llvm::ELF::STT_FUNC)
> + return typeCode;
> +
> + if ((Symbol->getType() == llvm::ELF::STT_COMMON)
> + || Symbol->st_shndx == llvm::ELF::SHN_COMMON)
> + return typeZeroFill;
> +
> + if (Symbol->getType() == llvm::ELF::STT_OBJECT)
> + return typeData;
> +
> + return typeUnknown;
> + }
> +
> + virtual Alignment alignment() const {
> +
> + // Unallocated common symbols specify their alignment
> + // constraints in st_value.
> + if ((Symbol->getType() == llvm::ELF::STT_COMMON)
> + || Symbol->st_shndx == llvm::ELF::SHN_COMMON) {
> + return (Alignment(Symbol->st_value));
> + }
> +
> + return Alignment(1);
> + }
> +
> + // Do we have a choice for ELF? All symbols
> + // live in explicit sections.
> + virtual SectionChoice sectionChoice() const {
> + if (Symbol->st_shndx > llvm::ELF::SHN_LORESERVE)
> + return sectionBasedOnContent;
> +
> + return sectionCustomRequired;
> + }
> +
> + virtual llvm::StringRef customSectionName() const {
> + return SectionName;
> + }
> +
> + // It isn't clear that __attribute__((used)) is transmitted to
> + // the ELF object file.
> + virtual DeadStripKind deadStrip() const {
> + return deadStripNormal;
> + }
> +
> + virtual ContentPermissions permissions() const {
> +
> + switch (Section->sh_type) {
> + // permRW_L is for sections modified by the runtime
> + // loader.
> + case llvm::ELF::SHT_REL:
> + case llvm::ELF::SHT_RELA:
> + return permRW_L;
> +
> + case llvm::ELF::SHT_DYNAMIC:
> + case llvm::ELF::SHT_PROGBITS:
> + switch (Section->sh_flags) {
> +
> + case (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR):
> + return permR_X;
> +
> + case (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE):
> + return permRW_;
> +
> + case llvm::ELF::SHF_ALLOC:
> + case (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_MERGE):
> + case (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_MERGE
> + | llvm::ELF::SHF_STRINGS):
> + return permR__;
> + }
> + default:
> + return perm___;
> + }
> + }
> +
> + // Many non ARM architectures use ELF file format
> + // This not really a place to put a architecture
> + // specific method in an atom. A better approach is
> + // needed.
> + //
> + virtual bool isThumb() const {
> + return false;
> + }
> +
> + // FIXME Not Sure if ELF supports alias atoms. Find out more.
> + virtual bool isAlias() const {
> + return false;
> + }
> +
> + virtual llvm::ArrayRef<uint8_t> rawContent() const {
> + return Data;
> + }
> +
> + virtual reference_iterator begin() const {
> + return reference_iterator(*this, nullptr);
> + }
> +
> + virtual reference_iterator end() const {
> + return reference_iterator(*this, nullptr);
> + }
> +
> +private:
> + virtual const Reference *derefIterator(const void *iter) const {
> + return nullptr;
> + }
> + virtual void incrementIterator(const void *&iter) const {
> + }
> +
> + const File &OwningFile;
> + llvm::StringRef SymbolName;
> + llvm::StringRef SectionName;
> + const Elf_Sym *Symbol;
> + const Elf_Shdr *Section;
> +
> + // Data will hold the bits that make up the atom.
> + llvm::ArrayRef<uint8_t> Data;
> +
> + uint64_t _ordinal;
> +};
> +
> +
> +// FileELF will read a binary, find out based on the symbol table contents
> +// what kind of symbol it is and create corresponding atoms for it
> +
> +template<llvm::support::endianness target_endianness, bool is64Bits>
> +class FileELF: public File {
> +
> + typedef llvm::object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
> + typedef llvm::object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
> +
> +public:
> + FileELF(std::unique_ptr<llvm::MemoryBuffer> MB, llvm::error_code &EC) :
> + File(MB->getBufferIdentifier()) {
> +
> + llvm::OwningPtr<llvm::object::Binary> Bin;
> + EC = llvm::object::createBinary(MB.release(), Bin);
> + if (EC)
> + return;
> +
> + // Point Obj to correct class and bitwidth ELF object
> + Obj.reset(llvm::dyn_cast<llvm::object::ELFObjectFile<target_endianness,
> + is64Bits> >(Bin.get()));
> +
> + if (!Obj) {
> + EC = make_error_code(llvm::object::object_error::invalid_file_type);
> + return;
> + }
> +
> + Bin.take();
> +
> + std::map< const Elf_Shdr *, std::vector<const Elf_Sym *>> SectionSymbols;
> +
> + llvm::object::SectionRef SR;
> + llvm::object::section_iterator section(SR);
> + llvm::object::symbol_iterator si(Obj->begin_symbols());
> + llvm::object::symbol_iterator se(Obj->end_symbols());
> +
> + for (; si != se; si.increment(EC)) {
> + if (EC)
> + llvm::report_fatal_error("Could not read all symbols");
> + llvm::object::SectionRef SR;
> + llvm::object::section_iterator section(SR);
> +
> + EC = si->getSection(section);
> + if (EC)
> + llvm::report_fatal_error("Could not get section iterator");
> +
> + const Elf_Shdr *Section = Obj->getElfSection(section);
> + const Elf_Sym *Symbol = Obj->getElfSymbol(si);
> +
> + llvm::StringRef SymbolName;
> + EC = Obj->getSymbolName(Section, Symbol, SymbolName);
> + if (EC)
> + llvm::report_fatal_error("Could not get symbol name");
> +
> + if (Symbol->st_shndx == llvm::ELF::SHN_ABS) {
> + // Create an absolute atom.
> + AbsoluteAtoms._atoms.push_back(
> + new (AtomStorage.Allocate<ELFAbsoluteAtom> ())
> + ELFAbsoluteAtom(*this, SymbolName,
> + Symbol->st_value));
> +
> + } else if (Symbol->st_shndx == llvm::ELF::SHN_UNDEF) {
> + // Create an undefined atom.
> + UndefinedAtoms._atoms.push_back(
> + new (AtomStorage.Allocate<ELFUndefinedAtom<
> + target_endianness, is64Bits>>())
> + ELFUndefinedAtom<target_endianness, is64Bits> (
> + *this, SymbolName, Symbol));
> + } else {
> + // This is actually a defined symbol. Add it to its section's list of
> + // symbols.
> + if (Symbol->getType() == llvm::ELF::STT_NOTYPE
> + || Symbol->getType() == llvm::ELF::STT_OBJECT
> + || Symbol->getType() == llvm::ELF::STT_FUNC
> + || Symbol->getType() == llvm::ELF::STT_SECTION
> + || Symbol->getType() == llvm::ELF::STT_FILE
> + || Symbol->getType() == llvm::ELF::STT_TLS
> + || Symbol->getType() == llvm::ELF::STT_COMMON
> + || Symbol->st_shndx == llvm::ELF::SHN_COMMON) {
> + SectionSymbols[Section].push_back(Symbol);
> + }
> + else {
> + llvm::errs() << "Unable to create atom for: " << SymbolName << "\n";
> + EC = llvm::object::object_error::parse_failed;
> + return;
> + }
> + }
> + }
> +
> + for (auto &i : SectionSymbols) {
> + auto &Symbs = i.second;
> + llvm::StringRef SymbolName;
> + llvm::StringRef SectionName;
> + // Sort symbols by position.
> + std::stable_sort(Symbs.begin(), Symbs.end(),
> + // From ReaderCOFF.cpp:
> + // For some reason MSVC fails to allow the lambda in this context with
> + // a "illegal use of local type in type instantiation". MSVC is clearly
> + // wrong here. Force a conversion to function pointer to work around.
> + static_cast<bool(*)(const Elf_Sym*, const Elf_Sym*)>(
> + [](const Elf_Sym *A, const Elf_Sym *B) -> bool {
> + return A->st_value < B->st_value;
> + }));
> +
> + // i.first is the section the symbol lives in
> + for (auto si = Symbs.begin(), se = Symbs.end(); si != se; ++si) {
> +
> + StringRef symbolContents;
> + EC = Obj->getSectionContents(i.first, symbolContents);
> + if (EC)
> + llvm::report_fatal_error("Could not get section iterator");
> +
> + EC = Obj->getSymbolName(i.first, *si, SymbolName);
> + if (EC)
> + llvm::report_fatal_error("Could not get symbol name");
> +
> + EC = Obj->getSectionName(i.first, SectionName);
> + if (EC)
> + llvm::report_fatal_error("Could not get section name");
> +
> + bool IsCommon = false;
> + if (((*si)->getType() == llvm::ELF::STT_COMMON)
> + || (*si)->st_shndx == llvm::ELF::SHN_COMMON)
> + IsCommon = true;
> +
> + // Get the symbol's content:
> + llvm::ArrayRef<uint8_t> SymbolData;
> + if (si + 1 == se) {
> + // if this is the last symbol, take up the remaining data.
> + SymbolData = llvm::ArrayRef<uint8_t>((uint8_t *)symbolContents.data()
> + + (*si)->st_value,
> + (IsCommon) ? 0 :
> + ((i.first)->sh_size - (*si)->st_value));
> + }
> + else {
> + SymbolData = llvm::ArrayRef<uint8_t>((uint8_t *)symbolContents.data()
> + + (*si)->st_value,
> + (IsCommon) ? 0 :
> + (*(si + 1))->st_value - (*si)->st_value);
> + }
> +
> + DefinedAtoms._atoms.push_back(
> + new (AtomStorage.Allocate<ELFDefinedAtom<
> + target_endianness, is64Bits> > ())
> + ELFDefinedAtom<target_endianness, is64Bits> (*this,
> + SymbolName, SectionName,
> + *si, i.first, SymbolData));
> + }
> + }
> + }
> +
> + virtual void addAtom(const Atom&) {
> + llvm_unreachable("cannot add atoms to native .o files");
> + }
> +
> + virtual const atom_collection<DefinedAtom> &defined() const {
> + return DefinedAtoms;
> + }
> +
> + virtual const atom_collection<UndefinedAtom> &undefined() const {
> + return UndefinedAtoms;
> + }
> +
> + virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
> + return SharedLibraryAtoms;
> + }
> +
> + virtual const atom_collection<AbsoluteAtom> &absolute() const {
> + return AbsoluteAtoms;
> + }
> +
> +private:
> + std::unique_ptr<llvm::object::ELFObjectFile<target_endianness, is64Bits> >
> + Obj;
> + atom_collection_vector<DefinedAtom> DefinedAtoms;
> + atom_collection_vector<UndefinedAtom> UndefinedAtoms;
> + atom_collection_vector<SharedLibraryAtom> SharedLibraryAtoms;
> + atom_collection_vector<AbsoluteAtom> AbsoluteAtoms;
> + llvm::BumpPtrAllocator AtomStorage;
> +
> +};
> +
> +// ReaderELF is reader object that will instantiate correct FileELF
> +// by examining the memory buffer for ELF class and bitwidth
> +
> +class ReaderELF: public Reader {
> +public:
> + ReaderELF(const ReaderOptionsELF &options) :
> + _options(options) {
> + }
> + error_code parseFile(std::unique_ptr<MemoryBuffer> mb, std::vector<
> + std::unique_ptr<File> > &result) {
> +
> + std::pair<unsigned char, unsigned char> Ident =
> + llvm::object::getElfArchType(&*mb);
> + llvm::error_code ec;
> + // Instantiate the correct FileELF template instance
> + // based on the Ident pair. Once the File is created
> + // we push the file to the vector of files already
> + // created during parser's life.
> +
> + std::unique_ptr<File> f;
> +
> + if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second
> + == llvm::ELF::ELFDATA2LSB) {
> + f.reset(new FileELF<llvm::support::little, false>(std::move(mb), ec));
> +
> + } else if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second
> + == llvm::ELF::ELFDATA2MSB) {
> + f.reset(new FileELF<llvm::support::big, false> (std::move(mb), ec));
> +
> + } else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second
> + == llvm::ELF::ELFDATA2MSB) {
> + f.reset(new FileELF<llvm::support::big, true> (std::move(mb), ec));
> +
> + } else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second
> + == llvm::ELF::ELFDATA2LSB) {
> + f.reset(new FileELF<llvm::support::little, true> (std::move(mb), ec));
> + }
> +
> + if (ec)
> + return ec;
> +
> + result.push_back(std::move(f));
> + return error_code::success();
> + }
> +private:
> + const ReaderOptionsELF &_options;
> +};
> +
> +} // namespace anonymous
>
> namespace lld {
>
> @@ -30,12 +553,8 @@
> }
>
>
> -
> -Reader* createReaderELF(const ReaderOptionsELF &options) {
> - assert(0 && "ELF Reader not yet implemented");
> - return nullptr;
> +Reader *createReaderELF(const ReaderOptionsELF &options) {
> + return new ReaderELF(options);
> }
>
> -
> -} // namespace
> -
> +} // namespace LLD
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list