diff options
| author | Michael J. Spencer <bigcheesegs@gmail.com> | 2012-05-03 20:52:22 +0000 |
|---|---|---|
| committer | Michael J. Spencer <bigcheesegs@gmail.com> | 2012-05-03 20:52:22 +0000 |
| commit | 60d835fa597c86c88dc2c7bfec399395d4d43f8b (patch) | |
| tree | e1bc26c0f98ea8e04fd7b99e2acbfe21520545e5 | |
| parent | 64cc29cb84649d634e6eb8072bcccfee40725341 (diff) | |
| download | bcm5719-llvm-60d835fa597c86c88dc2c7bfec399395d4d43f8b.tar.gz bcm5719-llvm-60d835fa597c86c88dc2c7bfec399395d4d43f8b.zip | |
Add COFF reader.
There are no tests for this yet because I still need to finish the
YAML -> COFF converter so we don't get binary files checked in.
llvm-svn: 156100
| -rw-r--r-- | lld/include/lld/Reader/Reader.h | 29 | ||||
| -rw-r--r-- | lld/lib/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | lld/lib/Reader/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | lld/lib/Reader/COFFReader.cpp | 366 | ||||
| -rw-r--r-- | lld/tools/lld-core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | lld/tools/lld-core/lld-core.cpp | 31 |
6 files changed, 425 insertions, 7 deletions
diff --git a/lld/include/lld/Reader/Reader.h b/lld/include/lld/Reader/Reader.h new file mode 100644 index 00000000000..c74615b0bfe --- /dev/null +++ b/lld/include/lld/Reader/Reader.h @@ -0,0 +1,29 @@ +//===- Reader.h - Create object file readers ------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_READER_H_ +#define LLD_READER_READER_H_ + +#include "llvm/ADT/OwningPtr.h" + +#include <memory> + +namespace llvm { + class error_code; + class MemoryBuffer; +} + +namespace lld { + class File; + + llvm::error_code parseCOFFObjectFile(std::unique_ptr<llvm::MemoryBuffer> MB, + std::unique_ptr<File> &Result); +} + +#endif diff --git a/lld/lib/CMakeLists.txt b/lld/lib/CMakeLists.txt index e5d0dbcb4aa..2ce187cf1d6 100644 --- a/lld/lib/CMakeLists.txt +++ b/lld/lib/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(Core) add_subdirectory(Passes) add_subdirectory(Platforms) +add_subdirectory(Reader) diff --git a/lld/lib/Reader/CMakeLists.txt b/lld/lib/Reader/CMakeLists.txt new file mode 100644 index 00000000000..c8f2421649c --- /dev/null +++ b/lld/lib/Reader/CMakeLists.txt @@ -0,0 +1,3 @@ +add_lld_library(lldReader + COFFReader.cpp + ) diff --git a/lld/lib/Reader/COFFReader.cpp b/lld/lib/Reader/COFFReader.cpp new file mode 100644 index 00000000000..ceedfd02977 --- /dev/null +++ b/lld/lib/Reader/COFFReader.cpp @@ -0,0 +1,366 @@ +//===- COFFReader.h - PECOFF Object File Reader ---------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Reader/Reader.h" +#include "lld/Core/File.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Object/COFF.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 <map> +#include <vector> + +using namespace lld; +using llvm::object::coff_symbol; + +class COFFAbsoluteAtom : public AbsoluteAtom { +public: + COFFAbsoluteAtom(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; +}; + +class COFFUndefinedAtom : public UndefinedAtom { +public: + COFFUndefinedAtom(const File &F, llvm::StringRef N) + : OwningFile(F) + , Name(N) + {} + + virtual const class File& file() const { + return OwningFile; + } + + virtual llvm::StringRef name() const { + return Name; + } + + virtual CanBeNull canBeNull() const { + return CanBeNull::canBeNullNever; + } + +private: + const File &OwningFile; + llvm::StringRef Name; +}; + +class COFFDefinedAtom : public DefinedAtom { +public: + COFFDefinedAtom( const File &F + , llvm::StringRef N + , const llvm::object::coff_symbol *Symb + , const llvm::object::coff_section *Sec + , llvm::ArrayRef<uint8_t> D) + : OwningFile(F) + , Name(N) + , Symbol(Symb) + , Section(Sec) + , Data(D) + {} + + virtual const class File& file() const { + return OwningFile; + } + + virtual llvm::StringRef name() const { + return Name; + } + + virtual uint64_t ordinal() const { + return reinterpret_cast<intptr_t>(Symbol); + } + + virtual uint64_t size() const { + return Data.size(); + } + + virtual Scope scope() const { + if (!Symbol) + return scopeTranslationUnit; + switch (Symbol->StorageClass) { + case llvm::COFF::IMAGE_SYM_CLASS_EXTERNAL: + return scopeGlobal; + case llvm::COFF::IMAGE_SYM_CLASS_STATIC: + return scopeTranslationUnit; + } + llvm_unreachable("Unknown scope!"); + } + + virtual Interposable interposable() const { + return interposeNo; + } + + virtual Merge merge() const { + return mergeNo; + } + + virtual ContentType contentType() const { + if (Section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_CODE) + return typeCode; + if (Section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) + return typeData; + if (Section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) + return typeZeroFill; + return typeUnknown; + } + + virtual Alignment alignment() const { + return Alignment(1); + } + + virtual SectionChoice sectionChoice() const { + return sectionBasedOnContent; + } + + virtual llvm::StringRef customSectionName() const { + return ""; + } + + virtual DeadStripKind deadStrip() const { + return deadStripNormal; + } + + virtual ContentPermissions permissions() const { + if ( Section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ + && Section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_WRITE) + return permRW_; + if ( Section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ + && Section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_EXECUTE) + return permR_X; + if (Section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ) + return permR__; + return perm___; + } + + virtual bool isThumb() const { + return false; + } + + 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 Name; + const llvm::object::coff_symbol *Symbol; + const llvm::object::coff_section *Section; + llvm::ArrayRef<uint8_t> Data; +}; + +class COFFReader : public File { +public: + COFFReader(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; + + Obj.reset(llvm::dyn_cast<const llvm::object::COFFObjectFile>(Bin.get())); + if (Obj) + Bin.take(); + else { + EC = make_error_code(llvm::object::object_error::invalid_file_type); + return; + } + + const llvm::object::coff_file_header *Header = nullptr; + if ((EC = Obj->getHeader(Header))) + return; + + // Assign each symbol to the section it's in. If it does not belong to a + // section, create an atom for it now. + std::map< const llvm::object::coff_section* + , std::vector<const llvm::object::coff_symbol*>> SectionSymbols; + + for (uint32_t i = 0, e = Header->NumberOfSymbols; i != e; ++i) { + const llvm::object::coff_symbol *Symb; + if ((EC = Obj->getSymbol(i, Symb))) + return; + llvm::StringRef Name; + if ((EC = Obj->getSymbolName(Symb, Name))) + return; + int16_t SectionIndex = Symb->SectionNumber; + assert(SectionIndex != llvm::COFF::IMAGE_SYM_DEBUG && + "Cannot atomize IMAGE_SYM_DEBUG!"); + if (SectionIndex == llvm::COFF::IMAGE_SYM_ABSOLUTE) { + // Create an absolute atom. + AbsoluteAtoms._atoms.push_back( + new (AtomStorage.Allocate<COFFAbsoluteAtom>()) + COFFAbsoluteAtom(*this, Name, Symb->Value)); + } else if (SectionIndex == llvm::COFF::IMAGE_SYM_UNDEFINED) { + // Create an undefined atom. + UndefinedAtoms._atoms.push_back( + new (AtomStorage.Allocate<COFFUndefinedAtom>()) + COFFUndefinedAtom(*this, Name)); + } else { + // This is actually a defined symbol. Add it to its section's list of + // symbols. + uint8_t SC = Symb->StorageClass; + // If Symb->Value actually means section offset. + if ( SC == llvm::COFF::IMAGE_SYM_CLASS_EXTERNAL + || SC == llvm::COFF::IMAGE_SYM_CLASS_STATIC + || SC == llvm::COFF::IMAGE_SYM_CLASS_FUNCTION) { + const llvm::object::coff_section *Sec; + if ((EC = Obj->getSection(SectionIndex, Sec))) + return; + assert(Sec && "SectionIndex > 0, Sec must be non-null!"); + SectionSymbols[Sec].push_back(Symb); + } else { + llvm::errs() << "Unable to create atom for: " << Name << "\n"; + EC = llvm::object::object_error::parse_failed; + return; + } + } + // Skip aux symbols. + i += Symb->NumberOfAuxSymbols; + } + + // For each section, sort its symbols by address, then create a defined atom + // for each range. + for (auto i = SectionSymbols.begin(), e = SectionSymbols.end(); + i != e; ++i) { + auto &Symbs = i->second; + // Sort symbols by position. + std::stable_sort(Symbs.begin(), Symbs.end(), + // 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 coff_symbol*, const coff_symbol*)>( + [](const coff_symbol *A, const coff_symbol *B) -> bool { + return A->Value < B->Value; + })); + + if (Symbs.empty()) { + // Create an atom for the entire section. + llvm::ArrayRef<uint8_t> Data; + DefinedAtoms._atoms.push_back( + new (AtomStorage.Allocate<COFFDefinedAtom>()) + COFFDefinedAtom(*this, "", nullptr, i->first, Data)); + continue; + } + + llvm::ArrayRef<uint8_t> SecData; + if ((EC = Obj->getSectionContents(i->first, SecData))) + return; + + // Create an unnamed atom if the first atom isn't at the start of the + // section. + if (Symbs[0]->Value != 0) { + uint64_t Size = Symbs[0]->Value; + llvm::ArrayRef<uint8_t> Data(SecData.data(), Size); + DefinedAtoms._atoms.push_back( + new (AtomStorage.Allocate<COFFDefinedAtom>()) + COFFDefinedAtom(*this, "", nullptr, i->first, Data)); + } + + for (auto si = Symbs.begin(), se = Symbs.end(); si != se; ++si) { + // if this is the last symbol, take up the remaining data. + llvm::ArrayRef<uint8_t> Data; + if (si + 1 == se) { + Data = llvm::ArrayRef<uint8_t>( SecData.data() + (*si)->Value + , SecData.end()); + } else { + Data = llvm::ArrayRef<uint8_t>( SecData.data() + (*si)->Value + , (*(si + 1))->Value - (*si)->Value); + } + llvm::StringRef Name; + if ((EC = Obj->getSymbolName(*si, Name))) + return; + DefinedAtoms._atoms.push_back( + new (AtomStorage.Allocate<COFFDefinedAtom>()) + COFFDefinedAtom(*this, Name, *si, i->first, Data)); + } + } + } + + virtual void addAtom(const Atom&) { + llvm_unreachable("cannot add atoms to native .obj 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<const llvm::object::COFFObjectFile> Obj; + atom_collection_vector<DefinedAtom> DefinedAtoms; + atom_collection_vector<UndefinedAtom> UndefinedAtoms; + atom_collection_vector<SharedLibraryAtom> SharedLibraryAtoms; + atom_collection_vector<AbsoluteAtom> AbsoluteAtoms; + llvm::BumpPtrAllocator AtomStorage; +}; + +llvm::error_code +lld::parseCOFFObjectFile(std::unique_ptr<llvm::MemoryBuffer> MB, + std::unique_ptr<File> &Result) { + llvm::error_code EC; + Result.reset(new COFFReader(std::move(MB), EC)); + if (EC) + Result.release(); + return EC; +} diff --git a/lld/tools/lld-core/CMakeLists.txt b/lld/tools/lld-core/CMakeLists.txt index 27ff1a998b7..bd645094d59 100644 --- a/lld/tools/lld-core/CMakeLists.txt +++ b/lld/tools/lld-core/CMakeLists.txt @@ -1,11 +1,13 @@ set(LLVM_USED_LIBS lldCore + lldReader lldPasses lldDarwinPlatform ) set(LLVM_LINK_COMPONENTS support + Object ) add_lld_executable(lld-core diff --git a/lld/tools/lld-core/lld-core.cpp b/lld/tools/lld-core/lld-core.cpp index 50e00fc7cbe..229ed868614 100644 --- a/lld/tools/lld-core/lld-core.cpp +++ b/lld/tools/lld-core/lld-core.cpp @@ -15,6 +15,7 @@ #include "lld/Core/Resolver.h" #include "lld/Core/YamlReader.h" #include "lld/Core/YamlWriter.h" +#include "lld/Reader/Reader.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/CommandLine.h" @@ -348,10 +349,9 @@ const TestingPlatform::KindMapping TestingPlatform::_s_kindMappings[] = { } // anon namespace -llvm::cl::opt<std::string> -cmdLineInputFilePath(llvm::cl::Positional, - llvm::cl::desc("<input file>"), - llvm::cl::init("-")); +llvm::cl::list<std::string> +cmdLineInputFilePaths(llvm::cl::Positional, + llvm::cl::desc("<input file>")); llvm::cl::opt<std::string> cmdLineOutputFilePath("o", @@ -421,6 +421,9 @@ int main(int argc, char *argv[]) { // parse options llvm::cl::ParseCommandLineOptions(argc, argv); + if (cmdLineInputFilePaths.empty()) + cmdLineInputFilePaths.emplace_back("-"); + // create platform for testing Platform* platform = nullptr; switch ( platformSelected ) { @@ -434,9 +437,23 @@ int main(int argc, char *argv[]) { // read input YAML doc into object file(s) std::vector<std::unique_ptr<const File>> files; - if (error(yaml::parseObjectTextFileOrSTDIN(cmdLineInputFilePath, - *platform, files))) { - return 1; + for (auto path : cmdLineInputFilePaths) { + OwningPtr<llvm::MemoryBuffer> ofile; + if (error(llvm::MemoryBuffer::getFileOrSTDIN(path, ofile))) + return 1; + std::unique_ptr<llvm::MemoryBuffer> file(ofile.take()); + if (llvm::sys::fs::identify_magic(file->getBuffer()) + == llvm::sys::fs::file_magic::coff_object) { + std::unique_ptr<File> f; + if (error(parseCOFFObjectFile(std::move(file), f))) + return 1; + files.push_back(std::move(f)); + } else { + if (error(yaml::parseObjectText( file.release() + , *platform + , files))) + return 1; + } } // create options for resolving |

