[llvm-commits] [lld] r156100 - in /lld/trunk: include/lld/Reader/ include/lld/Reader/Reader.h lib/CMakeLists.txt lib/Reader/ lib/Reader/CMakeLists.txt lib/Reader/COFFReader.cpp tools/lld-core/CMakeLists.txt tools/lld-core/lld-core.cpp

Michael J. Spencer bigcheesegs at gmail.com
Thu May 3 13:52:23 PDT 2012


Author: mspencer
Date: Thu May  3 15:52:22 2012
New Revision: 156100

URL: http://llvm.org/viewvc/llvm-project?rev=156100&view=rev
Log:
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.

Added:
    lld/trunk/include/lld/Reader/
    lld/trunk/include/lld/Reader/Reader.h
    lld/trunk/lib/Reader/
    lld/trunk/lib/Reader/CMakeLists.txt
    lld/trunk/lib/Reader/COFFReader.cpp
Modified:
    lld/trunk/lib/CMakeLists.txt
    lld/trunk/tools/lld-core/CMakeLists.txt
    lld/trunk/tools/lld-core/lld-core.cpp

Added: lld/trunk/include/lld/Reader/Reader.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Reader/Reader.h?rev=156100&view=auto
==============================================================================
--- lld/trunk/include/lld/Reader/Reader.h (added)
+++ lld/trunk/include/lld/Reader/Reader.h Thu May  3 15:52:22 2012
@@ -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

Modified: lld/trunk/lib/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/CMakeLists.txt?rev=156100&r1=156099&r2=156100&view=diff
==============================================================================
--- lld/trunk/lib/CMakeLists.txt (original)
+++ lld/trunk/lib/CMakeLists.txt Thu May  3 15:52:22 2012
@@ -1,3 +1,4 @@
 add_subdirectory(Core)
 add_subdirectory(Passes)
 add_subdirectory(Platforms)
+add_subdirectory(Reader)

Added: lld/trunk/lib/Reader/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Reader/CMakeLists.txt?rev=156100&view=auto
==============================================================================
--- lld/trunk/lib/Reader/CMakeLists.txt (added)
+++ lld/trunk/lib/Reader/CMakeLists.txt Thu May  3 15:52:22 2012
@@ -0,0 +1,3 @@
+add_lld_library(lldReader
+  COFFReader.cpp
+  )

Added: lld/trunk/lib/Reader/COFFReader.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Reader/COFFReader.cpp?rev=156100&view=auto
==============================================================================
--- lld/trunk/lib/Reader/COFFReader.cpp (added)
+++ lld/trunk/lib/Reader/COFFReader.cpp Thu May  3 15:52:22 2012
@@ -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;
+}

Modified: lld/trunk/tools/lld-core/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/tools/lld-core/CMakeLists.txt?rev=156100&r1=156099&r2=156100&view=diff
==============================================================================
--- lld/trunk/tools/lld-core/CMakeLists.txt (original)
+++ lld/trunk/tools/lld-core/CMakeLists.txt Thu May  3 15:52:22 2012
@@ -1,11 +1,13 @@
 set(LLVM_USED_LIBS
   lldCore
+  lldReader
   lldPasses
   lldDarwinPlatform
   )
 
 set(LLVM_LINK_COMPONENTS
   support
+  Object
   )
 
 add_lld_executable(lld-core

Modified: lld/trunk/tools/lld-core/lld-core.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/tools/lld-core/lld-core.cpp?rev=156100&r1=156099&r2=156100&view=diff
==============================================================================
--- lld/trunk/tools/lld-core/lld-core.cpp (original)
+++ lld/trunk/tools/lld-core/lld-core.cpp Thu May  3 15:52:22 2012
@@ -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 @@
 } // 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 @@
   // 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 @@
   
   // 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





More information about the llvm-commits mailing list