diff --git a/lib/ReaderWriter/ELF/ReaderELF.cpp b/lib/ReaderWriter/ELF/ReaderELF.cpp index ba23990..f4bd52d 100644 --- a/lib/ReaderWriter/ELF/ReaderELF.cpp +++ b/lib/ReaderWriter/ELF/ReaderELF.cpp @@ -1,41 +1,456 @@ -//===- lib/ReaderWriter/ELF/ReaderELF.cpp --------------------------------===// +//===- lib/ReaderWriter/ELF/ReaderELF.cpp ---------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // 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/Support/Allocator.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Memory.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/ELF.h" #include #include +using namespace lld; -namespace lld { +// This atom class corresponds to absolute symbol -ReaderOptionsELF::ReaderOptionsELF() { -} +class ELFAbsoluteAtom: public AbsoluteAtom { +public: + ELFAbsoluteAtom(const File &F, llvm::StringRef N, uint64_t V) : + OwningFile(F), Name(N), Value(V) { + } -ReaderOptionsELF::~ReaderOptionsELF() { -} + virtual const class File& file() const { + return OwningFile; + } + virtual llvm::StringRef name() const { + return Name; + } + virtual uint64_t value() const { + return Value; + } -Reader* createReaderELF(const ReaderOptionsELF &options) { - assert(0 && "ELF Reader not yet implemented"); - return nullptr; -} +private: + const File &OwningFile; + llvm::StringRef Name; + uint64_t Value; +}; + +// This atom corresponds to undefined symbols. +class ELFUndefinedAtom: public UndefinedAtom { +public: + ELFUndefinedAtom(const File &F, llvm::StringRef N, + llvm::object::symbol_iterator Symb) : + OwningFile(F), Name(N), Symbol(Symb) { + } + + 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 { + uint32_t Result; + + Symbol->getFlags(Result); + if (Result == llvm::object::SymbolRef::SF_Weak) + return CanBeNull::canBeNullAtBuildtime; + else + return CanBeNull::canBeNullNever; + } + +private: + const File &OwningFile; + llvm::StringRef Name; + llvm::object::symbol_iterator Symbol; +}; + +template +class ELFDefinedAtom: public DefinedAtom { +public: + ELFDefinedAtom(const File &F, llvm::StringRef N, + llvm::object::symbol_iterator Symb, + llvm::object::section_iterator Sec, llvm::ArrayRef D) : + OwningFile(F), Name(N), Symbol(Symb), Section(Sec), Data(D) { + static uint64_t ordernumber = 0; + _ordinal = ++ordernumber; + } + + virtual const class File& file() const { + return OwningFile; + } + + virtual llvm::StringRef name() const { + return Name; + } + + virtual uint64_t ordinal() const { + return _ordinal; + } + + virtual uint64_t size() const { + uint64_t size; + Symbol->getSize(size); + return size; + } + + // FIXME We also need to find visibility + // This will help us determine scopeLinkageUnit + // we also need to incorporate other visibilities + + + virtual Scope scope() const { + uint32_t Result; + Symbol->getFlags(Result); + if (Result == llvm::object::SymbolRef::SF_Global) + 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 { + return mergeNo; + } + + virtual ContentType contentType() const { + ContentType type; + bool Result = false; + llvm::error_code ec; + ec = Section->isText(Result); + if (!ec && Result) + return typeCode; + + ec = Section->isData(Result); + if (!ec && Result) + return typeData; + +// The ZeroFill type is a bit ambiguous in case of ELF +// Should this mean it occupies no space in the disk image? +// A .bss is such section + + + ec = Section->isBSS(Result); + if (!ec && Result) + return typeZeroFill; + + return typeUnknown; + } + + virtual Alignment alignment() const { + uint64_t Result; + llvm::error_code ec; + ec = Section->getAlignment(Result); + if (ec) + return Alignment(-1); + return Alignment(llvm::Log2_64(Result)); + + } + + virtual SectionChoice sectionChoice() const { + return sectionBasedOnContent; + } + + virtual llvm::StringRef customSectionName() const { + return ""; + } + + virtual DeadStripKind deadStrip() const { + return deadStripNormal; + } + + // This does not cover the possibility of the initial + // write permissions for PLT stubs + // The API available right now is an ugly way of doing it. + // We need a way to explicitly + // query the SHF_* attributes of a section. + + virtual ContentPermissions permissions() const { + char Result; + Symbol->getNMTypeChar(Result); + if (Result == 'r') + return permR__; + else if (Result == 'd') + return permRW_; + else if (Result == 't') + return permR_X; + else + 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 rawContent() const { + return Data; + } + virtual reference_iterator begin() const { + return reference_iterator(*this, nullptr); + } -} // namespace + 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 Name; + const llvm::object::symbol_iterator Symbol; + const llvm::object::section_iterator Section; + llvm::ArrayRef 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 +class FileELF: public File { +public: + FileELF(std::unique_ptr MB, llvm::error_code &EC) : + File(MB->getBufferIdentifier()) { + llvm::OwningPtr 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 >(Bin.get())); + + if (!Obj) { + EC = make_error_code(llvm::object::object_error::invalid_file_type); + return; + } + Bin.take(); + + // Now we need to iterate over symtab and + // get all the symbols + // convert these symbols to atoms + // FIXME what about dynamic symbols? + + + 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::StringRef Name; + llvm::object::SymbolRef::Type type; + uint32_t flags = 0; + + EC = si->getName(Name); + if (EC) + llvm::report_fatal_error("Could not get symbol name"); + + EC = si->getType(type); + if (EC) + llvm::report_fatal_error("Could not get symbol type"); + + EC = si->getFlags(flags); + if (EC) + llvm::report_fatal_error("Could not get symbol flags"); + + if (flags & llvm::object::SymbolRef::SF_Absolute + == llvm::object::SymbolRef::SF_Absolute) { + uint64_t AbsValue; + + EC = si->getAddress(AbsValue); + if (EC) + llvm::report_fatal_error( + "Could not get absolute symbol st_value"); + + AbsoluteAtoms._atoms.push_back(new (AtomStorage.Allocate< + ELFAbsoluteAtom>())ELFAbsoluteAtom(*this, Name, + AbsValue)); + } else if (flags & llvm::object::SymbolRef::SF_Undefined + == llvm::object::SymbolRef::SF_Undefined) { + UndefinedAtoms._atoms.push_back(new (AtomStorage.Allocate< + ELFUndefinedAtom>()) ELFUndefinedAtom(*this, Name, si)); + + } else { + bool Result; + //FIXME need to figure out a way to handle common type + //symbols. For now we abort + + EC = si->isCommon(Result); + assert(!Result && "STT_COMMON type is not yet implemented"); + //TODO We need to think about how to put other + //symbol types into the defined atom model. + + + if (type == llvm::object::SymbolRef::ST_Data || type + == llvm::object::SymbolRef::ST_Function) { + + llvm::object::SectionRef SR; + llvm::object::section_iterator section(SR); + + EC = si->getSection(section); + if (EC) + return; + //FIXME We need an API to get the actual st_value + //for now shorting this array reference to + //suppress errors during build time. + //Need to fix this + + llvm::ArrayRef val; + DefinedAtoms._atoms.push_back( + new (AtomStorage.Allocate >()) ELFDefinedAtom< + target_endianness, is64Bits>(*this, Name, + si, section, val)); + + } + } + } + } + + virtual void addAtom(const Atom&) { + llvm_unreachable("cannot add atoms to native .o files"); + } + + virtual const atom_collection &defined() const { + return DefinedAtoms; + } + + virtual const atom_collection &undefined() const { + return UndefinedAtoms; + } + + virtual const atom_collection &sharedLibrary() const { + return SharedLibraryAtoms; + } + + virtual const atom_collection &absolute() const { + return AbsoluteAtoms; + } + +private: + std::unique_ptr > + Obj; + atom_collection_vector DefinedAtoms; + atom_collection_vector UndefinedAtoms; + atom_collection_vector SharedLibraryAtoms; + atom_collection_vector 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 mb, std::vector< + std::unique_ptr > &result) { + + std::pair 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 f; + if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second + == llvm::ELF::ELFDATA2LSB) { + f.reset(new FileELF (std::move(mb), + ec)); + } else if (Ident.first == llvm::ELF::ELFCLASS32 && Ident.second + == llvm::ELF::ELFDATA2MSB) { + f.reset(new FileELF (std::move(mb), ec)); + } else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second + == llvm::ELF::ELFDATA2MSB) { + f.reset(new FileELF (std::move(mb), ec)); + } else if (Ident.first == llvm::ELF::ELFCLASS64 && Ident.second + == llvm::ELF::ELFDATA2LSB) { + f.reset(new FileELF(std::move(mb), + ec)); + } + if (ec) + return ec; + result.push_back(std::move(f)); + return error_code::success(); + } +private: + const ReaderOptionsELF &_options; +}; + +ReaderOptionsELF::ReaderOptionsELF() { +} + +ReaderOptionsELF::~ReaderOptionsELF() { +} + +namespace lld { +//This reader is not complete so I wont "enable" the knob + Reader* createReaderELF(const ReaderOptionsELF &options) { + assert(0 && "ELF Reader not yet implemented"); + return new ReaderELF(options); + } +} // namespace lld