[lld] r195169 - Do not inline large member functions. No functionality change.

Rui Ueyama ruiu at google.com
Tue Nov 19 15:40:44 PST 2013


Author: ruiu
Date: Tue Nov 19 17:40:44 2013
New Revision: 195169

URL: http://llvm.org/viewvc/llvm-project?rev=195169&view=rev
Log:
Do not inline large member functions. No functionality change.

Modified:
    lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp

Modified: lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp?rev=195169&r1=195168&r2=195169&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp Tue Nov 19 17:40:44 2013
@@ -53,6 +53,153 @@ using namespace lld;
 
 namespace {
 
+class FileCOFF : public File {
+private:
+  typedef vector<const coff_symbol *> SymbolVectorT;
+  typedef std::map<const coff_section *, SymbolVectorT> SectionToSymbolsT;
+  typedef std::map<const StringRef, Atom *> SymbolNameToAtomT;
+  typedef std::map<const coff_section *, vector<COFFDefinedFileAtom *> >
+  SectionToAtomsT;
+
+public:
+  FileCOFF(const LinkingContext &context, std::unique_ptr<MemoryBuffer> mb,
+           error_code &ec);
+
+  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;
+  }
+
+  virtual const LinkingContext &getLinkingContext() const { return _context; }
+
+  StringRef getLinkerDirectives() const { return _directives; }
+
+private:
+  error_code readSymbolTable(vector<const coff_symbol *> &result);
+
+  void createAbsoluteAtoms(const SymbolVectorT &symbols,
+                           vector<const AbsoluteAtom *> &result);
+
+  error_code createUndefinedAtoms(const SymbolVectorT &symbols,
+                                  vector<const UndefinedAtom *> &result);
+
+  error_code createDefinedSymbols(const SymbolVectorT &symbols,
+                                  vector<const DefinedAtom *> &result);
+
+  error_code cacheSectionAttributes();
+
+  error_code
+  AtomizeDefinedSymbolsInSection(const coff_section *section,
+                                 vector<const coff_symbol *> &symbols,
+                                 vector<COFFDefinedFileAtom *> &atoms);
+
+  error_code AtomizeDefinedSymbols(SectionToSymbolsT &definedSymbols,
+                                   vector<const DefinedAtom *> &definedAtoms);
+
+  error_code findAtomAt(const coff_section *section, uint32_t targetAddress,
+                        COFFDefinedFileAtom *&result, uint32_t &offsetInAtom);
+
+  error_code getAtomBySymbolIndex(uint32_t index, Atom *&ret);
+
+  error_code addRelocationReference(const coff_relocation *rel,
+                                    const coff_section *section,
+                                    const vector<COFFDefinedFileAtom *> &atoms);
+
+  error_code addRelocationReferenceToAtoms();
+  error_code findSection(StringRef name, const coff_section *&result);
+  std::string ArrayRefToString(ArrayRef<uint8_t> array);
+  error_code maybeReadLinkerDirectives();
+
+  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;
+
+  // The contents of .drectve section.
+  std::string _directives;
+
+  // A map from symbol to its name. All symbols should be in this map except
+  // unnamed ones.
+  std::map<const coff_symbol *, StringRef> _symbolName;
+
+  // A map from symbol to its resultant atom.
+  std::map<const coff_symbol *, Atom *> _symbolAtom;
+
+  // A map from symbol to its aux symbol.
+  std::map<const coff_symbol *, const coff_symbol *> _auxSymbol;
+
+  // A map from section to its atoms.
+  std::map<const coff_section *, vector<COFFDefinedFileAtom *> > _sectionAtoms;
+
+  // A set of COMDAT sections.
+  std::set<const coff_section *> _comdatSections;
+
+  // A map to get whether the section allows its contents to be merged or not.
+  std::map<const coff_section *, DefinedAtom::Merge> _merge;
+
+  // A sorted map to find an atom from a section and an offset within
+  // the section.
+  std::map<const coff_section *,
+           std::map<uint32_t, std::vector<COFFDefinedAtom *> > >
+  _definedAtomLocations;
+
+  mutable llvm::BumpPtrAllocator _alloc;
+  const LinkingContext &_context;
+};
+
+class BumpPtrStringSaver : public llvm::cl::StringSaver {
+public:
+  virtual const char *SaveString(const char *str) {
+    size_t len = strlen(str);
+    char *copy = _alloc.Allocate<char>(len + 1);
+    memcpy(copy, str, len + 1);
+    return copy;
+  }
+
+private:
+  llvm::BumpPtrAllocator _alloc;
+};
+
+class ReaderCOFF : public Reader {
+public:
+  explicit ReaderCOFF(PECOFFLinkingContext &context)
+      : Reader(context), _PECOFFLinkingContext(context) {}
+
+  error_code parseFile(std::unique_ptr<MemoryBuffer> &mb,
+                       std::vector<std::unique_ptr<File> > &result) const;
+
+private:
+  error_code handleDirectiveSection(StringRef directives) const;
+
+  ErrorOr<std::string>
+  writeResToTemporaryFile(std::unique_ptr<MemoryBuffer> mb) const;
+
+  ErrorOr<std::string>
+  convertResourceFileToCOFF(std::unique_ptr<MemoryBuffer> mb) const;
+
+  error_code convertAndParseResourceFile(
+      std::unique_ptr<MemoryBuffer> &mb,
+      std::vector<std::unique_ptr<File> > &result) const;
+
+  error_code parseCOFFFile(std::unique_ptr<MemoryBuffer> &mb,
+                           std::vector<std::unique_ptr<File> > &result) const;
+
+  PECOFFLinkingContext &_PECOFFLinkingContext;
+  mutable BumpPtrStringSaver _stringSaver;
+};
+
 // Converts the COFF symbol attribute to the LLD's atom attribute.
 Atom::Scope getScope(const coff_symbol *symbol) {
   switch (symbol->StorageClass) {
@@ -130,808 +277,709 @@ DefinedAtom::Merge getMerge(const coff_a
   }
 }
 
-class FileCOFF : public File {
-private:
-  typedef vector<const coff_symbol *> SymbolVectorT;
-  typedef std::map<const coff_section *, SymbolVectorT> SectionToSymbolsT;
-  typedef std::map<const StringRef, Atom *> SymbolNameToAtomT;
-  typedef std::map<const coff_section *, vector<COFFDefinedFileAtom *> >
-  SectionToAtomsT;
-
-public:
-  FileCOFF(const LinkingContext &context,
-           std::unique_ptr<MemoryBuffer> mb, error_code &ec)
-      : File(mb->getBufferIdentifier(), kindObject), _context(context) {
-    OwningPtr<llvm::object::Binary> bin;
-    ec = llvm::object::createBinary(mb.release(), bin);
-    if (ec)
-      return;
-
-    _obj.reset(dyn_cast<const llvm::object::COFFObjectFile>(bin.get()));
-    if (!_obj) {
-      ec = make_error_code(llvm::object::object_error::invalid_file_type);
-      return;
-    }
-    bin.take();
-
-    // Read the symbol table and atomize them if possible. Defined atoms
-    // cannot be atomized in one pass, so they will be not be atomized but
-    // added to symbolToAtom.
-    SymbolVectorT symbols;
-    if ((ec = readSymbolTable(symbols)))
-      return;
-
-    createAbsoluteAtoms(symbols, _absoluteAtoms._atoms);
-    if ((ec = createUndefinedAtoms(symbols, _undefinedAtoms._atoms)))
-      return;
-    if ((ec = createDefinedSymbols(symbols, _definedAtoms._atoms)))
-      return;
+FileCOFF::FileCOFF(const LinkingContext &context,
+                   std::unique_ptr<MemoryBuffer> mb, error_code &ec)
+    : File(mb->getBufferIdentifier(), kindObject), _context(context) {
+  OwningPtr<llvm::object::Binary> bin;
+  ec = llvm::object::createBinary(mb.release(), bin);
+  if (ec)
+    return;
+
+  _obj.reset(dyn_cast<const llvm::object::COFFObjectFile>(bin.get()));
+  if (!_obj) {
+    ec = make_error_code(llvm::object::object_error::invalid_file_type);
+    return;
+  }
+  bin.take();
+
+  // Read the symbol table and atomize them if possible. Defined atoms
+  // cannot be atomized in one pass, so they will be not be atomized but
+  // added to symbolToAtom.
+  SymbolVectorT symbols;
+  if ((ec = readSymbolTable(symbols)))
+    return;
+
+  createAbsoluteAtoms(symbols, _absoluteAtoms._atoms);
+  if ((ec = createUndefinedAtoms(symbols, _undefinedAtoms._atoms)))
+    return;
+  if ((ec = createDefinedSymbols(symbols, _definedAtoms._atoms)))
+    return;
 
-    if ((ec = addRelocationReferenceToAtoms()))
-      return;
+  if ((ec = addRelocationReferenceToAtoms()))
+    return;
 
-    // Read .drectve section if exists.
-    ec = maybeReadLinkerDirectives();
-  }
-
-  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;
-  }
-
-  virtual const LinkingContext &getLinkingContext() const { return _context; }
-
-  StringRef getLinkerDirectives() const { return _directives; }
-
-private:
-  /// Iterate over the symbol table to retrieve all symbols.
-  error_code readSymbolTable(vector<const coff_symbol *> &result) {
-    const llvm::object::coff_file_header *header = nullptr;
-    if (error_code ec = _obj->getHeader(header))
-      return ec;
+  // Read .drectve section if exists.
+  ec = maybeReadLinkerDirectives();
+}
 
-    for (uint32_t i = 0, e = header->NumberOfSymbols; i != e; ++i) {
-      // Retrieve the symbol.
-      const coff_symbol *sym;
-      if (error_code ec = _obj->getSymbol(i, sym))
+/// Iterate over the symbol table to retrieve all symbols.
+error_code FileCOFF::readSymbolTable(vector<const coff_symbol *> &result) {
+  const llvm::object::coff_file_header *header = nullptr;
+  if (error_code ec = _obj->getHeader(header))
+    return ec;
+
+  for (uint32_t i = 0, e = header->NumberOfSymbols; i != e; ++i) {
+    // Retrieve the symbol.
+    const coff_symbol *sym;
+    if (error_code ec = _obj->getSymbol(i, sym))
+      return ec;
+    assert(sym->SectionNumber != llvm::COFF::IMAGE_SYM_DEBUG &&
+           "Cannot atomize IMAGE_SYM_DEBUG!");
+    result.push_back(sym);
+
+    // Cache the name.
+    StringRef name;
+    if (error_code ec = _obj->getSymbolName(sym, name))
+      return ec;
+    _symbolName[sym] = name;
+
+    // Symbol may be followed by auxiliary symbol table records. The aux
+    // record can be in any format, but the size is always the same as the
+    // regular symbol. The aux record supplies additional information for the
+    // standard symbol. We do not interpret the aux record here, but just
+    // store it to _auxSymbol.
+    if (sym->NumberOfAuxSymbols > 0) {
+      const coff_symbol *aux = nullptr;
+      if (error_code ec = _obj->getAuxSymbol(i + 1, aux))
         return ec;
-      assert(sym->SectionNumber != llvm::COFF::IMAGE_SYM_DEBUG &&
-             "Cannot atomize IMAGE_SYM_DEBUG!");
-      result.push_back(sym);
-
-      // Cache the name.
-      StringRef name;
-      if (error_code ec = _obj->getSymbolName(sym, name))
-        return ec;
-      _symbolName[sym] = name;
-
-      // Symbol may be followed by auxiliary symbol table records. The aux
-      // record can be in any format, but the size is always the same as the
-      // regular symbol. The aux record supplies additional information for the
-      // standard symbol. We do not interpret the aux record here, but just
-      // store it to _auxSymbol.
-      if (sym->NumberOfAuxSymbols > 0) {
-        const coff_symbol *aux = nullptr;
-        if (error_code ec = _obj->getAuxSymbol(i + 1, aux))
-          return ec;
-        _auxSymbol[sym] = aux;
-        i += sym->NumberOfAuxSymbols;
-      }
+      _auxSymbol[sym] = aux;
+      i += sym->NumberOfAuxSymbols;
     }
-    return error_code::success();
   }
+  return error_code::success();
+}
 
-  /// Create atoms for the absolute symbols.
-  void createAbsoluteAtoms(const SymbolVectorT &symbols,
-                           vector<const AbsoluteAtom *> &result) {
-    for (const coff_symbol *sym : symbols) {
-      if (sym->SectionNumber != llvm::COFF::IMAGE_SYM_ABSOLUTE)
-        continue;
-      auto *atom = new (_alloc)
-          COFFAbsoluteAtom(*this, _symbolName[sym], getScope(sym), sym->Value);
+/// Create atoms for the absolute symbols.
+void FileCOFF::createAbsoluteAtoms(const SymbolVectorT &symbols,
+                                   vector<const AbsoluteAtom *> &result) {
+  for (const coff_symbol *sym : symbols) {
+    if (sym->SectionNumber != llvm::COFF::IMAGE_SYM_ABSOLUTE)
+      continue;
+    auto *atom = new (_alloc)
+        COFFAbsoluteAtom(*this, _symbolName[sym], getScope(sym), sym->Value);
 
-      result.push_back(atom);
-      _symbolAtom[sym] = atom;
-    }
+    result.push_back(atom);
+    _symbolAtom[sym] = atom;
   }
+}
 
-  /// Create atoms for the undefined symbols. This code is bit complicated
-  /// because it supports "weak externals" mechanism of COFF. If an undefined
-  /// symbol (sym1) has auxiliary data, the data contains a symbol table index
-  /// at which the "second symbol" (sym2) for sym1 exists. If sym1 is resolved,
-  /// it's linked normally. If not, sym1 is resolved as if it has sym2's
-  /// name. This relationship between sym1 and sym2 is represented using
-  /// fallback mechanism of undefined symbol.
-  error_code createUndefinedAtoms(const SymbolVectorT &symbols,
-                                  vector<const UndefinedAtom *> &result) {
-    // Sort out undefined symbols from all symbols.
-    std::set<const coff_symbol *> undefines;
-    std::map<const coff_symbol *, const coff_symbol *> weakExternal;
-    for (const coff_symbol *sym : symbols) {
-      if (sym->SectionNumber != llvm::COFF::IMAGE_SYM_UNDEFINED)
-        continue;
-      undefines.insert(sym);
-
-      // Create a mapping from sym1 to sym2, if the undefined symbol has
-      // auxiliary data.
-      auto iter = _auxSymbol.find(sym);
-      if (iter == _auxSymbol.end())
-        continue;
-      const coff_aux_weak_external *aux = reinterpret_cast<
-          const coff_aux_weak_external *>(iter->second);
-      const coff_symbol *sym2;
-      if (error_code ec = _obj->getSymbol(aux->TagIndex, sym2))
-        return ec;
-      weakExternal[sym] = sym2;
-    }
+/// Create atoms for the undefined symbols. This code is bit complicated
+/// because it supports "weak externals" mechanism of COFF. If an undefined
+/// symbol (sym1) has auxiliary data, the data contains a symbol table index
+/// at which the "second symbol" (sym2) for sym1 exists. If sym1 is resolved,
+/// it's linked normally. If not, sym1 is resolved as if it has sym2's
+/// name. This relationship between sym1 and sym2 is represented using
+/// fallback mechanism of undefined symbol.
+error_code
+FileCOFF::createUndefinedAtoms(const SymbolVectorT &symbols,
+                               vector<const UndefinedAtom *> &result) {
+  // Sort out undefined symbols from all symbols.
+  std::set<const coff_symbol *> undefines;
+  std::map<const coff_symbol *, const coff_symbol *> weakExternal;
+  for (const coff_symbol *sym : symbols) {
+    if (sym->SectionNumber != llvm::COFF::IMAGE_SYM_UNDEFINED)
+      continue;
+    undefines.insert(sym);
+
+    // Create a mapping from sym1 to sym2, if the undefined symbol has
+    // auxiliary data.
+    auto iter = _auxSymbol.find(sym);
+    if (iter == _auxSymbol.end())
+      continue;
+    const coff_aux_weak_external *aux =
+        reinterpret_cast<const coff_aux_weak_external *>(iter->second);
+    const coff_symbol *sym2;
+    if (error_code ec = _obj->getSymbol(aux->TagIndex, sym2))
+      return ec;
+    weakExternal[sym] = sym2;
+  }
+
+  // Sort out sym1s from sym2s. Sym2s shouldn't be added to the undefined atom
+  // list because they shouldn't be resolved unless sym1 is failed to
+  // be resolved.
+  for (auto i : weakExternal)
+    undefines.erase(i.second);
+
+  // Create atoms for the undefined symbols.
+  for (const coff_symbol *sym : undefines) {
+    // If the symbol has sym2, create an undefiend atom for sym2, so that we
+    // can pass it as a fallback atom.
+    UndefinedAtom *fallback = nullptr;
+    auto iter = weakExternal.find(sym);
+    if (iter != weakExternal.end()) {
+      const coff_symbol *sym2 = iter->second;
+      fallback = new (_alloc) COFFUndefinedAtom(*this, _symbolName[sym2]);
+      _symbolAtom[sym2] = fallback;
+    }
+
+    // Create an atom for the symbol.
+    auto *atom =
+        new (_alloc) COFFUndefinedAtom(*this, _symbolName[sym], fallback);
+    result.push_back(atom);
+    _symbolAtom[sym] = atom;
+  }
+  return error_code::success();
+}
 
-    // Sort out sym1s from sym2s. Sym2s shouldn't be added to the undefined atom
-    // list because they shouldn't be resolved unless sym1 is failed to
-    // be resolved.
-    for (auto i : weakExternal)
-      undefines.erase(i.second);
-
-    // Create atoms for the undefined symbols.
-    for (const coff_symbol *sym : undefines) {
-      // If the symbol has sym2, create an undefiend atom for sym2, so that we
-      // can pass it as a fallback atom.
-      UndefinedAtom *fallback = nullptr;
-      auto iter = weakExternal.find(sym);
-      if (iter != weakExternal.end()) {
-        const coff_symbol *sym2 = iter->second;
-        fallback = new (_alloc) COFFUndefinedAtom(*this, _symbolName[sym2]);
-        _symbolAtom[sym2] = fallback;
-      }
-
-      // Create an atom for the symbol.
-      auto *atom = new (_alloc) COFFUndefinedAtom(
-          *this, _symbolName[sym], fallback);
+/// Create atoms for the defined symbols. This pass is a bit complicated than
+/// the other two, because in order to create the atom for the defined symbol
+/// we need to know the adjacent symbols.
+error_code FileCOFF::createDefinedSymbols(const SymbolVectorT &symbols,
+                                          vector<const DefinedAtom *> &result) {
+  // A defined atom can be merged if its section attribute allows its contents
+  // to be merged. In COFF, it's not very easy to get the section attribute
+  // for the symbol, so scan all sections in advance and cache the attributes
+  // for later use.
+  if (error_code ec = cacheSectionAttributes())
+    return ec;
+
+  // Filter non-defined atoms, and group defined atoms by its section.
+  SectionToSymbolsT definedSymbols;
+  for (const coff_symbol *sym : symbols) {
+    // A symbol with section number 0 and non-zero value represents a common
+    // symbol. The MS COFF spec did not give a definition of what the common
+    // symbol is. We should probably follow ELF's definition shown below.
+    //
+    // - If one object file has a common symbol and another has a definition,
+    //   the common symbol is treated as an undefined reference.
+    // - If there is no definition for a common symbol, the program linker
+    //   acts as though it saw a definition initialized to zero of the
+    //   appropriate size.
+    // - Two object files may have common symbols of
+    //   different sizes, in which case the program linker will use the
+    //   largest size.
+    //
+    // FIXME: We are currently treating the common symbol as a normal
+    // mergeable atom. Implement the above semantcis.
+    if (sym->SectionNumber == llvm::COFF::IMAGE_SYM_UNDEFINED &&
+        sym->Value > 0) {
+      StringRef name = _symbolName[sym];
+      uint32_t size = sym->Value;
+      auto *atom = new (_alloc)
+          COFFBSSAtom(*this, name, getScope(sym), DefinedAtom::permRW_,
+                      DefinedAtom::mergeAsWeakAndAddressUsed, size, 0);
       result.push_back(atom);
-      _symbolAtom[sym] = atom;
+      continue;
     }
-    return error_code::success();
-  }
-
-  /// Create atoms for the defined symbols. This pass is a bit complicated than
-  /// the other two, because in order to create the atom for the defined symbol
-  /// we need to know the adjacent symbols.
-  error_code createDefinedSymbols(const SymbolVectorT &symbols,
-                                  vector<const DefinedAtom *> &result) {
-    // A defined atom can be merged if its section attribute allows its contents
-    // to be merged. In COFF, it's not very easy to get the section attribute
-    // for the symbol, so scan all sections in advance and cache the attributes
-    // for later use.
-    if (error_code ec = cacheSectionAttributes())
-      return ec;
-
-    // Filter non-defined atoms, and group defined atoms by its section.
-    SectionToSymbolsT definedSymbols;
-    for (const coff_symbol *sym : symbols) {
-      // A symbol with section number 0 and non-zero value represents a common
-      // symbol. The MS COFF spec did not give a definition of what the common
-      // symbol is. We should probably follow ELF's definition shown below.
-      //
-      // - If one object file has a common symbol and another has a definition,
-      //   the common symbol is treated as an undefined reference.
-      // - If there is no definition for a common symbol, the program linker
-      //   acts as though it saw a definition initialized to zero of the
-      //   appropriate size.
-      // - Two object files may have common symbols of
-      //   different sizes, in which case the program linker will use the
-      //   largest size.
-      //
-      // FIXME: We are currently treating the common symbol as a normal
-      // mergeable atom. Implement the above semantcis.
-      if (sym->SectionNumber == llvm::COFF::IMAGE_SYM_UNDEFINED &&
-          sym->Value > 0) {
-        StringRef name = _symbolName[sym];
-        uint32_t size = sym->Value;
-        auto *atom = new (_alloc)
-            COFFBSSAtom(*this, name, getScope(sym), DefinedAtom::permRW_,
-                        DefinedAtom::mergeAsWeakAndAddressUsed, size, 0);
-        result.push_back(atom);
-        continue;
-      }
-
-      // Skip if it's not for defined atom.
-      if (sym->SectionNumber == llvm::COFF::IMAGE_SYM_ABSOLUTE ||
-          sym->SectionNumber == llvm::COFF::IMAGE_SYM_UNDEFINED)
-        continue;
-
-      const coff_section *sec;
-      if (error_code ec = _obj->getSection(sym->SectionNumber, sec))
-        return ec;
-      assert(sec && "SectionIndex > 0, Sec must be non-null!");
-
-      // Skip if it's a section symbol for a COMDAT section. A section symbol
-      // has the name of the section and value 0. A translation unit may contain
-      // multiple COMDAT sections whose section name are the same. We don't want
-      // to make atoms for them as they would become duplicate symbols.
-      StringRef sectionName;
-      if (error_code ec = _obj->getSectionName(sec, sectionName))
-        return ec;
-      if (_symbolName[sym] == sectionName && sym->Value == 0 &&
-          _merge[sec] != DefinedAtom::mergeNo)
-        continue;
-
-      uint8_t sc = sym->StorageClass;
-      if (sc != llvm::COFF::IMAGE_SYM_CLASS_EXTERNAL &&
-          sc != llvm::COFF::IMAGE_SYM_CLASS_STATIC &&
-          sc != llvm::COFF::IMAGE_SYM_CLASS_FUNCTION &&
-          sc != llvm::COFF::IMAGE_SYM_CLASS_LABEL) {
-        llvm::errs() << "Unable to create atom for: " << _symbolName[sym]
-                     << " (" << static_cast<int>(sc) << ")\n";
-        return llvm::object::object_error::parse_failed;
-      }
 
-      definedSymbols[sec].push_back(sym);
-    }
+    // Skip if it's not for defined atom.
+    if (sym->SectionNumber == llvm::COFF::IMAGE_SYM_ABSOLUTE ||
+        sym->SectionNumber == llvm::COFF::IMAGE_SYM_UNDEFINED)
+      continue;
 
-    // Atomize the defined symbols.
-    if (error_code ec = AtomizeDefinedSymbols(definedSymbols, result))
+    const coff_section *sec;
+    if (error_code ec = _obj->getSection(sym->SectionNumber, sec))
       return ec;
+    assert(sec && "SectionIndex > 0, Sec must be non-null!");
 
-    return error_code::success();
-  }
-
-  // Cache the COMDAT attributes, which indicate whether the symbols in the
-  // section can be merged or not.
-  error_code cacheSectionAttributes() {
-    // The COMDAT section attribute is not an attribute of coff_section, but is
-    // stored in the auxiliary symbol for the first symbol referring a COMDAT
-    // section. It feels to me that it's unnecessarily complicated, but this is
-    // how COFF works.
-    for (auto i : _auxSymbol) {
-      const coff_symbol *sym = i.first;
-      if (sym->SectionNumber == llvm::COFF::IMAGE_SYM_ABSOLUTE ||
-          sym->SectionNumber == llvm::COFF::IMAGE_SYM_UNDEFINED)
-        continue;
-
-      const coff_section *sec;
-      if (error_code ec = _obj->getSection(sym->SectionNumber, sec))
-        return ec;
-
-      if (_merge.count(sec))
-        continue;
-      if (!(sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_COMDAT))
-        continue;
-
-      _comdatSections.insert(sec);
-
-      if (sym->NumberOfAuxSymbols == 0)
-        return llvm::object::object_error::parse_failed;
-      const coff_aux_section_definition *aux =
-          reinterpret_cast<const coff_aux_section_definition *>(i.second);
-      _merge[sec] = getMerge(aux);
-    }
-
-    // The sections that does not have auxiliary symbol are regular sections, in
-    // which symbols are not allowed to be merged.
-    error_code ec;
-    for (auto si = _obj->begin_sections(), se = _obj->end_sections(); si != se;
-         si.increment(ec)) {
-      const coff_section *sec = _obj->getCOFFSection(si);
-      if (!_merge.count(sec))
-        _merge[sec] = DefinedAtom::mergeNo;
-    }
-    return error_code::success();
-  }
-
-  /// Atomize \p symbols and append the results to \p atoms. The symbols are
-  /// assumed to have been defined in the \p section.
-  error_code
-  AtomizeDefinedSymbolsInSection(const coff_section *section,
-                                 vector<const coff_symbol *> &symbols,
-                                 vector<COFFDefinedFileAtom *> &atoms) {
-      // Sort symbols by position.
-    std::stable_sort(
-        symbols.begin(), symbols.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;
-    }));
-
+    // Skip if it's a section symbol for a COMDAT section. A section symbol
+    // has the name of the section and value 0. A translation unit may contain
+    // multiple COMDAT sections whose section name are the same. We don't want
+    // to make atoms for them as they would become duplicate symbols.
     StringRef sectionName;
-    if (error_code ec = _obj->getSectionName(section, sectionName))
+    if (error_code ec = _obj->getSectionName(sec, sectionName))
       return ec;
-    uint64_t ordinal = -1;
+    if (_symbolName[sym] == sectionName && sym->Value == 0 &&
+        _merge[sec] != DefinedAtom::mergeNo)
+      continue;
 
-    // BSS section does not have contents. If this is the BSS section, create
-    // COFFBSSAtom instead of COFFDefinedAtom.
-    if (section->Characteristics &
-        llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
-      for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
-        const coff_symbol *sym = *si;
-        uint32_t size = (si + 1 == se) ? section->SizeOfRawData - sym->Value
-                                       : si[1]->Value - sym->Value;
-        auto *atom = new (_alloc) COFFBSSAtom(
-            *this, _symbolName[sym], getScope(sym), getPermissions(section),
-            DefinedAtom::mergeAsWeakAndAddressUsed, size, ++ordinal);
-        atoms.push_back(atom);
-        _symbolAtom[sym] = atom;
-      }
-      return error_code::success();
+    uint8_t sc = sym->StorageClass;
+    if (sc != llvm::COFF::IMAGE_SYM_CLASS_EXTERNAL &&
+        sc != llvm::COFF::IMAGE_SYM_CLASS_STATIC &&
+        sc != llvm::COFF::IMAGE_SYM_CLASS_FUNCTION &&
+        sc != llvm::COFF::IMAGE_SYM_CLASS_LABEL) {
+      llvm::errs() << "Unable to create atom for: " << _symbolName[sym] << " ("
+                   << static_cast<int>(sc) << ")\n";
+      return llvm::object::object_error::parse_failed;
     }
 
-    ArrayRef<uint8_t> secData;
-    if (error_code ec = _obj->getSectionContents(section, secData))
-      return ec;
+    definedSymbols[sec].push_back(sym);
+  }
 
-    // We do not support debug information yet. We could keep data in ".debug$S"
-    // section in the resultant binary by copying as opaque bytes, but it would
-    // make the binary hard to debug because of extraneous data. So we'll skip
-    // the debug info.
-    if (sectionName == ".debug$S")
-      return error_code::success();
+  // Atomize the defined symbols.
+  if (error_code ec = AtomizeDefinedSymbols(definedSymbols, result))
+    return ec;
 
-    // A section with IMAGE_SCN_LNK_REMOVE attribute will never become
-    // a part of the output image. That's what the COFF spec says.
-    if (section->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
-      return error_code::success();
-
-    DefinedAtom::ContentType type = getContentType(section);
-    DefinedAtom::ContentPermissions perms = getPermissions(section);
-    bool isComdat = (_comdatSections.count(section) == 1);
-
-    // Create an atom for the entire section.
-    if (symbols.empty()) {
-      ArrayRef<uint8_t> data(secData.data(), secData.size());
-      auto *atom = new (_alloc)
-          COFFDefinedAtom(*this, "", sectionName, Atom::scopeTranslationUnit,
-                          type, isComdat, perms, _merge[section], data, 0);
-      atoms.push_back(atom);
-      _definedAtomLocations[section][0].push_back(atom);
-      return error_code::success();
-    }
+  return error_code::success();
+}
 
-    // Create an unnamed atom if the first atom isn't at the start of the
-    // section.
-    if (symbols[0]->Value != 0) {
-      uint64_t size = symbols[0]->Value;
-      ArrayRef<uint8_t> data(secData.data(), size);
-      auto *atom = new (_alloc) COFFDefinedAtom(
-          *this, "", sectionName, Atom::scopeTranslationUnit, type, isComdat,
-          perms, _merge[section], data, ++ordinal);
-      atoms.push_back(atom);
-      _definedAtomLocations[section][0].push_back(atom);
-    }
+// Cache the COMDAT attributes, which indicate whether the symbols in the
+// section can be merged or not.
+error_code FileCOFF::cacheSectionAttributes() {
+  // The COMDAT section attribute is not an attribute of coff_section, but is
+  // stored in the auxiliary symbol for the first symbol referring a COMDAT
+  // section. It feels to me that it's unnecessarily complicated, but this is
+  // how COFF works.
+  for (auto i : _auxSymbol) {
+    const coff_symbol *sym = i.first;
+    if (sym->SectionNumber == llvm::COFF::IMAGE_SYM_ABSOLUTE ||
+        sym->SectionNumber == llvm::COFF::IMAGE_SYM_UNDEFINED)
+      continue;
+
+    const coff_section *sec;
+    if (error_code ec = _obj->getSection(sym->SectionNumber, sec))
+      return ec;
+
+    if (_merge.count(sec))
+      continue;
+    if (!(sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_COMDAT))
+      continue;
+
+    _comdatSections.insert(sec);
+
+    if (sym->NumberOfAuxSymbols == 0)
+      return llvm::object::object_error::parse_failed;
+    const coff_aux_section_definition *aux =
+        reinterpret_cast<const coff_aux_section_definition *>(i.second);
+    _merge[sec] = getMerge(aux);
+  }
+
+  // The sections that does not have auxiliary symbol are regular sections, in
+  // which symbols are not allowed to be merged.
+  error_code ec;
+  for (auto si = _obj->begin_sections(), se = _obj->end_sections(); si != se;
+       si.increment(ec)) {
+    const coff_section *sec = _obj->getCOFFSection(si);
+    if (!_merge.count(sec))
+      _merge[sec] = DefinedAtom::mergeNo;
+  }
+  return error_code::success();
+}
 
+/// Atomize \p symbols and append the results to \p atoms. The symbols are
+/// assumed to have been defined in the \p section.
+error_code
+FileCOFF::AtomizeDefinedSymbolsInSection(const coff_section *section,
+                                         vector<const coff_symbol *> &symbols,
+                                         vector<COFFDefinedFileAtom *> &atoms) {
+  // Sort symbols by position.
+  std::stable_sort(
+      symbols.begin(), symbols.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; }));
+
+  StringRef sectionName;
+  if (error_code ec = _obj->getSectionName(section, sectionName))
+    return ec;
+  uint64_t ordinal = -1;
+
+  // BSS section does not have contents. If this is the BSS section, create
+  // COFFBSSAtom instead of COFFDefinedAtom.
+  if (section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
     for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
-      const uint8_t *start = secData.data() + (*si)->Value;
-      // if this is the last symbol, take up the remaining data.
-      const uint8_t *end = (si + 1 == se) ? secData.data() + secData.size()
-                                          : secData.data() + (*(si + 1))->Value;
-      ArrayRef<uint8_t> data(start, end);
-      auto *atom = new (_alloc) COFFDefinedAtom(
-          *this, _symbolName[*si], sectionName, getScope(*si), type, isComdat,
-          perms, _merge[section], data, ++ordinal);
+      const coff_symbol *sym = *si;
+      uint32_t size = (si + 1 == se) ? section->SizeOfRawData - sym->Value
+                                     : si[1]->Value - sym->Value;
+      auto *atom = new (_alloc) COFFBSSAtom(
+          *this, _symbolName[sym], getScope(sym), getPermissions(section),
+          DefinedAtom::mergeAsWeakAndAddressUsed, size, ++ordinal);
       atoms.push_back(atom);
-      _symbolAtom[*si] = atom;
-      _definedAtomLocations[section][(*si)->Value].push_back(atom);
-    }
-
-    // Finally, set alignment to the first atom so that the section contents
-    // will be aligned as specified by the object section header.
-    _definedAtomLocations[section][0][0]->setAlignment(getAlignment(section));
-    return error_code::success();
-  }
-
-  error_code AtomizeDefinedSymbols(SectionToSymbolsT &definedSymbols,
-                                   vector<const DefinedAtom *> &definedAtoms) {
-    // For each section, make atoms for all the symbols defined in the
-    // section, and append the atoms to the result objects.
-    for (auto &i : definedSymbols) {
-      const coff_section *section = i.first;
-      vector<const coff_symbol *> &symbols = i.second;
-      vector<COFFDefinedFileAtom *> atoms;
-      if (error_code ec =
-              AtomizeDefinedSymbolsInSection(section, symbols, atoms))
-        return ec;
-
-      // Connect atoms with layout-before/layout-after edges.
-      connectAtomsWithLayoutEdge(atoms);
-
-      for (COFFDefinedFileAtom *atom : atoms) {
-        _sectionAtoms[section].push_back(atom);
-        definedAtoms.push_back(atom);
-      }
+      _symbolAtom[sym] = atom;
     }
     return error_code::success();
   }
 
-  /// Find the atom that is at \p targetAddress in \p section.
-  error_code findAtomAt(const coff_section *section, uint32_t targetAddress,
-                        COFFDefinedFileAtom *&result, uint32_t &offsetInAtom) {
-    for (auto i : _definedAtomLocations[section]) {
-      uint32_t atomAddress = i.first;
-      std::vector<COFFDefinedAtom *> &atomsAtSameLocation = i.second;
-      COFFDefinedAtom *atom = atomsAtSameLocation.back();
-      if (atomAddress <= targetAddress &&
-          targetAddress < atomAddress + atom->size()) {
-        result = atom;
-        offsetInAtom = targetAddress - atomAddress;
-        return error_code::success();
-      }
-    }
-    // Relocation target is out of range
-    return llvm::object::object_error::parse_failed;
-  }
-
-  /// Find the atom for the symbol that was at the \p index in the symbol
-  /// table.
-  error_code getAtomBySymbolIndex(uint32_t index, Atom *&ret) {
-    const coff_symbol *symbol;
-    if (error_code ec = _obj->getSymbol(index, symbol))
-      return ec;
-    ret = _symbolAtom[symbol];
-    assert(ret);
+  ArrayRef<uint8_t> secData;
+  if (error_code ec = _obj->getSectionContents(section, secData))
+    return ec;
+
+  // We do not support debug information yet. We could keep data in ".debug$S"
+  // section in the resultant binary by copying as opaque bytes, but it would
+  // make the binary hard to debug because of extraneous data. So we'll skip
+  // the debug info.
+  if (sectionName == ".debug$S")
+    return error_code::success();
+
+  // A section with IMAGE_SCN_LNK_REMOVE attribute will never become
+  // a part of the output image. That's what the COFF spec says.
+  if (section->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
+    return error_code::success();
+
+  DefinedAtom::ContentType type = getContentType(section);
+  DefinedAtom::ContentPermissions perms = getPermissions(section);
+  bool isComdat = (_comdatSections.count(section) == 1);
+
+  // Create an atom for the entire section.
+  if (symbols.empty()) {
+    ArrayRef<uint8_t> data(secData.data(), secData.size());
+    auto *atom = new (_alloc)
+        COFFDefinedAtom(*this, "", sectionName, Atom::scopeTranslationUnit,
+                        type, isComdat, perms, _merge[section], data, 0);
+    atoms.push_back(atom);
+    _definedAtomLocations[section][0].push_back(atom);
     return error_code::success();
   }
 
-  /// Add relocation information to an atom based on \p rel. \p rel is an
-  /// relocation entry for the \p section, and \p atoms are all the atoms
-  /// defined in the \p section.
-  error_code
-  addRelocationReference(const coff_relocation *rel,
-                         const coff_section *section,
-                         const vector<COFFDefinedFileAtom *> &atoms) {
-    assert(atoms.size() > 0);
-    // The address of the item which relocation is applied. Section's
-    // VirtualAddress needs to be added for historical reasons, but the value
-    // is usually just zero, so adding it is usually no-op.
-    uint32_t itemAddress = rel->VirtualAddress + section->VirtualAddress;
-
-    Atom *targetAtom = nullptr;
-    if (error_code ec = getAtomBySymbolIndex(rel->SymbolTableIndex, targetAtom))
-      return ec;
-
-    COFFDefinedFileAtom *atom;
-    uint32_t offsetInAtom;
-    if (error_code ec = findAtomAt(section, itemAddress, atom, offsetInAtom))
-      return ec;
-    atom->addReference(std::unique_ptr<COFFReference>(
-        new COFFReference(targetAtom, offsetInAtom, rel->Type)));
-    return error_code::success();
-  }
+  // Create an unnamed atom if the first atom isn't at the start of the
+  // section.
+  if (symbols[0]->Value != 0) {
+    uint64_t size = symbols[0]->Value;
+    ArrayRef<uint8_t> data(secData.data(), size);
+    auto *atom = new (_alloc) COFFDefinedAtom(
+        *this, "", sectionName, Atom::scopeTranslationUnit, type, isComdat,
+        perms, _merge[section], data, ++ordinal);
+    atoms.push_back(atom);
+    _definedAtomLocations[section][0].push_back(atom);
+  }
+
+  for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
+    const uint8_t *start = secData.data() + (*si)->Value;
+    // if this is the last symbol, take up the remaining data.
+    const uint8_t *end = (si + 1 == se) ? secData.data() + secData.size()
+                                        : secData.data() + (*(si + 1))->Value;
+    ArrayRef<uint8_t> data(start, end);
+    auto *atom = new (_alloc) COFFDefinedAtom(
+        *this, _symbolName[*si], sectionName, getScope(*si), type, isComdat,
+        perms, _merge[section], data, ++ordinal);
+    atoms.push_back(atom);
+    _symbolAtom[*si] = atom;
+    _definedAtomLocations[section][(*si)->Value].push_back(atom);
+  }
+
+  // Finally, set alignment to the first atom so that the section contents
+  // will be aligned as specified by the object section header.
+  _definedAtomLocations[section][0][0]->setAlignment(getAlignment(section));
+  return error_code::success();
+}
 
-  /// Add relocation information to atoms.
-  error_code addRelocationReferenceToAtoms() {
-    // Relocation entries are defined for each section.
-    error_code ec;
-    for (auto si = _obj->begin_sections(), se = _obj->end_sections(); si != se;
-         si.increment(ec)) {
-      const coff_section *section = _obj->getCOFFSection(si);
-
-      // Skip there's no atom for the section. Currently we do not create any
-      // atoms for some sections, such as "debug$S", and such sections need to
-      // be skipped here too.
-      if (_sectionAtoms.find(section) == _sectionAtoms.end())
-        continue;
-
-      for (auto ri = si->begin_relocations(), re = si->end_relocations();
-           ri != re; ri.increment(ec)) {
-        const coff_relocation *rel = _obj->getCOFFRelocation(ri);
-        if ((ec = addRelocationReference(rel, section, _sectionAtoms[section])))
-          return ec;
-      }
+error_code
+FileCOFF::AtomizeDefinedSymbols(SectionToSymbolsT &definedSymbols,
+                                vector<const DefinedAtom *> &definedAtoms) {
+  // For each section, make atoms for all the symbols defined in the
+  // section, and append the atoms to the result objects.
+  for (auto &i : definedSymbols) {
+    const coff_section *section = i.first;
+    vector<const coff_symbol *> &symbols = i.second;
+    vector<COFFDefinedFileAtom *> atoms;
+    if (error_code ec = AtomizeDefinedSymbolsInSection(section, symbols, atoms))
+      return ec;
+
+    // Connect atoms with layout-before/layout-after edges.
+    connectAtomsWithLayoutEdge(atoms);
+
+    for (COFFDefinedFileAtom *atom : atoms) {
+      _sectionAtoms[section].push_back(atom);
+      definedAtoms.push_back(atom);
     }
-    return error_code::success();
   }
+  return error_code::success();
+}
 
-  /// Find a section by name.
-  error_code findSection(StringRef name, const coff_section *&result) {
-    error_code ec;
-    for (auto si = _obj->begin_sections(), se = _obj->end_sections(); si != se;
-         si.increment(ec)) {
-      const coff_section *section = _obj->getCOFFSection(si);
-      StringRef sectionName;
-      if ((ec = _obj->getSectionName(section, sectionName)))
-        return ec;
-      if (sectionName == name) {
-        result = section;
-        return error_code::success();
-      }
+/// Find the atom that is at \p targetAddress in \p section.
+error_code FileCOFF::findAtomAt(const coff_section *section,
+                                uint32_t targetAddress,
+                                COFFDefinedFileAtom *&result,
+                                uint32_t &offsetInAtom) {
+  for (auto i : _definedAtomLocations[section]) {
+    uint32_t atomAddress = i.first;
+    std::vector<COFFDefinedAtom *> &atomsAtSameLocation = i.second;
+    COFFDefinedAtom *atom = atomsAtSameLocation.back();
+    if (atomAddress <= targetAddress &&
+        targetAddress < atomAddress + atom->size()) {
+      result = atom;
+      offsetInAtom = targetAddress - atomAddress;
+      return error_code::success();
     }
-    // Section was not found, but it's not an error. This method returns an
-    // error
-    // only when there's a read error.
-    return error_code::success();
   }
+  // Relocation target is out of range
+  return llvm::object::object_error::parse_failed;
+}
 
-  // Convert ArrayRef<uint8_t> to std::string. The array contains a string which
-  // may not be terminated by NUL.
-  std::string ArrayRefToString(ArrayRef<uint8_t> array) {
-    // Skip the UTF-8 byte marker if exists. The contents of .drectve section
-    // is, according to the Microsoft PE/COFF spec, encoded as ANSI or UTF-8
-    // with the BOM marker.
-    //
-    // FIXME: I think "ANSI" in the spec means Windows-1252 encoding, which is a
-    // superset of ASCII. We need to convert it to UTF-8.
-    if (array.size() >= 3 && array[0] == 0xEF && array[1] == 0xBB &&
-        array[2] == 0xBF) {
-      array = array.slice(3);
-    }
-
-    if (array.empty())
-      return "";
+/// Find the atom for the symbol that was at the \p index in the symbol
+/// table.
+error_code FileCOFF::getAtomBySymbolIndex(uint32_t index, Atom *&ret) {
+  const coff_symbol *symbol;
+  if (error_code ec = _obj->getSymbol(index, symbol))
+    return ec;
+  ret = _symbolAtom[symbol];
+  assert(ret);
+  return error_code::success();
+}
 
-    size_t len = 0;
-    size_t e = array.size();
-    while (len < e && array[len] != '\0')
-      ++len;
-    return std::string(reinterpret_cast<const char *>(&array[0]), len);
-  }
+/// Add relocation information to an atom based on \p rel. \p rel is an
+/// relocation entry for the \p section, and \p atoms are all the atoms
+/// defined in the \p section.
+error_code
+FileCOFF::addRelocationReference(const coff_relocation *rel,
+                                 const coff_section *section,
+                                 const vector<COFFDefinedFileAtom *> &atoms) {
+  assert(atoms.size() > 0);
+  // The address of the item which relocation is applied. Section's
+  // VirtualAddress needs to be added for historical reasons, but the value
+  // is usually just zero, so adding it is usually no-op.
+  uint32_t itemAddress = rel->VirtualAddress + section->VirtualAddress;
+
+  Atom *targetAtom = nullptr;
+  if (error_code ec = getAtomBySymbolIndex(rel->SymbolTableIndex, targetAtom))
+    return ec;
+
+  COFFDefinedFileAtom *atom;
+  uint32_t offsetInAtom;
+  if (error_code ec = findAtomAt(section, itemAddress, atom, offsetInAtom))
+    return ec;
+  atom->addReference(std::unique_ptr<COFFReference>(
+      new COFFReference(targetAtom, offsetInAtom, rel->Type)));
+  return error_code::success();
+}
 
-  // Read .drectve section contents if exists, and store it to _directives.
-  error_code maybeReadLinkerDirectives() {
-    const coff_section *section = nullptr;
-    if (error_code ec = findSection(".drectve", section))
-      return ec;
-    if (section != nullptr) {
-      ArrayRef<uint8_t> contents;
-      if (error_code ec = _obj->getSectionContents(section, contents))
+/// Add relocation information to atoms.
+error_code FileCOFF::addRelocationReferenceToAtoms() {
+  // Relocation entries are defined for each section.
+  error_code ec;
+  for (auto si = _obj->begin_sections(), se = _obj->end_sections(); si != se;
+       si.increment(ec)) {
+    const coff_section *section = _obj->getCOFFSection(si);
+
+    // Skip there's no atom for the section. Currently we do not create any
+    // atoms for some sections, such as "debug$S", and such sections need to
+    // be skipped here too.
+    if (_sectionAtoms.find(section) == _sectionAtoms.end())
+      continue;
+
+    for (auto ri = si->begin_relocations(), re = si->end_relocations();
+         ri != re; ri.increment(ec)) {
+      const coff_relocation *rel = _obj->getCOFFRelocation(ri);
+      if ((ec = addRelocationReference(rel, section, _sectionAtoms[section])))
         return ec;
-      _directives = std::move(ArrayRefToString(contents));
     }
-    return error_code::success();
   }
+  return error_code::success();
+}
 
-  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;
-
-  // The contents of .drectve section.
-  std::string _directives;
-
-  // A map from symbol to its name. All symbols should be in this map except
-  // unnamed ones.
-  std::map<const coff_symbol *, StringRef> _symbolName;
-
-  // A map from symbol to its resultant atom.
-  std::map<const coff_symbol *, Atom *> _symbolAtom;
-
-  // A map from symbol to its aux symbol.
-  std::map<const coff_symbol *, const coff_symbol *> _auxSymbol;
-
-  // A map from section to its atoms.
-  std::map<const coff_section *, vector<COFFDefinedFileAtom *> > _sectionAtoms;
-
-  // A set of COMDAT sections.
-  std::set<const coff_section *> _comdatSections;
-
-  // A map to get whether the section allows its contents to be merged or not.
-  std::map<const coff_section *, DefinedAtom::Merge> _merge;
-
-  // A sorted map to find an atom from a section and an offset within
-  // the section.
-  std::map<const coff_section *,
-           std::map<uint32_t, std::vector<COFFDefinedAtom *> > >
-  _definedAtomLocations;
-
-  mutable llvm::BumpPtrAllocator _alloc;
-  const LinkingContext &_context;
-};
-
-class BumpPtrStringSaver : public llvm::cl::StringSaver {
-public:
-  virtual const char *SaveString(const char *str) {
-    size_t len = strlen(str);
-    char *copy = _alloc.Allocate<char>(len + 1);
-    memcpy(copy, str, len + 1);
-    return copy;
-  }
-
-private:
-  llvm::BumpPtrAllocator _alloc;
-};
-
-class ReaderCOFF : public Reader {
-public:
-  explicit ReaderCOFF(PECOFFLinkingContext &context)
-      : Reader(context), _PECOFFLinkingContext(context) {}
-
-  error_code parseFile(std::unique_ptr<MemoryBuffer> &mb,
-                       std::vector<std::unique_ptr<File> > &result) const {
-    StringRef magic(mb->getBufferStart(), mb->getBufferSize());
-
-    // The input file should be a resource file, an archive file, a regular COFF
-    // file, or an import library member file. Try to parse in that order. If
-    // the input file does not start with a known magic, parseCOFFImportLibrary
-    // will return an error object.
-    llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(magic);
-
-    if (fileType == llvm::sys::fs::file_magic::windows_resource)
-      return convertAndParseResourceFile(mb, result);
-    if (fileType == llvm::sys::fs::file_magic::coff_import_library)
-      return lld::coff::parseCOFFImportLibrary(_context, mb, result);
-    return parseCOFFFile(mb, result);
+/// Find a section by name.
+error_code FileCOFF::findSection(StringRef name, const coff_section *&result) {
+  error_code ec;
+  for (auto si = _obj->begin_sections(), se = _obj->end_sections(); si != se;
+       si.increment(ec)) {
+    const coff_section *section = _obj->getCOFFSection(si);
+    StringRef sectionName;
+    if ((ec = _obj->getSectionName(section, sectionName)))
+      return ec;
+    if (sectionName == name) {
+      result = section;
+      return error_code::success();
+    }
   }
+  // Section was not found, but it's not an error. This method returns an
+  // error
+  // only when there's a read error.
+  return error_code::success();
+}
 
-private:
-  // Interpret the contents of .drectve section. If exists, the section contains
-  // a string containing command line options. The linker is expected to
-  // interpret the options as if they were given via the command line.
+// Convert ArrayRef<uint8_t> to std::string. The array contains a string which
+// may not be terminated by NUL.
+std::string FileCOFF::ArrayRefToString(ArrayRef<uint8_t> array) {
+  // Skip the UTF-8 byte marker if exists. The contents of .drectve section
+  // is, according to the Microsoft PE/COFF spec, encoded as ANSI or UTF-8
+  // with the BOM marker.
   //
-  // The section mainly contains /defaultlib (-l in Unix), but can contain any
-  // options as long as they are valid.
-  error_code handleDirectiveSection(StringRef directives) const {
-    DEBUG({
-      llvm::dbgs() << ".drectve: " << directives << "\n";
-    });
-
-    // Split the string into tokens, as the shell would do for argv.
-    SmallVector<const char *, 16> tokens;
-    tokens.push_back("link"); // argv[0] is the command name. Will be ignored.
-    llvm::cl::TokenizeWindowsCommandLine(directives, _stringSaver, tokens);
-    tokens.push_back(nullptr);
-
-    // Calls the command line parser to interpret the token string as if they
-    // were given via the command line.
-    int argc = tokens.size() - 1;
-    const char **argv = &tokens[0];
-    std::string errorMessage;
-    llvm::raw_string_ostream stream(errorMessage);
-    bool parseFailed = !WinLinkDriver::parse(argc, argv, _PECOFFLinkingContext,
-                                             stream, /*isDirective*/ true);
-    stream.flush();
-
-    // Print error message if error.
-    if (parseFailed) {
-      llvm::errs() << "Failed to parse '" << directives << "'\n";
-      return make_error_code(llvm::object::object_error::invalid_file_type);
-    }
-    if (!errorMessage.empty()) {
-      llvm::errs() << "lld warning: " << errorMessage << "\n";
-    }
-    return error_code::success();
+  // FIXME: I think "ANSI" in the spec means Windows-1252 encoding, which is a
+  // superset of ASCII. We need to convert it to UTF-8.
+  if (array.size() >= 3 && array[0] == 0xEF && array[1] == 0xBB &&
+      array[2] == 0xBF) {
+    array = array.slice(3);
   }
 
-  //
-  // RC file Reader
-  //
+  if (array.empty())
+    return "";
+
+  size_t len = 0;
+  size_t e = array.size();
+  while (len < e && array[len] != '\0')
+    ++len;
+  return std::string(reinterpret_cast<const char *>(&array[0]), len);
+}
 
-  ErrorOr<std::string>
-  writeResToTemporaryFile(std::unique_ptr<MemoryBuffer> mb) const {
-    // Get a temporary file path for .res file.
-    SmallString<128> tempFilePath;
-    if (error_code ec = llvm::sys::fs::createTemporaryFile(
-            "tmp", "res", tempFilePath))
+// Read .drectve section contents if exists, and store it to _directives.
+error_code FileCOFF::maybeReadLinkerDirectives() {
+  const coff_section *section = nullptr;
+  if (error_code ec = findSection(".drectve", section))
+    return ec;
+  if (section != nullptr) {
+    ArrayRef<uint8_t> contents;
+    if (error_code ec = _obj->getSectionContents(section, contents))
       return ec;
+    _directives = std::move(ArrayRefToString(contents));
+  }
+  return error_code::success();
+}
 
-    // Write the memory buffer contents to .res file, so that we can run
-    // cvtres.exe on it.
-    OwningPtr<llvm::FileOutputBuffer> buffer;
-    if (error_code ec = llvm::FileOutputBuffer::create(
-            tempFilePath.str(), mb->getBufferSize(), buffer))
-      return ec;
-    memcpy(buffer->getBufferStart(), mb->getBufferStart(), mb->getBufferSize());
-    if (error_code ec = buffer->commit())
-      return ec;
+error_code
+ReaderCOFF::parseFile(std::unique_ptr<MemoryBuffer> &mb,
+                      std::vector<std::unique_ptr<File> > &result) const {
+  StringRef magic(mb->getBufferStart(), mb->getBufferSize());
+
+  // The input file should be a resource file, an archive file, a regular COFF
+  // file, or an import library member file. Try to parse in that order. If
+  // the input file does not start with a known magic, parseCOFFImportLibrary
+  // will return an error object.
+  llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(magic);
+
+  if (fileType == llvm::sys::fs::file_magic::windows_resource)
+    return convertAndParseResourceFile(mb, result);
+  if (fileType == llvm::sys::fs::file_magic::coff_import_library)
+    return lld::coff::parseCOFFImportLibrary(_context, mb, result);
+  return parseCOFFFile(mb, result);
+}
 
-    // Convert SmallString -> StringRef -> std::string.
-    return tempFilePath.str().str();
+// Interpret the contents of .drectve section. If exists, the section contains
+// a string containing command line options. The linker is expected to
+// interpret the options as if they were given via the command line.
+//
+// The section mainly contains /defaultlib (-l in Unix), but can contain any
+// options as long as they are valid.
+error_code ReaderCOFF::handleDirectiveSection(StringRef directives) const {
+  DEBUG(llvm::dbgs() << ".drectve: " << directives << "\n");
+
+  // Split the string into tokens, as the shell would do for argv.
+  SmallVector<const char *, 16> tokens;
+  tokens.push_back("link"); // argv[0] is the command name. Will be ignored.
+  llvm::cl::TokenizeWindowsCommandLine(directives, _stringSaver, tokens);
+  tokens.push_back(nullptr);
+
+  // Calls the command line parser to interpret the token string as if they
+  // were given via the command line.
+  int argc = tokens.size() - 1;
+  const char **argv = &tokens[0];
+  std::string errorMessage;
+  llvm::raw_string_ostream stream(errorMessage);
+  bool parseFailed = !WinLinkDriver::parse(argc, argv, _PECOFFLinkingContext,
+                                           stream, /*isDirective*/ true);
+  stream.flush();
+
+  // Print error message if error.
+  if (parseFailed) {
+    llvm::errs() << "Failed to parse '" << directives << "'\n";
+    return make_error_code(llvm::object::object_error::invalid_file_type);
+  }
+  if (!errorMessage.empty()) {
+    llvm::errs() << "lld warning: " << errorMessage << "\n";
   }
+  return error_code::success();
+}
 
-  ErrorOr<std::string>
-  convertResourceFileToCOFF(std::unique_ptr<MemoryBuffer> mb) const {
-    // Write the resource file to a temporary file.
-    ErrorOr<std::string> inFilePath = writeResToTemporaryFile(std::move(mb));
-    if (!inFilePath)
-      return error_code(inFilePath);
-    llvm::FileRemover inFileRemover(*inFilePath);
-
-    // Create an output file path.
-    SmallString<128> outFilePath;
-    if (error_code ec = llvm::sys::fs::createTemporaryFile(
-            "tmp", "obj", outFilePath))
-      return ec;
-    std::string outFileArg = ("/out:" + outFilePath).str();
+ErrorOr<std::string>
+ReaderCOFF::writeResToTemporaryFile(std::unique_ptr<MemoryBuffer> mb) const {
+  // Get a temporary file path for .res file.
+  SmallString<128> tempFilePath;
+  if (error_code ec =
+          llvm::sys::fs::createTemporaryFile("tmp", "res", tempFilePath))
+    return ec;
+
+  // Write the memory buffer contents to .res file, so that we can run
+  // cvtres.exe on it.
+  OwningPtr<llvm::FileOutputBuffer> buffer;
+  if (error_code ec = llvm::FileOutputBuffer::create(
+          tempFilePath.str(), mb->getBufferSize(), buffer))
+    return ec;
+  memcpy(buffer->getBufferStart(), mb->getBufferStart(), mb->getBufferSize());
+  if (error_code ec = buffer->commit())
+    return ec;
 
-    // Construct CVTRES.EXE command line and execute it.
-    std::string program = "cvtres.exe";
-    std::string programPath = llvm::sys::FindProgramByName(program);
-    if (programPath.empty()) {
-      llvm::errs() << "Unable to find " << program << " in PATH\n";
-      return llvm::errc::broken_pipe;
-    }
-    std::vector<const char *> args;
-    args.push_back(programPath.c_str());
-    args.push_back("/machine:x86");
-    args.push_back("/readonly");
-    args.push_back("/nologo");
-    args.push_back(outFileArg.c_str());
-    args.push_back(inFilePath->c_str());
-    args.push_back(nullptr);
-
-    DEBUG({
-      for (const char **p = &args[0]; *p; ++p)
-        llvm::dbgs() << *p << " ";
-      llvm::dbgs() << "\n";
-    });
-
-    if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) {
-      llvm::errs() << program << " failed\n";
-      return llvm::errc::broken_pipe;
-    }
-    return outFilePath.str().str();
-  }
+  // Convert SmallString -> StringRef -> std::string.
+  return tempFilePath.str().str();
+}
 
-  // Convert .res file to .coff file and then parse it. Resource file is a file
-  // containing various types of data, such as icons, translation texts,
-  // etc. "cvtres.exe" command reads an RC file to create a COFF file which
-  // encapsulates resource data into rsrc$N sections, where N is an integer.
-  //
-  // The linker is not capable to handle RC files directly. Instead, it runs
-  // cvtres.exe on RC files and then then link its outputs.
-  error_code
-  convertAndParseResourceFile(
-      std::unique_ptr<MemoryBuffer> &mb,
-      std::vector<std::unique_ptr<File> > &result) const {
-    // Convert an RC to a COFF
-    ErrorOr<std::string> coffFilePath = convertResourceFileToCOFF(std::move(mb));
-    if (!coffFilePath)
-      return error_code(coffFilePath);
-    llvm::FileRemover coffFileRemover(*coffFilePath);
-
-    // Read and parse the COFF
-    OwningPtr<MemoryBuffer> opmb;
-    if (error_code ec = MemoryBuffer::getFile(*coffFilePath, opmb))
-      return ec;
-    std::unique_ptr<MemoryBuffer> newmb(opmb.take());
-    return parseCOFFFile(newmb, result);
+ErrorOr<std::string>
+ReaderCOFF::convertResourceFileToCOFF(std::unique_ptr<MemoryBuffer> mb) const {
+  // Write the resource file to a temporary file.
+  ErrorOr<std::string> inFilePath = writeResToTemporaryFile(std::move(mb));
+  if (!inFilePath)
+    return error_code(inFilePath);
+  llvm::FileRemover inFileRemover(*inFilePath);
+
+  // Create an output file path.
+  SmallString<128> outFilePath;
+  if (error_code ec =
+          llvm::sys::fs::createTemporaryFile("tmp", "obj", outFilePath))
+    return ec;
+  std::string outFileArg = ("/out:" + outFilePath).str();
+
+  // Construct CVTRES.EXE command line and execute it.
+  std::string program = "cvtres.exe";
+  std::string programPath = llvm::sys::FindProgramByName(program);
+  if (programPath.empty()) {
+    llvm::errs() << "Unable to find " << program << " in PATH\n";
+    return llvm::errc::broken_pipe;
+  }
+  std::vector<const char *> args;
+  args.push_back(programPath.c_str());
+  args.push_back("/machine:x86");
+  args.push_back("/readonly");
+  args.push_back("/nologo");
+  args.push_back(outFileArg.c_str());
+  args.push_back(inFilePath->c_str());
+  args.push_back(nullptr);
+
+  DEBUG({
+    for (const char **p = &args[0]; *p; ++p)
+      llvm::dbgs() << *p << " ";
+    llvm::dbgs() << "\n";
+  });
+
+  if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) {
+    llvm::errs() << program << " failed\n";
+    return llvm::errc::broken_pipe;
   }
+  return outFilePath.str().str();
+}
 
-  //
-  // COFF file Reader
-  //
+// Convert .res file to .coff file and then parse it. Resource file is a file
+// containing various types of data, such as icons, translation texts,
+// etc. "cvtres.exe" command reads an RC file to create a COFF file which
+// encapsulates resource data into rsrc$N sections, where N is an integer.
+//
+// The linker is not capable to handle RC files directly. Instead, it runs
+// cvtres.exe on RC files and then then link its outputs.
+error_code ReaderCOFF::convertAndParseResourceFile(
+    std::unique_ptr<MemoryBuffer> &mb,
+    std::vector<std::unique_ptr<File> > &result) const {
+  // Convert an RC to a COFF
+  ErrorOr<std::string> coffFilePath = convertResourceFileToCOFF(std::move(mb));
+  if (!coffFilePath)
+    return error_code(coffFilePath);
+  llvm::FileRemover coffFileRemover(*coffFilePath);
+
+  // Read and parse the COFF
+  OwningPtr<MemoryBuffer> opmb;
+  if (error_code ec = MemoryBuffer::getFile(*coffFilePath, opmb))
+    return ec;
+  std::unique_ptr<MemoryBuffer> newmb(opmb.take());
+  return parseCOFFFile(newmb, result);
+}
 
-  error_code parseCOFFFile(std::unique_ptr<MemoryBuffer> &mb,
-                           std::vector<std::unique_ptr<File> > &result) const {
-    // Parse the memory buffer as PECOFF file.
-    error_code ec;
-    std::unique_ptr<FileCOFF> file(new FileCOFF(_context, std::move(mb), ec));
-    if (ec)
+error_code
+ReaderCOFF::parseCOFFFile(std::unique_ptr<MemoryBuffer> &mb,
+                          std::vector<std::unique_ptr<File> > &result) const {
+  // Parse the memory buffer as PECOFF file.
+  error_code ec;
+  std::unique_ptr<FileCOFF> file(new FileCOFF(_context, std::move(mb), ec));
+  if (ec)
+    return ec;
+
+  DEBUG({
+    llvm::dbgs() << "Defined atoms:\n";
+    for (const auto &atom : file->defined()) {
+      llvm::dbgs() << "  " << atom->name() << "\n";
+      for (const Reference *ref : *atom)
+        llvm::dbgs() << "    @" << ref->offsetInAtom() << " -> "
+                     << ref->target()->name() << "\n";
+    }
+  });
+
+  // Interpret .drectve section if the section has contents.
+  StringRef directives = file->getLinkerDirectives();
+  if (!directives.empty())
+    if (error_code ec = handleDirectiveSection(directives))
       return ec;
 
-    DEBUG({
-      llvm::dbgs() << "Defined atoms:\n";
-      for (const auto &atom : file->defined()) {
-        llvm::dbgs() << "  " << atom->name() << "\n";
-        for (const Reference *ref : *atom)
-          llvm::dbgs() << "    @" << ref->offsetInAtom() << " -> "
-                       << ref->target()->name() << "\n";
-      }
-    });
-
-    // Interpret .drectve section if the section has contents.
-    StringRef directives = file->getLinkerDirectives();
-    if (!directives.empty())
-      if (error_code ec = handleDirectiveSection(directives))
-        return ec;
-
-    result.push_back(std::move(file));
-    return error_code::success();
-  }
-
-  PECOFFLinkingContext &_PECOFFLinkingContext;
-  mutable BumpPtrStringSaver _stringSaver;
-};
+  result.push_back(std::move(file));
+  return error_code::success();
+}
 
 } // end namespace anonymous
 





More information about the llvm-commits mailing list