Sources now require C++11 to build.

Add first linker pass (StubsPass) which looks for calls to shared library
symbols and replaces them with calls to a StubAtom.  On ELF system, a "stub"
is a PLT entry.  Added a simple test case.

Pass a Platform object to YAML reader and writer for converting fixup kinds 
between names and values.

Change output of Resolver to be a File object instead of a vector of Atoms.
Thus, passes operate on a File instead of just Atoms.

Rework how to walk through a File's Atoms. Now iterator based instead of 
a method that visits each atom.  

llvm-svn: 152269
diff --git a/lld/lib/Core/YamlWriter.cpp b/lld/lib/Core/YamlWriter.cpp
index c3a7f23..f844066 100644
--- a/lld/lib/Core/YamlWriter.cpp
+++ b/lld/lib/Core/YamlWriter.cpp
@@ -14,6 +14,8 @@
 #include "lld/Core/File.h"
 #include "lld/Core/Reference.h"
 
+#include "lld/Platform/Platform.h"
+
 #include "llvm/ADT/OwningPtr.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringExtras.h"
@@ -41,44 +43,50 @@
 /// In that case referencing the function by name is ambiguous, so a unique
 /// ref-name is added.
 ///
-class RefNameBuilder : public File::AtomHandler, 
-                       public DefinedAtom::ReferenceHandler {
+class RefNameBuilder {
 public:
-  RefNameBuilder() { }
-
-  virtual void doReference(const Reference& ref) {
-    // create refname for any unnamed reference target
-    if ( ref.target()->name().empty() ) {
-      char* buffer;
-      asprintf(&buffer, "L%03d", _unnamedCounter++);
-      _refNames[ref.target()] = buffer;
+  RefNameBuilder(const File& file) 
+                : _collisionCount(0), _unnamedCounter(0) { 
+    // visit all atoms
+    for(File::defined_iterator it=file.definedAtomsBegin(), 
+                              end=file.definedAtomsEnd(); 
+                               it != end; ++it) {
+      const DefinedAtom* atom = *it;  
+      // Build map of atoms names to detect duplicates
+      if ( ! atom->name().empty() )
+        buildDuplicateNameMap(*atom);
+      
+      // Find references to unnamed atoms and create ref-names for them.
+      for (auto rit=atom->referencesBegin(), rend=atom->referencesEnd();
+                                                        rit != rend; ++rit) {
+        const Reference* ref = *rit;
+        // create refname for any unnamed reference target
+        if ( ref->target()->name().empty() ) {
+          char* buffer;
+          asprintf(&buffer, "L%03d", _unnamedCounter++);
+          _refNames[ref->target()] = buffer;
+        }
+      }
     }
-  }
+    for(File::undefined_iterator it=file.undefinedAtomsBegin(), 
+                              end=file.undefinedAtomsEnd(); 
+                               it != end; ++it) {
+      buildDuplicateNameMap(**it);
+    }
+    for(File::shared_library_iterator it=file.sharedLibraryAtomsBegin(), 
+                              end=file.sharedLibraryAtomsEnd(); 
+                               it != end; ++it) {
+      buildDuplicateNameMap(**it);
+    }
+    for(File::absolute_iterator it=file.absoluteAtomsBegin(), 
+                              end=file.absoluteAtomsEnd(); 
+                               it != end; ++it) {
+      buildDuplicateNameMap(**it);
+    }
 
-  virtual void doFile(const File &) { }
   
-  virtual void doDefinedAtom(const DefinedAtom& atom) {
-    // Build map of atoms names to detect duplicates
-    if ( ! atom.name().empty() )
-      buildDuplicateNameMap(atom);
-    
-    // Find references to unnamed atoms and create ref-names for them.
-    _unnamedCounter = 0;
-    atom.forEachReference(*this);
   }
-  
-  virtual void doUndefinedAtom(const UndefinedAtom& atom) {
-    buildDuplicateNameMap(atom);
-  }
-  
-  virtual void doSharedLibraryAtom(const SharedLibraryAtom& atom) {
-    buildDuplicateNameMap(atom);
-  }
-
-  virtual void doAbsoluteAtom(const AbsoluteAtom& atom) {
-    buildDuplicateNameMap(atom);
-  }
-                         
+                           
   void buildDuplicateNameMap(const Atom& atom) {
     assert(!atom.name().empty());
     NameToAtom::iterator pos = _nameMap.find(atom.name());
@@ -131,27 +139,55 @@
 ///
 /// Helper class for writeObjectText() to write out atoms in yaml format.
 ///
-class AtomWriter : public File::AtomHandler,
-                   public DefinedAtom::ReferenceHandler {
+class AtomWriter {
 public:
-  AtomWriter(RefNameBuilder& rnb, llvm::raw_ostream &out) 
-    : _out(out), _rnb(rnb), _firstAtom(true) { }
+  AtomWriter(const File& file, Platform& platform, RefNameBuilder& rnb) 
+    : _file(file), _platform(platform), _rnb(rnb), _firstAtom(true) { }
 
-  virtual void doFile(const class File &) { _firstAtom = true; }
+
+  void write(llvm::raw_ostream& out) {
+    // write header 
+    out << "---\n";
+    
+    // visit all atoms
+    for(File::defined_iterator it=_file.definedAtomsBegin(), 
+                              end=_file.definedAtomsEnd(); 
+                               it != end; ++it) {
+      writeDefinedAtom(**it, out);
+    }
+    for(File::undefined_iterator it=_file.undefinedAtomsBegin(), 
+                              end=_file.undefinedAtomsEnd(); 
+                               it != end; ++it) {
+      writeUndefinedAtom(**it, out);
+    }
+    for(File::shared_library_iterator it=_file.sharedLibraryAtomsBegin(), 
+                              end=_file.sharedLibraryAtomsEnd(); 
+                               it != end; ++it) {
+      writeSharedLibraryAtom(**it, out);
+    }
+    for(File::absolute_iterator it=_file.absoluteAtomsBegin(), 
+                              end=_file.absoluteAtomsEnd(); 
+                               it != end; ++it) {
+      writeAbsoluteAtom(**it, out);
+    }
+    
+    out << "...\n";
+  }
+
   
-  virtual void doDefinedAtom(const class DefinedAtom &atom) {
+  void writeDefinedAtom(const DefinedAtom &atom, llvm::raw_ostream& out) {
     if ( _firstAtom ) {
-      _out << "atoms:\n";
+      out << "atoms:\n";
       _firstAtom = false;
     }
     else {
       // add blank line between atoms for readability
-      _out << "\n";
+      out << "\n";
     }
     
     bool hasDash = false;
     if ( !atom.name().empty() ) {
-      _out  << "    - "
+      out   << "    - "
             << KeyValues::nameKeyword
             << ":"
             << spacePadding(KeyValues::nameKeyword)
@@ -161,7 +197,7 @@
     }
      
     if ( _rnb.hasRefName(&atom) ) {
-      _out  << (hasDash ? "      " : "    - ")
+      out   << (hasDash ? "      " : "    - ")
             << KeyValues::refNameKeyword
             << ":"
             << spacePadding(KeyValues::refNameKeyword)
@@ -171,7 +207,7 @@
     }
     
     if ( atom.definition() != KeyValues::definitionDefault ) {
-      _out  << (hasDash ? "      " : "    - ")
+      out   << (hasDash ? "      " : "    - ")
             << KeyValues::definitionKeyword 
             << ":"
             << spacePadding(KeyValues::definitionKeyword)
@@ -181,7 +217,7 @@
     }
     
     if ( atom.scope() != KeyValues::scopeDefault ) {
-      _out  << (hasDash ? "      " : "    - ")
+      out   << (hasDash ? "      " : "    - ")
             << KeyValues::scopeKeyword 
             << ":"
             << spacePadding(KeyValues::scopeKeyword)
@@ -191,7 +227,7 @@
     }
     
      if ( atom.interposable() != KeyValues::interposableDefault ) {
-      _out  << "      " 
+      out   << "      " 
             << KeyValues::interposableKeyword 
             << ":"
             << spacePadding(KeyValues::interposableKeyword)
@@ -200,7 +236,7 @@
     }
     
     if ( atom.merge() != KeyValues::mergeDefault ) {
-      _out  << "      " 
+      out   << "      " 
             << KeyValues::mergeKeyword 
             << ":"
             << spacePadding(KeyValues::mergeKeyword)
@@ -209,7 +245,7 @@
     }
     
     if ( atom.contentType() != KeyValues::contentTypeDefault ) {
-      _out  << "      " 
+      out   << "      " 
             << KeyValues::contentTypeKeyword 
             << ":"
             << spacePadding(KeyValues::contentTypeKeyword)
@@ -218,7 +254,7 @@
     }
 
     if ( atom.deadStrip() != KeyValues::deadStripKindDefault ) {
-      _out  << "      " 
+      out   << "      " 
             << KeyValues::deadStripKindKeyword 
             << ":"
             << spacePadding(KeyValues::deadStripKindKeyword)
@@ -227,14 +263,14 @@
     }
 
     if ( atom.sectionChoice() != KeyValues::sectionChoiceDefault ) {
-      _out  << "      " 
+      out   << "      " 
             << KeyValues::sectionChoiceKeyword 
             << ":"
             << spacePadding(KeyValues::sectionChoiceKeyword)
             << KeyValues::sectionChoice(atom.sectionChoice()) 
             << "\n";
       assert( ! atom.customSectionName().empty() );
-      _out  << "      " 
+      out   << "      " 
             << KeyValues::sectionNameKeyword 
             << ":"
             << spacePadding(KeyValues::sectionNameKeyword)
@@ -243,7 +279,7 @@
     }
 
     if ( atom.isThumb() != KeyValues::isThumbDefault ) {
-      _out  << "      " 
+      out   << "      " 
             << KeyValues::isThumbKeyword 
             << ":"
             << spacePadding(KeyValues::isThumbKeyword)
@@ -252,7 +288,7 @@
     }
 
     if ( atom.isAlias() != KeyValues::isAliasDefault ) {
-      _out  << "      " 
+      out   << "      " 
             << KeyValues::isAliasKeyword 
             << ":"
             << spacePadding(KeyValues::isAliasKeyword)
@@ -262,7 +298,7 @@
 
     if ( (atom.contentType() != DefinedAtom::typeZeroFill) 
                                    && (atom.size() != 0) ) {
-      _out  << "      " 
+      out   << "      " 
             << KeyValues::contentKeyword 
             << ":"
             << spacePadding(KeyValues::contentKeyword)
@@ -271,77 +307,77 @@
       bool needComma = false;
       for (unsigned int i=0; i < arr.size(); ++i) {
         if ( needComma )
-          _out << ", ";
-        _out << hexdigit(arr[i] >> 4);
-        _out << hexdigit(arr[i] & 0x0F);
+          out  << ", ";
+        out  << hexdigit(arr[i] >> 4);
+        out  << hexdigit(arr[i] & 0x0F);
         needComma = true;
       }
-      _out << " ]\n";
+      out  << " ]\n";
     }
 
-    _wroteFirstFixup = false;
-    atom.forEachReference(*this);
+    bool wroteFirstFixup = false;
+    for (auto it=atom.referencesBegin(), end=atom.referencesEnd();
+                                                    it != end; ++it) {
+      const Reference* ref = *it;
+      if ( !wroteFirstFixup ) {
+        out  << "      fixups:\n";
+        wroteFirstFixup = true;
+      }
+      out   << "      - "
+            << KeyValues::fixupsOffsetKeyword
+            << ":"
+            << spacePadding(KeyValues::fixupsOffsetKeyword)
+            << ref->offsetInAtom()
+            << "\n";
+      out   << "        "
+            << KeyValues::fixupsKindKeyword
+            << ":"
+            << spacePadding(KeyValues::fixupsKindKeyword)
+            << _platform.kindToString(ref->kind())
+            << "\n";
+      const Atom* target = ref->target();
+      if ( target != NULL ) {
+        llvm::StringRef refName = target->name();
+        if ( _rnb.hasRefName(target) )
+          refName = _rnb.refName(target);
+        assert(!refName.empty());
+        out   << "        "
+              << KeyValues::fixupsTargetKeyword
+              << ":"
+              << spacePadding(KeyValues::fixupsTargetKeyword)
+              << refName 
+              << "\n";
+      }
+      if ( ref->addend() != 0 ) {
+        out   << "        "
+              << KeyValues::fixupsAddendKeyword
+              << ":"
+              << spacePadding(KeyValues::fixupsAddendKeyword)
+              << ref->addend()
+              << "\n";
+      }
+    }
   }
     
-  virtual void doReference(const Reference& ref) {
-    if ( !_wroteFirstFixup ) {
-      _out << "      fixups:\n";
-      _wroteFirstFixup = true;
-    }
-    _out  << "      - "
-          << KeyValues::fixupsOffsetKeyword
-          << ":"
-          << spacePadding(KeyValues::fixupsOffsetKeyword)
-          << ref.offsetInAtom()
-          << "\n";
-    _out  << "        "
-          << KeyValues::fixupsKindKeyword
-          << ":"
-          << spacePadding(KeyValues::fixupsKindKeyword)
-          << ref.kind()
-          << "\n";
-    const Atom* target = ref.target();
-    if ( target != NULL ) {
-      llvm::StringRef refName = target->name();
-      if ( _rnb.hasRefName(target) )
-        refName = _rnb.refName(target);
-      assert(!refName.empty());
-      _out  << "        "
-            << KeyValues::fixupsTargetKeyword
-            << ":"
-            << spacePadding(KeyValues::fixupsTargetKeyword)
-            << refName 
-            << "\n";
-    }
-    if ( ref.addend() != 0 ) {
-      _out  << "        "
-            << KeyValues::fixupsAddendKeyword
-            << ":"
-            << spacePadding(KeyValues::fixupsAddendKeyword)
-            << ref.addend()
-            << "\n";
-    }
-  }
 
-
-  virtual void doUndefinedAtom(const class UndefinedAtom &atom) {
+  void writeUndefinedAtom(const UndefinedAtom &atom, llvm::raw_ostream& out) {
     if ( _firstAtom ) {
-      _out << "atoms:\n";
+      out  << "atoms:\n";
       _firstAtom = false;
     }
     else {
       // add blank line between atoms for readability
-      _out << "\n";
+      out  << "\n";
     }
         
-    _out  << "    - "
+    out   << "    - "
           << KeyValues::nameKeyword
           << ":"
           << spacePadding(KeyValues::nameKeyword)
           << atom.name() 
           << "\n";
 
-    _out  << "      " 
+    out   << "      " 
           << KeyValues::definitionKeyword 
           << ":"
           << spacePadding(KeyValues::definitionKeyword)
@@ -349,7 +385,7 @@
           << "\n";
 
     if ( atom.canBeNull() != KeyValues::canBeNullDefault ) {
-      _out  << "      " 
+      out   << "      " 
             << KeyValues::canBeNullKeyword 
             << ":"
             << spacePadding(KeyValues::canBeNullKeyword)
@@ -358,24 +394,24 @@
     }
   }
 
-   virtual void doSharedLibraryAtom(const SharedLibraryAtom& atom) {
+  void writeSharedLibraryAtom(const SharedLibraryAtom& atom, llvm::raw_ostream& out) {
     if ( _firstAtom ) {
-      _out << "atoms:\n";
+      out  << "atoms:\n";
       _firstAtom = false;
     }
     else {
       // add blank line between atoms for readability
-      _out << "\n";
+      out  << "\n";
     }
         
-    _out  << "    - "
+    out   << "    - "
           << KeyValues::nameKeyword
           << ":"
           << spacePadding(KeyValues::nameKeyword)
           << atom.name() 
           << "\n";
 
-    _out  << "      " 
+    out   << "      " 
           << KeyValues::definitionKeyword 
           << ":"
           << spacePadding(KeyValues::definitionKeyword)
@@ -383,7 +419,7 @@
           << "\n";
 
     if ( !atom.loadName().empty() ) {
-      _out  << "      " 
+      out   << "      " 
             << KeyValues::loadNameKeyword 
             << ":"
             << spacePadding(KeyValues::loadNameKeyword)
@@ -392,7 +428,7 @@
     }
 
     if ( atom.canBeNullAtRuntime() ) {
-      _out  << "      " 
+      out   << "      " 
             << KeyValues::canBeNullKeyword 
             << ":"
             << spacePadding(KeyValues::canBeNullKeyword)
@@ -401,37 +437,37 @@
     }
    }
    
-   virtual void doAbsoluteAtom(const AbsoluteAtom& atom) {
+  void writeAbsoluteAtom(const AbsoluteAtom& atom, llvm::raw_ostream& out) {
      if ( _firstAtom ) {
-      _out << "atoms:\n";
+      out << "atoms:\n";
       _firstAtom = false;
     }
     else {
       // add blank line between atoms for readability
-      _out << "\n";
+      out << "\n";
     }
         
-    _out  << "    - "
+    out   << "    - "
           << KeyValues::nameKeyword
           << ":"
           << spacePadding(KeyValues::nameKeyword)
           << atom.name() 
           << "\n";
 
-    _out  << "      " 
+    out   << "      " 
           << KeyValues::definitionKeyword 
           << ":"
           << spacePadding(KeyValues::definitionKeyword)
           << KeyValues::definition(atom.definition()) 
           << "\n";
     
-    _out  << "      " 
+    out   << "      " 
           << KeyValues::valueKeyword 
           << ":"
           << spacePadding(KeyValues::valueKeyword)
           << "0x";
-     _out.write_hex(atom.value());
-     _out << "\n";
+     out.write_hex(atom.value());
+     out << "\n";
    }
                      
 
@@ -450,10 +486,10 @@
       return 'A' + nibble - 0x0A;
   }
 
-  llvm::raw_ostream&  _out;
-  RefNameBuilder      _rnb;
+  const File&         _file;
+  Platform&           _platform;
+  RefNameBuilder&     _rnb;
   bool                _firstAtom;
-  bool                _wroteFirstFixup;
 };
 
 } // anonymous namespace
@@ -464,16 +500,14 @@
 /// writeObjectText - writes the lld::File object as in YAML
 /// format to the specified stream.
 ///
-void writeObjectText(const File &file, llvm::raw_ostream &out) {
+void writeObjectText(const File& file, Platform& platform, 
+                      llvm::raw_ostream &out) {
   // Figure what ref-name labels are needed
-  RefNameBuilder rnb;
-  file.forEachAtom(rnb);
+  RefNameBuilder rnb(file);
   
   // Write out all atoms
-  AtomWriter h(rnb, out);
-  out << "---\n";
-  file.forEachAtom(h);
-  out << "...\n";
+  AtomWriter writer(file, platform, rnb);
+  writer.write(out);
 }
 
 } // namespace yaml