[llvm-commits] [lld] r154242 - in /lld/trunk: include/lld/Core/ include/lld/Platform/ lib/ lib/Core/ lib/Passes/ lib/Platforms/ lib/Platforms/Darwin/ test/darwin/ tools/lld-core/

Nick Kledzik kledzik at apple.com
Fri Apr 6 18:31:00 PDT 2012


Author: kledzik
Date: Fri Apr  6 20:31:00 2012
New Revision: 154242

URL: http://llvm.org/viewvc/llvm-project?rev=154242&view=rev
Log:
First implementation of Darwin Platform.  It is rich enough to generate
a hello world executable from atoms.  There is still much to be flushed out.
Added one test case, test/darwin/hello-world.objtxt, which exercises the
darwin platform.

Added -platform option to lld-core tool to dynamically select platform.

Added:
    lld/trunk/lib/Core/Platform.cpp
    lld/trunk/lib/Platforms/
    lld/trunk/lib/Platforms/CMakeLists.txt
    lld/trunk/lib/Platforms/Darwin/
    lld/trunk/lib/Platforms/Darwin/CMakeLists.txt
    lld/trunk/lib/Platforms/Darwin/DarwinPlatform.cpp
    lld/trunk/lib/Platforms/Darwin/DarwinPlatform.h
    lld/trunk/lib/Platforms/Darwin/DarwinReferenceKinds.cpp
    lld/trunk/lib/Platforms/Darwin/DarwinReferenceKinds.h
    lld/trunk/lib/Platforms/Darwin/ExecutableWriter.cpp
    lld/trunk/lib/Platforms/Darwin/ExecutableWriter.h
    lld/trunk/lib/Platforms/Darwin/MachOFormat.hpp
    lld/trunk/lib/Platforms/Darwin/StubAtoms.hpp
    lld/trunk/test/darwin/
    lld/trunk/test/darwin/hello-world.objtxt
Removed:
    lld/trunk/include/lld/Platform/PlatformDarwin.h
Modified:
    lld/trunk/include/lld/Core/DefinedAtom.h
    lld/trunk/include/lld/Core/File.h
    lld/trunk/include/lld/Core/Platform.h
    lld/trunk/include/lld/Core/Reference.h
    lld/trunk/include/lld/Core/Resolver.h
    lld/trunk/include/lld/Core/SymbolTable.h
    lld/trunk/lib/CMakeLists.txt
    lld/trunk/lib/Core/CMakeLists.txt
    lld/trunk/lib/Core/File.cpp
    lld/trunk/lib/Core/NativeFileFormat.h
    lld/trunk/lib/Core/NativeReader.cpp
    lld/trunk/lib/Core/NativeWriter.cpp
    lld/trunk/lib/Core/Resolver.cpp
    lld/trunk/lib/Core/YamlReader.cpp
    lld/trunk/lib/Passes/GOTPass.cpp
    lld/trunk/lib/Passes/StubsPass.cpp
    lld/trunk/tools/lld-core/CMakeLists.txt
    lld/trunk/tools/lld-core/lld-core.cpp

Modified: lld/trunk/include/lld/Core/DefinedAtom.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/DefinedAtom.h?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/DefinedAtom.h (original)
+++ lld/trunk/include/lld/Core/DefinedAtom.h Fri Apr  6 20:31:00 2012
@@ -251,7 +251,7 @@
 
   /// This class abstracts iterating over the sequence of References
   /// in an Atom.  Concrete instances of DefinedAtom must implement
-  /// the derefIterator() and incrementIterator methods.
+  /// the derefIterator() and incrementIterator() methods.
   class reference_iterator {
   public:
     reference_iterator(const DefinedAtom& a, const void* it)
@@ -284,6 +284,10 @@
   /// Returns an iterator to the end of this Atom's References
   virtual reference_iterator referencesEnd() const = 0;
 
+  reference_iterator begin() const { return referencesBegin(); }
+  reference_iterator end() const { return referencesEnd(); }
+
+
   static inline bool classof(const Atom *a) {
     return a->definition() == definitionRegular;
   }

Modified: lld/trunk/include/lld/Core/File.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/File.h?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/File.h (original)
+++ lld/trunk/include/lld/Core/File.h Fri Apr  6 20:31:00 2012
@@ -49,6 +49,12 @@
   /// be ascertained, this method returns the empty string.
   virtual StringRef translationUnitSource() const;
 
+  /// Returns pointer to "main" atom, or nullptr. All object files can
+  /// use the default implementation which just returns nullptr.  
+  /// But the master merged File operated on by Passes, needs override
+  /// this and return the atom for "main". 
+  virtual const Atom *entryPoint() const; 
+
 protected:
   template <typename T> class atom_iterator; // forward reference
 public:
@@ -165,7 +171,8 @@
     const atom_collection<T>&   _collection;
     const void*                 _it;
   };
-
+  
+public:
   /// Must be implemented to return the atom_collection object for 
   /// all DefinedAtoms in this File.
   virtual const atom_collection<DefinedAtom>& defined() const = 0;
@@ -181,7 +188,8 @@
   /// Must be implemented to return the atom_collection object for 
   /// all AbsoluteAtoms in this File.
   virtual const atom_collection<AbsoluteAtom>& absolute() const = 0;
-
+  
+protected:
   /// This is a convenience class for File subclasses which manage their
   /// atoms as a simple std::vector<>.  
   template <typename T>

Modified: lld/trunk/include/lld/Core/Platform.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/Platform.h?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/Platform.h (original)
+++ lld/trunk/include/lld/Core/Platform.h Fri Apr  6 20:31:00 2012
@@ -11,12 +11,15 @@
 #define LLD_CORE_PLATFORM_H_
 
 #include "lld/Core/Reference.h"
-
+#include "lld/Core/LLVM.h"
 #include <vector>
 
 namespace lld {
 class Atom;
 class DefinedAtom;
+class UndefinedAtom;
+class SharedLibraryAtom;
+class File;
 
 
 /// The Platform class encapsulated plaform specific linking knowledge.
@@ -24,6 +27,8 @@
 /// Much of what it does is driving by platform specific linker options.
 class Platform {
 public:
+  virtual ~Platform();
+
   virtual void initialize() = 0;
 
   /// @brief tell platform object another file has been added
@@ -132,15 +137,38 @@
   /// directly access the target.
   virtual void updateReferenceToGOT(const Reference*, bool targetIsNowGOT) = 0;
 
-  /// Create a platform specific atom which contains a stub/PLT entry
-  /// targeting the specified shared library atom.
-  virtual const DefinedAtom* makeStub(const Atom&, File&) = 0;
+  /// Returns a platform specific atom for a stub/PLT entry which will
+  /// jump to the specified atom.  May be called multiple times for the same
+  /// target atom, in which case this method should return the same stub
+  /// atom.  The platform needs to maintain a list of all stubs (and 
+  /// associated atoms) it has created for use by addStubAtoms().
+  virtual const DefinedAtom* getStub(const Atom &target, File&) = 0;
+
+  /// After the stubs Pass is done calling getStub(), the Pass will call
+  /// this method to add all the stub (and support) atoms to the master
+  /// file object.
+  virtual void addStubAtoms(File &file) = 0;
 
   /// Create a platform specific GOT atom.
   virtual const DefinedAtom* makeGOTEntry(const Atom&, File&) = 0;
-
+  
+  /// Write an executable file from the supplied file object to the 
+  /// supplied stream.
+  virtual void writeExecutable(const lld::File &, raw_ostream &out) = 0;
+  
+protected:
+  Platform();
 };
 
+
+
+///
+/// Creates a platform object for linking as done on Darwin (iOS/OSX).
+///
+extern Platform *createDarwinPlatform();
+
+
+
 } // namespace lld
 
 #endif // LLD_CORE_PLATFORM_H_

Modified: lld/trunk/include/lld/Core/Reference.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/Reference.h?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/Reference.h (original)
+++ lld/trunk/include/lld/Core/Reference.h Fri Apr  6 20:31:00 2012
@@ -58,6 +58,9 @@
   /// Some relocations require a symbol and a value (e.g. foo + 4).
   virtual Addend addend() const = 0;
 
+  /// During linking, some optimzations may change addend value.
+  virtual void setAddend(Addend) = 0;
+
 protected:
   /// Atom is an abstract base class.  Only subclasses can access constructor.
   Reference() {}

Modified: lld/trunk/include/lld/Core/Resolver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/Resolver.h?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/Resolver.h (original)
+++ lld/trunk/include/lld/Core/Resolver.h Fri Apr  6 20:31:00 2012
@@ -80,10 +80,11 @@
 
   class MergedFile : public File {
   public:
-    MergedFile() : File("<linker-internal>") { }
-
-
+    MergedFile() : File("<linker-internal>"), _mainAtom(nullptr) { }
 
+  virtual const Atom *entryPoint() const {
+    return _mainAtom;
+  }
   virtual const atom_collection<DefinedAtom>& defined() const {
     return _definedAtoms;
   }
@@ -102,6 +103,8 @@
   virtual void addAtom(const Atom& atom);
 
   private:
+    friend class Resolver;
+    const Atom*                                 _mainAtom;
     atom_collection_vector<DefinedAtom>         _definedAtoms;
     atom_collection_vector<UndefinedAtom>       _undefinedAtoms;
     atom_collection_vector<SharedLibraryAtom>   _sharedLibraryAtoms;

Modified: lld/trunk/include/lld/Core/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/SymbolTable.h?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/SymbolTable.h (original)
+++ lld/trunk/include/lld/Core/SymbolTable.h Fri Apr  6 20:31:00 2012
@@ -77,7 +77,7 @@
     static bool isEqual(StringRef const lhs,
                         StringRef const rhs) { return lhs.equals(rhs); }
   };
-	typedef llvm::DenseMap<StringRef, const Atom *,
+  typedef llvm::DenseMap<StringRef, const Atom *,
                                            StringRefMappingInfo> NameToAtom;
 
   struct AtomMappingInfo {

Removed: lld/trunk/include/lld/Platform/PlatformDarwin.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Platform/PlatformDarwin.h?rev=154241&view=auto
==============================================================================
--- lld/trunk/include/lld/Platform/PlatformDarwin.h (original)
+++ lld/trunk/include/lld/Platform/PlatformDarwin.h (removed)
@@ -1,29 +0,0 @@
-//===- Platform/PlatformDarwin.h - Darwin Platform Implementation ---------===//
-//
-//                             The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_PLATFORM_PLATFORM_H_
-#define LLD_PLATFORM_PLATFORM_H_
-
-#include "lld/Platform/Platform.h"
-
-namespace lld {
-
-class PlatformDarwin : public Platform {
-  virtual void initialize();
-
-  // keep track of: ObjC GC-ness, if any .o file cannot be scattered,
-  // cpu-sub-type
-  virtual void fileAdded(const File &file);
-
-  virtual bool deadCodeStripping();
-};
-
-} // namespace lld
-
-#endif // LLD_PLATFORM_PLATFORM_H_

Modified: lld/trunk/lib/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/CMakeLists.txt?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/lib/CMakeLists.txt (original)
+++ lld/trunk/lib/CMakeLists.txt Fri Apr  6 20:31:00 2012
@@ -1,2 +1,3 @@
 add_subdirectory(Core)
 add_subdirectory(Passes)
+add_subdirectory(Platforms)

Modified: lld/trunk/lib/Core/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/CMakeLists.txt?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/lib/Core/CMakeLists.txt (original)
+++ lld/trunk/lib/Core/CMakeLists.txt Fri Apr  6 20:31:00 2012
@@ -4,6 +4,7 @@
   NativeFileFormat.h
   NativeReader.cpp
   NativeWriter.cpp
+  Platform.cpp
   Resolver.cpp
   SymbolTable.cpp
   YamlKeyValues.cpp

Modified: lld/trunk/lib/Core/File.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/File.cpp?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/lib/Core/File.cpp (original)
+++ lld/trunk/lib/Core/File.cpp Fri Apr  6 20:31:00 2012
@@ -18,5 +18,8 @@
   return StringRef();
 }
 
+const Atom *File::entryPoint() const {
+  return nullptr;
+}
 
 }

Modified: lld/trunk/lib/Core/NativeFileFormat.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/NativeFileFormat.h?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/lib/Core/NativeFileFormat.h (original)
+++ lld/trunk/lib/Core/NativeFileFormat.h Fri Apr  6 20:31:00 2012
@@ -193,6 +193,9 @@
 // The NCS_ReferencesArrayV1 chunk contains an array of these structs
 //
 struct NativeReferenceIvarsV1 {
+  enum {
+    noTarget = 0xFFFF
+  };
   uint16_t  offsetInAtom;
    int16_t  kind;
   uint16_t  targetIndex;
@@ -200,7 +203,6 @@
 };
 
 
-
 //
 // The NCS_ReferencesArrayV2 chunk contains an array of these structs
 //

Modified: lld/trunk/lib/Core/NativeReader.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/NativeReader.cpp?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/lib/Core/NativeReader.cpp (original)
+++ lld/trunk/lib/Core/NativeReader.cpp Fri Apr  6 20:31:00 2012
@@ -20,6 +20,7 @@
 #include "llvm/Support/MemoryBuffer.h"
 
 #include <vector>
+#include <memory>
 
 namespace lld {
 
@@ -202,6 +203,7 @@
   virtual const Atom* target() const;
   virtual Addend addend() const;
   virtual void setTarget(const Atom* newAtom);
+  virtual void setAddend(Addend a);
 
 private:
   // Used in rare cases when Reference is modified,
@@ -606,15 +608,19 @@
     return reinterpret_cast<const NativeReferenceV1*>(p);
   }
 
-  const Atom* target(uint32_t index) const {
+  const Atom* target(uint16_t index) const {
+    if ( index == NativeReferenceIvarsV1::noTarget )
+      return nullptr;
     assert(index < _targetsTableCount);
     return _targetsTable[index];
   }
 
-  void setTarget(uint32_t index, const Atom* newAtom) const {
+  void setTarget(uint16_t index, const Atom* newAtom) const {
+    assert(index != NativeReferenceIvarsV1::noTarget);
     assert(index > _targetsTableCount);
     _targetsTable[index] = newAtom;
   }
+  
 
 
   // private constructor, only called by make()
@@ -799,6 +805,10 @@
   return _file->setTarget(_ivarData->targetIndex, newAtom);
 }
 
+inline void NativeReferenceV1::setAddend(Addend a) {
+  assert(0 && "setAddend() not supported");
+}
+
 
 //
 // Instantiate an lld::File from the given native object file buffer

Modified: lld/trunk/lib/Core/NativeWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/NativeWriter.cpp?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/lib/Core/NativeWriter.cpp (original)
+++ lld/trunk/lib/Core/NativeWriter.cpp Fri Apr  6 20:31:00 2012
@@ -430,11 +430,13 @@
   }
 
   uint32_t getTargetIndex(const Atom* target) {
+    if ( target == nullptr )
+      return NativeReferenceIvarsV1::noTarget;
     TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
     if ( pos != _targetsTableIndex.end() ) {
       return pos->second;
     }
-    uint32_t result = _targetsTableIndex.size();
+    uint32_t result = _targetsTableIndex.size(); 
     _targetsTableIndex[target] = result;
     return result;
   }

Added: lld/trunk/lib/Core/Platform.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/Platform.cpp?rev=154242&view=auto
==============================================================================
--- lld/trunk/lib/Core/Platform.cpp (added)
+++ lld/trunk/lib/Core/Platform.cpp Fri Apr  6 20:31:00 2012
@@ -0,0 +1,19 @@
+//===- Core/Platform.cpp - Base class ------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Platform.h"
+
+namespace lld {
+
+Platform::Platform() {}
+
+Platform::~Platform() {}
+
+
+}

Modified: lld/trunk/lib/Core/Resolver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/Resolver.cpp?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/lib/Core/Resolver.cpp (original)
+++ lld/trunk/lib/Core/Resolver.cpp Fri Apr  6 20:31:00 2012
@@ -7,6 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "lld/Core/LLVM.h"
 #include "lld/Core/Resolver.h"
 #include "lld/Core/Atom.h"
 #include "lld/Core/File.h"
@@ -359,7 +360,7 @@
 // get "main" atom for linkage unit
 const Atom *Resolver::entryPoint() {
   StringRef symbolName = _platform.entryPointName();
-  if (symbolName != nullptr)
+  if ( !symbolName.empty() )
     return _symbolTable.findByName(symbolName);
 
   return nullptr;
@@ -387,6 +388,7 @@
   this->linkTimeOptimize();
   this->tweakAtoms();
   this->_result.addAtoms(_atoms);
+  this->_result._mainAtom = this->entryPoint();
 }
 
 void Resolver::MergedFile::addAtom(const Atom& atom) {

Modified: lld/trunk/lib/Core/YamlReader.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/YamlReader.cpp?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/lib/Core/YamlReader.cpp (original)
+++ lld/trunk/lib/Core/YamlReader.cpp Fri Apr  6 20:31:00 2012
@@ -179,7 +179,7 @@
       }
       break;
     case inSpaceBeforeValue:
-      if (isalnum(c) || (c == '-') || (c == '_')) {
+      if (isalnum(c) || (c == '-') || (c == '_') || (c == '/')) {
         p = &value[0];
         *p++ = c;
         state = inValue;
@@ -280,6 +280,10 @@
   virtual Addend addend() const {
     return _addend;
   }
+  
+  virtual void setAddend(Addend a) {
+    _addend = a;
+  }
 
   virtual void setTarget(const Atom* newAtom) {
     _target = newAtom;
@@ -554,7 +558,10 @@
   }
 
   virtual StringRef loadName() const {
-    return _loadName;
+    if ( _loadName == nullptr )
+      return StringRef();
+    else
+      return StringRef(_loadName);
   }
 
   virtual bool canBeNullAtRuntime() const {

Modified: lld/trunk/lib/Passes/GOTPass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Passes/GOTPass.cpp?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/lib/Passes/GOTPass.cpp (original)
+++ lld/trunk/lib/Passes/GOTPass.cpp Fri Apr  6 20:31:00 2012
@@ -9,7 +9,7 @@
 //
 // This linker pass transforms all GOT kind references to real references.
 // That is, in assembly you can write something like:
-//     movq	foo at GOTPCREL(%rip), %rax 
+//     movq foo at GOTPCREL(%rip), %rax 
 // which means you want to load a pointer to "foo" out of the GOT (global
 // Offsets Table). In the object file, the Atom containing this instruction
 // has a Reference whose target is an Atom named "foo" and the Reference

Modified: lld/trunk/lib/Passes/StubsPass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Passes/StubsPass.cpp?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/lib/Passes/StubsPass.cpp (original)
+++ lld/trunk/lib/Passes/StubsPass.cpp Fri Apr  6 20:31:00 2012
@@ -30,9 +30,6 @@
   if ( !_platform.noTextRelocs() )
     return;
 
-  // Use map so all call sites to same shlib symbol use same stub.
-  llvm::DenseMap<const Atom*, const DefinedAtom*> targetToStub;
-
   // Scan all references in all atoms.
   for(auto ait=_file.definedAtomsBegin(), aend=_file.definedAtomsEnd();
                                                       ait != aend; ++ait) {
@@ -48,7 +45,8 @@
         if ( target->definition() == Atom::definitionSharedLibrary ) {
           // Calls to shared libraries go through stubs.
           replaceCalleeWithStub = true;
-        } else if (const DefinedAtom* defTarget =
+        } 
+        else if (const DefinedAtom* defTarget =
                      dyn_cast<DefinedAtom>(target)) {
           if ( defTarget->interposable() != DefinedAtom::interposeNo ) {
             // Calls to interposable functions in same linkage unit
@@ -58,34 +56,18 @@
           }
         }
         if ( replaceCalleeWithStub ) {
-          // Replace the reference's target with a stub.
-          const DefinedAtom* stub;
-          auto pos = targetToStub.find(target);
-          if ( pos == targetToStub.end() ) {
-            // This is no existing stub.  Create a new one.
-            stub = _platform.makeStub(*target, _file);
-            assert(stub != nullptr);
-            assert(stub->contentType() == DefinedAtom::typeStub);
-            targetToStub[target] = stub;
-          }
-          else {
-            // Reuse an existing stub.
-            stub = pos->second;
-            assert(stub != nullptr);
-          }
-          // Switch call site to reference stub atom.
+          // Ask platform to make stub and other support atoms.
+          const DefinedAtom* stub = _platform.getStub(*target, _file);
+          assert(stub != nullptr);
+          // Switch call site to reference stub atom instead.
           (const_cast<Reference*>(ref))->setTarget(stub);
-        }
+         }
       }
     }
   }
 
-  // add all created stubs to file
-  for (auto it=targetToStub.begin(), end=targetToStub.end(); it != end; ++it) {
-    _file.addAtom(*it->second);
-  }
-
-
+  // Tell platform to add all created stubs and support Atoms to file.
+  _platform.addStubAtoms(_file);
 }
 
 

Added: lld/trunk/lib/Platforms/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Platforms/CMakeLists.txt?rev=154242&view=auto
==============================================================================
--- lld/trunk/lib/Platforms/CMakeLists.txt (added)
+++ lld/trunk/lib/Platforms/CMakeLists.txt Fri Apr  6 20:31:00 2012
@@ -0,0 +1 @@
+add_subdirectory(Darwin)

Added: lld/trunk/lib/Platforms/Darwin/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Platforms/Darwin/CMakeLists.txt?rev=154242&view=auto
==============================================================================
--- lld/trunk/lib/Platforms/Darwin/CMakeLists.txt (added)
+++ lld/trunk/lib/Platforms/Darwin/CMakeLists.txt Fri Apr  6 20:31:00 2012
@@ -0,0 +1,5 @@
+add_lld_library(lldDarwinPlatform
+  DarwinPlatform.cpp
+  DarwinReferenceKinds.cpp
+  ExecutableWriter.cpp
+  )

Added: lld/trunk/lib/Platforms/Darwin/DarwinPlatform.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Platforms/Darwin/DarwinPlatform.cpp?rev=154242&view=auto
==============================================================================
--- lld/trunk/lib/Platforms/Darwin/DarwinPlatform.cpp (added)
+++ lld/trunk/lib/Platforms/Darwin/DarwinPlatform.cpp Fri Apr  6 20:31:00 2012
@@ -0,0 +1,264 @@
+//===- Platforms/Darwin/DarwinPlatform.cpp --------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DarwinPlatform.h"
+#include "MachOFormat.hpp"
+#include "StubAtoms.hpp"
+#include "DarwinReferenceKinds.h"
+#include "ExecutableWriter.h"
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+
+#include "llvm/Support/ErrorHandling.h"
+
+namespace lld {
+
+Platform *createDarwinPlatform() {
+  return new darwin::DarwinPlatform();
+}
+
+
+namespace darwin {
+
+DarwinPlatform::DarwinPlatform()
+  : _helperCommonAtom(nullptr) {
+}
+
+void DarwinPlatform::initialize() {
+}
+
+void DarwinPlatform::fileAdded(const File &file) {
+}
+
+
+void DarwinPlatform::atomAdded(const Atom &file) {
+}
+
+
+void DarwinPlatform::adjustScope(const DefinedAtom &atom) {
+}
+
+
+bool DarwinPlatform::getAliasAtoms(const Atom &atom,
+                           std::vector<const DefinedAtom *>&) {
+  return false;
+}
+
+
+bool DarwinPlatform::getPlatformAtoms(StringRef undefined,
+                              std::vector<const DefinedAtom *>&) {
+  return false;
+}
+
+
+bool DarwinPlatform::deadCodeStripping() {
+  return false;
+}
+
+
+bool DarwinPlatform::isDeadStripRoot(const Atom &atom) {
+  return false;
+}
+
+
+bool DarwinPlatform::getImplicitDeadStripRoots(std::vector<const DefinedAtom *>&) {
+  return false;
+}
+
+
+StringRef DarwinPlatform::entryPointName() {
+  return StringRef("_main");
+}
+
+
+Platform::UndefinesIterator DarwinPlatform::initialUndefinesBegin() const {
+  return nullptr;
+}
+
+Platform::UndefinesIterator DarwinPlatform::initialUndefinesEnd() const {
+  return nullptr;
+}
+
+
+bool DarwinPlatform::searchArchivesToOverrideTentativeDefinitions() {
+  return false;
+}
+
+bool DarwinPlatform::searchSharedLibrariesToOverrideTentativeDefinitions() {
+  return false;
+}
+
+
+bool DarwinPlatform::allowUndefinedSymbol(StringRef name) {
+  return false;
+}
+
+bool DarwinPlatform::printWhyLive(StringRef name) {
+  return false;
+}
+
+
+const Atom& DarwinPlatform::handleMultipleDefinitions(const Atom& def1, 
+                                              const Atom& def2) {
+  llvm::report_fatal_error("multiple definitions");
+}
+
+
+void DarwinPlatform::errorWithUndefines(const std::vector<const Atom *>& undefs,
+                                const std::vector<const Atom *>& all) {
+}
+
+
+void DarwinPlatform::undefineCanBeNullMismatch(const UndefinedAtom& undef1,
+                                       const UndefinedAtom& undef2,
+                                       bool& useUndef2) {
+}
+
+
+void DarwinPlatform::sharedLibrarylMismatch(const SharedLibraryAtom& shLib1,
+                                    const SharedLibraryAtom& shLib2,
+                                    bool& useShlib2) {
+}
+
+
+void DarwinPlatform::postResolveTweaks(std::vector<const Atom *>& all) {
+}
+
+
+Reference::Kind DarwinPlatform::kindFromString(StringRef kindName) {
+  return ReferenceKind::fromString(kindName);
+}
+
+
+StringRef DarwinPlatform::kindToString(Reference::Kind kindValue) {
+  return ReferenceKind::toString(kindValue);
+}
+
+bool DarwinPlatform::noTextRelocs() {
+  return true;
+}
+
+
+bool DarwinPlatform::isCallSite(Reference::Kind kind) {
+  return ReferenceKind::isCallSite(kind);
+}
+
+
+bool DarwinPlatform::isGOTAccess(Reference::Kind, bool& canBypassGOT) {
+  return false;
+}
+
+
+void DarwinPlatform::updateReferenceToGOT(const Reference*, bool nowGOT) {
+}
+
+
+const DefinedAtom* DarwinPlatform::getStub(const Atom& target, File& file) {
+  auto pos = _targetToStub.find(&target);
+  if ( pos != _targetToStub.end() ) {
+    // Reuse an existing stub.
+    assert(pos->second != nullptr);
+    return pos->second;
+  }
+  else {
+    // There is no existing stub, so create a new one.
+    if ( _helperCommonAtom == nullptr ) {
+      // Lazily create common helper code and data.
+      _helperCacheAtom = new X86_64NonLazyPointerAtom(file);
+      _stubBinderAtom = new StubBinderAtom(file);
+      _helperBinderAtom = new X86_64NonLazyPointerAtom(file, *_stubBinderAtom);
+      _helperCommonAtom = new X86_64StubHelperCommonAtom(file,
+                                        *_helperCacheAtom, *_helperBinderAtom);
+    }
+    const DefinedAtom* helper = new X86_64StubHelperAtom(file,
+                                                          *_helperCommonAtom);
+    _stubHelperAtoms.push_back(helper);
+    const DefinedAtom* lp = new X86_64LazyPointerAtom(file, *helper, target);
+    assert(lp->contentType() == DefinedAtom::typeLazyPointer);
+    const DefinedAtom* stub = new X86_64StubAtom(file, *lp);
+    assert(stub->contentType() == DefinedAtom::typeStub);
+    _targetToStub[&target] = stub;
+    _lazyPointers.push_back(lp);
+    return stub;
+  }
+}
+
+
+void DarwinPlatform::addStubAtoms(File &file) {
+  // Add all stubs to master file.
+  for (auto it=_targetToStub.begin(), end=_targetToStub.end(); it != end; ++it) {
+    file.addAtom(*it->second);
+  }
+  // Add helper code atoms.
+  file.addAtom(*_helperCommonAtom);
+  for (const DefinedAtom *lp : _stubHelperAtoms) {
+    file.addAtom(*lp);
+  }
+  // Add GOT slots used for lazy binding.
+  file.addAtom(*_helperBinderAtom);
+  file.addAtom(*_helperCacheAtom);
+  // Add all lazy pointers to master file.
+  for (const DefinedAtom *lp : _lazyPointers) {
+    file.addAtom(*lp);
+  }
+  // Add sharedlibrary atom
+  file.addAtom(*_stubBinderAtom);
+}
+
+
+const DefinedAtom* DarwinPlatform::makeGOTEntry(const Atom&, File&) {
+  return nullptr;
+}
+
+void DarwinPlatform::applyFixup(Reference::Kind kind, uint64_t addend,  
+                                  uint8_t* location, uint64_t fixupAddress, 
+                                                     uint64_t targetAddress) {
+  //fprintf(stderr, "applyFixup(kind=%s, addend=0x%0llX, "
+  //                "fixupAddress=0x%0llX, targetAddress=0x%0llX\n", 
+  //                kindToString(kind).data(), addend, 
+  //                fixupAddress, targetAddress);
+  if ( ReferenceKind::isRipRel32(kind) ) {
+    // compute rip relative value and update.
+    int32_t* loc32 = reinterpret_cast<int32_t*>(location);
+    *loc32 = (targetAddress - (fixupAddress+4)) + addend;
+  }
+  else if ( kind == ReferenceKind::pointer64 ) {
+    uint64_t* loc64 = reinterpret_cast<uint64_t*>(location);
+    *loc64 = targetAddress + addend;
+  }
+}
+
+void DarwinPlatform::writeExecutable(const lld::File &file, raw_ostream &out) {
+  lld::darwin::writeExecutable(file, *this, out);
+}
+
+
+uint64_t DarwinPlatform::pageZeroSize() {
+  return 0x100000000;
+}
+
+
+void DarwinPlatform::initializeMachHeader(const lld::File& file, 
+                                                   mach_header& mh) {
+  // FIXME: Need to get cpu info from file object
+  mh.magic      = MAGIC_64;
+  mh.cputype    = CPU_TYPE_X86_64;
+  mh.cpusubtype = CPU_SUBTYPE_X86_64_ALL;
+  mh.filetype   = MH_EXECUTE;
+  mh.ncmds      = 0;
+  mh.sizeofcmds = 0;
+  mh.flags      = 0;
+  mh.reserved   = 0;
+}
+
+
+} // namespace darwin 
+} // namespace lld 

Added: lld/trunk/lib/Platforms/Darwin/DarwinPlatform.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Platforms/Darwin/DarwinPlatform.h?rev=154242&view=auto
==============================================================================
--- lld/trunk/lib/Platforms/Darwin/DarwinPlatform.h (added)
+++ lld/trunk/lib/Platforms/Darwin/DarwinPlatform.h Fri Apr  6 20:31:00 2012
@@ -0,0 +1,87 @@
+//===- Platform/DarwinPlatform.h - Darwin Platform Implementation ---------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_PLATFORM_DARWIN_PLATFORM_H_
+#define LLD_PLATFORM_DARWIN_PLATFORM_H_
+
+#include "lld/Core/Platform.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace lld {
+namespace darwin {
+
+class DarwinPlatform : public Platform {
+public:
+                DarwinPlatform();
+                
+/// @name Platform methods
+/// @{
+  virtual void initialize();
+  virtual void fileAdded(const File &file);
+  virtual void atomAdded(const Atom &file);
+  virtual void adjustScope(const DefinedAtom &atom);
+  virtual bool getAliasAtoms(const Atom &atom,
+                             std::vector<const DefinedAtom *>&);
+  virtual bool getPlatformAtoms(llvm::StringRef undefined,
+                                std::vector<const DefinedAtom *>&);
+  virtual bool deadCodeStripping();
+  virtual bool isDeadStripRoot(const Atom &atom);
+  virtual bool getImplicitDeadStripRoots(std::vector<const DefinedAtom *>&);
+  virtual llvm::StringRef entryPointName();
+  virtual UndefinesIterator  initialUndefinesBegin() const;
+  virtual UndefinesIterator  initialUndefinesEnd() const;
+  virtual bool searchArchivesToOverrideTentativeDefinitions();
+  virtual bool searchSharedLibrariesToOverrideTentativeDefinitions();
+  virtual bool allowUndefinedSymbol(llvm::StringRef name);
+  virtual bool printWhyLive(llvm::StringRef name);
+  virtual const Atom& handleMultipleDefinitions(const Atom& def1, 
+                                                const Atom& def2);
+  virtual void errorWithUndefines(const std::vector<const Atom *>& undefs,
+                                  const std::vector<const Atom *>& all);
+  virtual void undefineCanBeNullMismatch(const UndefinedAtom& undef1,
+                                         const UndefinedAtom& undef2,
+                                         bool& useUndef2);
+  virtual void sharedLibrarylMismatch(const SharedLibraryAtom& shLib1,
+                                      const SharedLibraryAtom& shLib2,
+                                      bool& useShlib2);
+  virtual void postResolveTweaks(std::vector<const Atom *>& all);
+  virtual Reference::Kind kindFromString(llvm::StringRef);
+  virtual llvm::StringRef kindToString(Reference::Kind);
+  virtual bool noTextRelocs();
+  virtual bool isCallSite(Reference::Kind);
+  virtual bool isGOTAccess(Reference::Kind, bool& canBypassGOT);
+  virtual void updateReferenceToGOT(const Reference*, bool targetIsNowGOT);
+  virtual const DefinedAtom* getStub(const Atom&, File&);
+  virtual void addStubAtoms(File &file);
+  virtual const DefinedAtom* makeGOTEntry(const Atom&, File&);
+  virtual void applyFixup(Reference::Kind, uint64_t addend, uint8_t*, 
+                          uint64_t fixupAddress, uint64_t targetAddress);
+  virtual void writeExecutable(const lld::File &, raw_ostream &out);
+/// @}
+/// @name Darwin specific methods
+/// @{
+  uint64_t  pageZeroSize();
+  void initializeMachHeader(const lld::File& file, class mach_header& mh);
+/// @}
+
+private:
+  llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToStub;
+  std::vector<const DefinedAtom*>                 _lazyPointers;
+  std::vector<const DefinedAtom*>                 _stubHelperAtoms;
+  const SharedLibraryAtom                        *_stubBinderAtom;
+  const DefinedAtom*                              _helperCommonAtom;
+  const DefinedAtom*                              _helperCacheAtom;
+  const DefinedAtom*                              _helperBinderAtom;
+};
+
+} // namespace darwin
+} // namespace lld
+
+#endif // LLD_PLATFORM_DARWIN_PLATFORM_H_

Added: lld/trunk/lib/Platforms/Darwin/DarwinReferenceKinds.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Platforms/Darwin/DarwinReferenceKinds.cpp?rev=154242&view=auto
==============================================================================
--- lld/trunk/lib/Platforms/Darwin/DarwinReferenceKinds.cpp (added)
+++ lld/trunk/lib/Platforms/Darwin/DarwinReferenceKinds.cpp Fri Apr  6 20:31:00 2012
@@ -0,0 +1,89 @@
+//===- Platforms/Darwin/DarwinReferenceKinds.cpp --------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "DarwinReferenceKinds.h"
+#include "llvm/ADT/StringRef.h"
+
+
+namespace lld {
+namespace darwin {
+
+  
+struct Mapping {
+  const char*           string;
+  Reference::Kind       value;
+  uint32_t              flags;
+};
+
+enum {
+  flagsNone       = 0x0000,
+  flagsIsCallSite = 0x0001,
+  flagsUsesGOT    = 0x0002,
+  flagsisGOTLoad  = 0x0006,
+  flags32RipRel   = 0x1000,
+};
+
+
+static const Mapping sKindMappings[] = {
+  { "call32",         ReferenceKind::call32,      flagsIsCallSite | flags32RipRel },
+  { "pcrel32",        ReferenceKind::pcRel32,     flags32RipRel },
+  { "gotLoad32",      ReferenceKind::gotLoad32,   flagsisGOTLoad | flags32RipRel },
+  { "gotUse32",       ReferenceKind::gotUse32,    flagsUsesGOT | flags32RipRel },
+  { "lea32wasGot",    ReferenceKind::lea32WasGot, flags32RipRel },
+  { "lazyTarget",     ReferenceKind::lazyTarget,  flagsNone },
+  { "lazyImm",        ReferenceKind::lazyImm,     flagsNone },
+  { "gotTarget",      ReferenceKind::gotTarget,   flagsNone },
+  { "pointer64",      ReferenceKind::pointer64,   flagsNone },
+  { NULL,             ReferenceKind::none,        flagsNone }
+};
+
+
+Reference::Kind ReferenceKind::fromString(StringRef kindName) {
+  for (const Mapping* p = sKindMappings; p->string != NULL; ++p) {
+    if ( kindName.equals(p->string) )
+      return p->value;
+  }
+  assert(0 && "unknown darwin reference kind");
+  return ReferenceKind::none;
+}
+
+StringRef ReferenceKind::toString(Reference::Kind kindValue) {
+  for (const Mapping* p = sKindMappings; p->string != NULL; ++p) {
+    if ( kindValue == p->value)
+      return p->string;
+  }
+  return StringRef("???");
+}
+
+bool ReferenceKind::isCallSite(Reference::Kind kindValue) {
+  for (const Mapping* p = sKindMappings; p->string != NULL; ++p) {
+    if ( kindValue == p->value )
+      return (p->flags & flagsIsCallSite);
+  }
+  return false;
+}
+
+bool ReferenceKind::isRipRel32(Reference::Kind kindValue) {
+  for (const Mapping* p = sKindMappings; p->string != NULL; ++p) {
+    if ( kindValue == p->value )
+      return (p->flags & flags32RipRel);
+  }
+  return false;
+}
+
+
+
+
+
+} // namespace darwin
+} // namespace lld
+
+
+

Added: lld/trunk/lib/Platforms/Darwin/DarwinReferenceKinds.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Platforms/Darwin/DarwinReferenceKinds.h?rev=154242&view=auto
==============================================================================
--- lld/trunk/lib/Platforms/Darwin/DarwinReferenceKinds.h (added)
+++ lld/trunk/lib/Platforms/Darwin/DarwinReferenceKinds.h Fri Apr  6 20:31:00 2012
@@ -0,0 +1,54 @@
+//===- Platforms/Darwin/DarwinReferenceKinds.h ----------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+
+
+#ifndef LLD_PLATFORM_DARWIN_REFERENCE_KINDS_H_
+#define LLD_PLATFORM_DARWIN_REFERENCE_KINDS_H_
+
+namespace lld {
+namespace darwin {
+
+
+class ReferenceKind {
+public:
+  enum {
+    none        = 0,
+    call32      = 1,
+    pcRel32     = 2,
+    gotLoad32   = 3,
+    gotUse32    = 4,
+    lea32WasGot = 5,
+    lazyTarget  = 6,
+    lazyImm     = 7,
+    gotTarget   = 8,
+    pointer64   = 9,
+  };
+
+  static Reference::Kind fromString(StringRef kindName); 
+  
+  static StringRef toString(Reference::Kind kindValue);
+  
+  static bool isCallSite(Reference::Kind kindValue);
+  
+  static bool isRipRel32(Reference::Kind kindValue);
+};
+
+
+
+} // namespace darwin
+} // namespace lld
+
+
+
+#endif // LLD_PLATFORM_DARWIN_REFERENCE_KINDS_H_
+

Added: lld/trunk/lib/Platforms/Darwin/ExecutableWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Platforms/Darwin/ExecutableWriter.cpp?rev=154242&view=auto
==============================================================================
--- lld/trunk/lib/Platforms/Darwin/ExecutableWriter.cpp (added)
+++ lld/trunk/lib/Platforms/Darwin/ExecutableWriter.cpp Fri Apr  6 20:31:00 2012
@@ -0,0 +1,1438 @@
+//===- Platforms/Darwin/ExecutableWriter.cpp ------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExecutableWriter.h"
+#include "MachOFormat.hpp"
+#include "DarwinReferenceKinds.h"
+#include "DarwinPlatform.h"
+
+#include <vector>
+#include <map>
+
+#include <string.h>
+
+#include "llvm/Support/Debug.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+
+
+namespace lld {
+namespace darwin {
+
+// 
+// A mach-o file consists of some meta data (header and load commands), 
+// then atom content (e.g. function instructions), then more meta data
+// (symbol table, etc).  Before you can write a mach-o file, you need to
+// compute what will be the file offsets and "addresses" of various things
+// in the file.  
+//
+// The design here is to break up what will be the mach-o file into chunks.  
+// Each Chunk has an object to manage its size and content.  There is a
+// chunk for the mach_header, one for the load commands, and one for each
+// part of the LINKEDIT segment.  There is also one chunk for each traditional
+// mach-o section.  The MachOWriter manages the list of chunks.  And
+// asks each to determine its size in the correct order.  Many chunks
+// cannot be sized until other chunks are sized (e.g. the dyld info
+// in the LINKEDIT cannot be sized until all atoms have been assigned 
+// addresses).
+//
+// Once all chunks have a size, the MachOWriter iterates through them and
+// asks each to write out their content.   
+//
+
+
+
+//
+// A Chunk is an abstrace contiguous range of a generated 
+// mach-o executable file.
+//
+class Chunk {
+public:
+  virtual StringRef   segmentName() const = 0;
+  virtual bool        occupiesNoDiskSpace();
+  virtual void        write(raw_ostream &out) = 0;
+  static void         writeZeros(uint64_t amount, raw_ostream &out);
+  void                assignFileOffset(uint64_t &curOff, uint64_t &curAddr);
+  virtual const char* info() = 0;
+  uint64_t            size() const;
+  uint64_t            address() const;
+  uint64_t            fileOffset() const;
+  uint64_t            align2() const;
+  static uint64_t     alignTo(uint64_t value, uint8_t align2);
+  
+protected:
+                      Chunk();
+  
+  uint64_t            _size;
+  uint64_t            _address;
+  uint64_t            _fileOffset;
+  uint32_t            _align2;
+};
+
+
+
+//
+// A SectionChunk represents a set of Atoms assigned to a specific 
+// mach-o section (which is a subrange of a mach-o segment).  
+// For example, there is one SectionChunk for the __TEXT,__text section.
+//
+class SectionChunk : public Chunk {
+public:
+  static SectionChunk*  make(DefinedAtom::ContentType, 
+                             DarwinPlatform &platform,
+                             class MachOWriter &writer);
+  virtual StringRef     segmentName() const;
+  virtual bool          occupiesNoDiskSpace();
+  virtual void          write(raw_ostream &out);
+  virtual const char*   info();
+  StringRef             sectionName();
+  uint32_t              flags() const;
+  uint32_t              permissions();
+  void                  appendAtom(const DefinedAtom*);
+
+  struct AtomInfo {
+    const DefinedAtom  *atom;
+    uint64_t            offsetInSection;
+  };
+
+  const std::vector<AtomInfo>& atoms() const;
+
+private:
+                SectionChunk(StringRef seg, 
+                             StringRef sect, 
+                             uint32_t flags, 
+                             DarwinPlatform &platform,
+                             class MachOWriter &writer);
+
+  StringRef                _segmentName;
+  StringRef                _sectionName;
+  DarwinPlatform          &_platform;
+  class MachOWriter       &_writer;
+  uint32_t                 _flags;
+  uint32_t                 _permissions;
+  std::vector<AtomInfo>    _atoms;
+};
+
+
+
+//
+// A MachHeaderChunk represents the mach_header struct at the start 
+// of a mach-o executable file.
+//
+class MachHeaderChunk : public Chunk {
+public:
+                MachHeaderChunk(DarwinPlatform &plat, const File &file);
+  virtual StringRef     segmentName() const;
+  virtual void          write(raw_ostream &out);
+  virtual const char*   info(); 
+  void                  recordLoadCommand(load_command*);
+  uint64_t              loadCommandsSize();
+
+private:
+  mach_header               _mh;
+};
+
+
+
+//
+// A LoadCommandsChunk represents the variable length list of
+// of load commands in a mach-o executable file right after the
+// mach_header.
+//
+class LoadCommandsChunk : public Chunk {
+public:
+                      LoadCommandsChunk(MachHeaderChunk&, 
+                                        DarwinPlatform&,
+                                        class MachOWriter&);
+  virtual StringRef   segmentName() const;
+  virtual void        write(raw_ostream &out);
+  virtual const char* info(); 
+  void                computeSize(const lld::File &file);
+  void                addSection(SectionChunk*);
+  void                updateLoadCommandContent(const lld::File &file);
+
+private:
+  friend class LoadCommandPaddingChunk;
+
+  void                addLoadCommand(load_command* lc);
+  void                setMachOSection(SectionChunk *chunk, 
+                                      segment_command_64 *seg, uint32_t index);
+  uint32_t            permissionsFromSections(
+                                  const SmallVector<SectionChunk*,16> &);
+
+  struct ChunkSegInfo {
+    SectionChunk*         chunk;
+    segment_command_64*   segment;
+    section_64*           section;
+  };
+
+  MachHeaderChunk             &_mh;
+  DarwinPlatform              &_platform;
+  class MachOWriter           &_writer;
+  segment_command_64          *_linkEditSegment;
+  symtab_command              *_symbolTableLoadCommand;
+  entry_point_command         *_entryPointLoadCommand;
+  dyld_info_command           *_dyldInfoLoadCommand;
+  std::vector<load_command*>   _loadCmds;
+  std::vector<ChunkSegInfo>    _sectionInfo;
+};
+
+
+
+//
+// A LoadCommandPaddingChunk represents the padding space between the last 
+// load commmand and the first section (usually __text) in the __TEXT
+// segment.
+//
+class LoadCommandPaddingChunk : public Chunk {
+public:
+                      LoadCommandPaddingChunk(LoadCommandsChunk&);
+  virtual StringRef   segmentName() const;
+  virtual void        write(raw_ostream &out);
+  virtual const char* info(); 
+  void                computeSize();
+private:
+  LoadCommandsChunk&  _loadCommandsChunk;
+};
+
+
+
+//
+// LinkEditChunk is the base class for all chunks in the
+// __LINKEDIT segment at the end of a mach-o executable. 
+//
+class LinkEditChunk : public Chunk {
+public:
+                      LinkEditChunk();
+  virtual StringRef   segmentName() const;
+  virtual void        computeSize(const lld::File &file,
+                                      const std::vector<SectionChunk*>&) = 0;
+};
+
+
+
+//
+// A DyldInfoChunk represents the bytes for any of the dyld info areas
+// in the __LINKEDIT segment at the end of a mach-o executable. 
+//
+class DyldInfoChunk : public LinkEditChunk {
+public:
+                      DyldInfoChunk(class MachOWriter &);
+  virtual void        write(raw_ostream &out);
+
+protected:
+  void                append_byte(uint8_t);
+  void                append_uleb128(uint64_t);
+  void                append_string(StringRef);
+
+  class MachOWriter      &_writer;
+  std::vector<uint8_t>    _bytes;
+};
+
+
+
+//
+// A BindingInfoChunk represents the bytes containing binding info
+// in the __LINKEDIT segment at the end of a mach-o executable. 
+//
+class BindingInfoChunk : public DyldInfoChunk {
+public:
+                      BindingInfoChunk(class MachOWriter &);
+  virtual void        computeSize(const lld::File &file,
+                                      const std::vector<SectionChunk*>&);
+  virtual const char* info(); 
+};
+
+
+
+//
+// A LazyBindingInfoChunk represents the bytes containing lazy binding info
+// in the __LINKEDIT segment at the end of a mach-o executable. 
+//
+class LazyBindingInfoChunk : public DyldInfoChunk {
+public:
+                      LazyBindingInfoChunk(class MachOWriter &);
+  virtual void        computeSize(const lld::File &file,
+                                      const std::vector<SectionChunk*>&);
+  virtual const char* info(); 
+private:
+  void                 updateHelper(const DefinedAtom *, uint32_t );
+};
+  
+
+//
+// A SymbolTableChunk represents the array of nlist structs in the
+// __LINKEDIT segment at the end of a mach-o executable. 
+//
+class SymbolTableChunk : public LinkEditChunk {
+public:
+                      SymbolTableChunk(class SymbolStringsChunk&);
+  virtual void        write(raw_ostream &out);
+  virtual void        computeSize(const lld::File &file,
+                                      const std::vector<SectionChunk*>&);
+  virtual const char* info(); 
+  uint32_t            count();
+
+private:
+  uint8_t             nType(const DefinedAtom*);
+
+  SymbolStringsChunk       &_stringsChunk;
+  std::vector<nlist_64>     _globalDefinedsymbols;
+  std::vector<nlist_64>     _localDefinedsymbols;
+  std::vector<nlist_64>     _undefinedsymbols;
+};
+
+
+//
+// A SymbolStringsChunk represents the strings pointed to
+// by nlist structs in the __LINKEDIT segment at the end 
+// of a mach-o executable. 
+//
+class SymbolStringsChunk : public LinkEditChunk {
+public:
+                      SymbolStringsChunk();
+  virtual void        write(raw_ostream &out);
+  virtual void        computeSize(const lld::File &file,
+                                      const std::vector<SectionChunk*>&);
+  virtual const char* info(); 
+  uint32_t            stringIndex(StringRef);
+
+private:
+  std::vector<char>         _strings;
+};
+
+
+//
+// A MachOWriter manages all the Chunks that comprise a mach-o executable.
+//
+class MachOWriter {
+public:
+              MachOWriter(DarwinPlatform &platform);
+  void        build(const lld::File &file);
+  void        write(raw_ostream &out);
+
+  uint64_t    addressOfAtom(const Atom *atom);
+  void        zeroFill(int64_t amount, raw_ostream &out);
+  void        findSegment(StringRef segmentName, uint32_t *segIndex,
+                                uint64_t *segStartAddr, uint64_t *segEndAddr);
+
+  const std::vector<Chunk*> chunks() { return _chunks; }
+
+private:
+  friend LoadCommandsChunk;
+  friend LazyBindingInfoChunk;
+
+  void        createChunks(const lld::File &file);
+  void        buildAtomToAddressMap();
+  void        assignFileOffsets();
+  void        addLinkEditChunk(LinkEditChunk *chunk);
+  void        buildLinkEdit(const lld::File &file);
+  void        assignLinkEditFileOffsets();
+  void        dump();
+
+
+  typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
+  
+  DarwinPlatform             &_platform;
+  LoadCommandsChunk          *_loadCommandsChunk;
+  LoadCommandPaddingChunk    *_paddingChunk;
+  AtomToAddress               _atomToAddress;
+  std::vector<Chunk*>         _chunks;
+  std::vector<SectionChunk*>  _sectionChunks;
+  std::vector<LinkEditChunk*> _linkEditChunks;
+  BindingInfoChunk           *_bindingInfo;
+  LazyBindingInfoChunk       *_lazyBindingInfo;
+  SymbolTableChunk           *_symbolTableChunk;
+  SymbolStringsChunk         *_stringsChunk;
+  uint64_t                    _linkEditStartOffset;
+  uint64_t                    _linkEditStartAddress;
+};
+
+
+
+//===----------------------------------------------------------------------===//
+//  Chunk
+//===----------------------------------------------------------------------===//
+
+Chunk::Chunk() 
+ : _size(0), _address(0), _fileOffset(0), _align2(0) {
+}
+
+bool Chunk::occupiesNoDiskSpace() { 
+  return false; 
+}
+
+uint64_t Chunk::size() const {
+  return _size;
+}
+
+uint64_t Chunk::align2() const {
+  return _align2;
+}
+
+uint64_t Chunk::address() const {
+  return _address;
+}
+
+uint64_t Chunk::fileOffset() const {
+  return _fileOffset;
+}
+
+
+void Chunk::writeZeros(uint64_t amount, raw_ostream &out) {
+  for( int i=amount; i > 0; --i)
+    out.write('\0');
+}
+
+uint64_t Chunk::alignTo(uint64_t value, uint8_t align2) {
+  uint64_t align = 1 << align2;
+  return ( (value + (align-1)) & (-align) );
+}
+
+void Chunk::assignFileOffset(uint64_t &curOffset, uint64_t &curAddress) {
+  if ( this->occupiesNoDiskSpace() ) {
+    // FileOffset does not change, but address space does change.
+    uint64_t alignedAddress = alignTo(curAddress, _align2);
+   _address = alignedAddress;
+   curAddress = alignedAddress + _size;
+  }
+  else {
+    // FileOffset and address both move by _size amount after alignment.
+    uint64_t alignPadding = alignTo(curAddress, _align2) - curAddress;
+    _fileOffset = curOffset + alignPadding;
+    _address = curAddress + alignPadding;
+    curOffset = _fileOffset + _size;
+    curAddress = _address + _size;
+  }
+  DEBUG(llvm::dbgs() << "   fileOffset=0x";
+        llvm::dbgs().write_hex(_fileOffset);
+        llvm::dbgs() << " address=0x";
+        llvm::dbgs().write_hex(_address);
+        llvm::dbgs() << " info=" << this->info() << "\n");
+} 
+
+
+
+//===----------------------------------------------------------------------===//
+//  SectionChunk
+//===----------------------------------------------------------------------===//
+
+SectionChunk::SectionChunk(StringRef seg, StringRef sect, 
+                           uint32_t flags, DarwinPlatform &platform,
+                                                MachOWriter &writer)
+ : _segmentName(seg), _sectionName(sect), _platform(platform), 
+   _writer(writer), _flags(flags), _permissions(0) {
+  
+}
+
+SectionChunk* SectionChunk::make(DefinedAtom::ContentType type, 
+                                 DarwinPlatform &platform,
+                                 MachOWriter &writer) {
+  switch ( type ) {
+    case DefinedAtom::typeCode:
+      return new SectionChunk("__TEXT", "__text", 
+                              S_REGULAR | S_ATTR_PURE_INSTRUCTIONS,
+                              platform, writer);
+      break;
+    case DefinedAtom::typeCString:
+       return new SectionChunk("__TEXT", "__cstring", 
+                               S_CSTRING_LITERALS,
+                              platform, writer);
+       break;
+    case DefinedAtom::typeStub:
+      return new SectionChunk("__TEXT", "__stubs", 
+                              S_SYMBOL_STUBS | S_ATTR_PURE_INSTRUCTIONS,
+                              platform, writer);
+      break;
+    case DefinedAtom::typeStubHelper:
+      return new SectionChunk("__TEXT", "__stub_helper", 
+                              S_REGULAR | S_ATTR_PURE_INSTRUCTIONS,
+                              platform, writer);
+      break;
+    case DefinedAtom::typeLazyPointer:
+      return new SectionChunk("__DATA", "__la_symbol_ptr", 
+                              S_LAZY_SYMBOL_POINTERS,
+                              platform, writer);
+      break;
+    case DefinedAtom::typeGOT:
+      return new SectionChunk("__DATA", "__got", 
+                              S_NON_LAZY_SYMBOL_POINTERS,
+                              platform, writer);
+      break;
+    default:
+      assert(0 && "TO DO: add support for more sections");
+      break;
+  }
+  return nullptr;
+}
+
+bool SectionChunk::occupiesNoDiskSpace() {
+  return ( (_flags & SECTION_TYPE) == S_ZEROFILL );
+}
+
+StringRef SectionChunk::segmentName() const {
+  return _segmentName;
+}
+
+StringRef SectionChunk::sectionName() {
+  return _sectionName;
+}
+
+uint32_t SectionChunk::flags() const {
+  return _flags;
+}
+
+uint32_t SectionChunk::permissions() {
+  return _permissions;
+}
+
+const char* SectionChunk::info() {
+  return _sectionName.data();
+}
+
+const std::vector<SectionChunk::AtomInfo>& SectionChunk::atoms() const {
+  return _atoms;
+}
+
+void SectionChunk::appendAtom(const DefinedAtom *atom) {
+  // Figure out offset for atom in this section given alignment constraints.
+  uint64_t offset = _size;
+  DefinedAtom::Alignment atomAlign = atom->alignment();
+  uint64_t align2 = 1 << atomAlign.powerOf2;
+  uint64_t requiredModulus = atomAlign.modulus;
+  uint64_t currentModulus = (offset % align2);
+  if ( currentModulus != requiredModulus ) {
+    if ( requiredModulus > currentModulus )
+      offset += requiredModulus-currentModulus;
+    else
+      offset += align2+requiredModulus-currentModulus;
+  }
+  // Record max alignment of any atom in this section.
+  if ( align2 > _align2 )
+    _align2 = align2;
+  // Assign atom to this section with this offset.
+  _atoms.push_back({atom, offset});
+  // Update section size to include this atom.
+  _size = offset + atom->size();
+  // Update permissions
+  DefinedAtom::ContentPermissions perms = atom->permissions();
+  if ( (perms & DefinedAtom::permR__) == DefinedAtom::permR__ )
+    _permissions |= VM_PROT_READ;
+  if ( (perms & DefinedAtom::permRW_) == DefinedAtom::permRW_ )
+    _permissions |= VM_PROT_WRITE;
+  if ( (perms & DefinedAtom::permR_X) == DefinedAtom::permR_X )
+    _permissions |= VM_PROT_EXECUTE;
+}
+
+
+void SectionChunk::write(raw_ostream &out) {
+  assert( out.tell() == _fileOffset);
+  SmallVector<uint8_t, 1024> buffer;
+  // Each section's content is just its atoms' content.
+  for (const AtomInfo &atomInfo : _atoms ) {
+    uint64_t atomFileOffset = _fileOffset + atomInfo.offsetInSection;
+    if ( atomFileOffset != out.tell() ) {
+      // Need to add alignment padding before this atom starts.
+      assert(atomFileOffset > out.tell());
+      this->writeZeros(atomFileOffset - out.tell(), out);
+    }
+    // Copy raw content of atom.
+    ArrayRef<uint8_t> content = atomInfo.atom->rawContent();
+    buffer.resize(content.size());
+    ::memcpy(buffer.data(), content.data(), content.size());
+    for (auto rit=atomInfo.atom->referencesBegin(), 
+               rend=atomInfo.atom->referencesEnd(); rit != rend; ++rit) {
+      const Reference* ref = *rit;
+      uint32_t offset = ref->offsetInAtom();
+      uint64_t targetAddress = 0;
+      if ( ref->target() != nullptr )
+        targetAddress = _writer.addressOfAtom(ref->target());
+      uint64_t fixupAddress = _writer.addressOfAtom(atomInfo.atom) + offset;
+      _platform.applyFixup(ref->kind(), ref->addend(), &buffer[offset],
+                                              fixupAddress, targetAddress);
+    }
+    for( uint8_t byte : buffer) {
+      out.write(byte);
+    }
+  }
+}
+
+//===----------------------------------------------------------------------===//
+//  MachHeaderChunk
+//===----------------------------------------------------------------------===//
+
+MachHeaderChunk::MachHeaderChunk(DarwinPlatform &platform, const File &file) {
+  // Let platform convert file info to mach-o cpu type and subtype.
+  platform.initializeMachHeader(file, _mh);
+  _size = _mh.size();
+}
+
+
+StringRef MachHeaderChunk::segmentName() const {
+  return StringRef("__TEXT");
+}
+
+void MachHeaderChunk::write(raw_ostream &out) {
+  assert( out.tell() == _fileOffset);
+  _mh.write(out);
+}
+
+const char* MachHeaderChunk::info() {
+  return "mach_header";
+}
+
+void MachHeaderChunk::recordLoadCommand(load_command* lc) {
+  _mh.recordLoadCommand(lc);
+}
+
+uint64_t MachHeaderChunk::loadCommandsSize() {
+  return _mh.sizeofcmds;
+}
+
+
+
+//===----------------------------------------------------------------------===//
+//  LoadCommandsChunk
+//===----------------------------------------------------------------------===//
+
+LoadCommandsChunk::LoadCommandsChunk(MachHeaderChunk &mh, 
+                                     DarwinPlatform& platform, 
+                                     MachOWriter& writer)
+ : _mh(mh), _platform(platform), _writer(writer),
+   _linkEditSegment(nullptr), _symbolTableLoadCommand(nullptr),
+   _entryPointLoadCommand(nullptr), _dyldInfoLoadCommand(nullptr) {
+}
+
+
+StringRef LoadCommandsChunk::segmentName() const {
+  return StringRef("__TEXT");
+}
+
+void LoadCommandsChunk::write(raw_ostream &out) {
+  assert( out.tell() == _fileOffset);
+  for ( load_command* lc : _loadCmds ) {
+    lc->write(out);
+  }
+}
+
+const char* LoadCommandsChunk::info() {
+  return "load commands";
+}
+
+void LoadCommandsChunk::setMachOSection(SectionChunk *chunk, 
+                                    segment_command_64 *seg, uint32_t index) {
+  for (ChunkSegInfo &entry : _sectionInfo) {
+    if ( entry.chunk == chunk ) {
+      entry.section = &(seg->sections[index]);
+      entry.segment = seg;
+      return;
+    }
+  }
+  assert(0 && "setMachOSection() chunk not found");
+}
+
+uint32_t LoadCommandsChunk::permissionsFromSections(
+                        const SmallVector<SectionChunk*,16> &sections) {
+  uint32_t result = 0;
+  for (SectionChunk *chunk : sections) {
+    result |= chunk->permissions();
+  }
+  return result;
+}
+
+void LoadCommandsChunk::computeSize(const lld::File &file) {
+  // Main executables have a __PAGEZERO segment.
+  uint64_t pageZeroSize = _platform.pageZeroSize();
+  if ( pageZeroSize != 0 ) {
+    segment_command_64* pzSegCmd = segment_command_64::make(0);
+    strcpy(pzSegCmd->segname, "__PAGEZERO");
+    pzSegCmd->vmaddr   = 0;
+    pzSegCmd->vmsize   = pageZeroSize;
+    pzSegCmd->fileoff  = 0;
+    pzSegCmd->filesize = 0;
+    pzSegCmd->maxprot  = 0;
+    pzSegCmd->initprot = 0;
+    pzSegCmd->nsects   = 0;
+    pzSegCmd->flags    = 0;
+    this->addLoadCommand(pzSegCmd);
+  }
+  // Add other segment load commands
+  StringRef lastSegName = StringRef("__TEXT");
+  SmallVector<SectionChunk*,16> sections;
+  for (ChunkSegInfo &entry : _sectionInfo) {
+    StringRef entryName = entry.chunk->segmentName();
+    if ( !lastSegName.equals(entryName) ) {
+      // Start of new segment, so create load command for all previous sections.
+      segment_command_64* segCmd = segment_command_64::make(sections.size());
+      strncpy(segCmd->segname, lastSegName.data(), 16);
+      segCmd->initprot = this->permissionsFromSections(sections);
+      segCmd->maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
+      this->addLoadCommand(segCmd);
+      unsigned int index = 0;
+      for (SectionChunk *chunk : sections) {
+        this->setMachOSection(chunk, segCmd, index);
+        ++index;
+      }
+      // Reset to begin new segment.
+      sections.clear();
+      lastSegName = entryName;
+    }
+    sections.push_back(entry.chunk);
+  }
+  // Add last segment load command.
+  segment_command_64* segCmd = segment_command_64::make(sections.size());
+  strncpy(segCmd->segname, lastSegName.data(), 16);
+  segCmd->initprot = this->permissionsFromSections(sections);;
+  segCmd->maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
+  this->addLoadCommand(segCmd);
+  unsigned int index = 0;
+  for (SectionChunk *chunk : sections) {
+    this->setMachOSection(chunk, segCmd, index);
+    ++index;
+  }
+
+  // Add LINKEDIT segment load command
+  _linkEditSegment = segment_command_64::make(0);
+  strcpy(_linkEditSegment->segname, "__LINKEDIT");
+  _linkEditSegment->initprot = VM_PROT_READ;
+  _linkEditSegment->maxprot = VM_PROT_READ;
+  this->addLoadCommand(_linkEditSegment);
+
+  // Add dyld load command.
+  this->addLoadCommand(dylinker_command::make("/usr/lib/dyld"));
+
+  // Add dylib load commands.
+  llvm::StringMap<uint32_t> dylibNamesToOrdinal;
+  for (const SharedLibraryAtom* shlibAtom : file.sharedLibrary() ) {
+    StringRef installName = shlibAtom->loadName();
+    if ( dylibNamesToOrdinal.count(installName) == 0 ) {
+      uint32_t ord = dylibNamesToOrdinal.size();
+      dylibNamesToOrdinal[installName] = ord;
+    }
+  }
+  for (llvm::StringMap<uint32_t>::iterator it=dylibNamesToOrdinal.begin(),
+                            end=dylibNamesToOrdinal.end(); it != end; ++it) {
+    this->addLoadCommand(dylib_command::make(it->first().data()));
+  }
+  
+  // Add symbol table load command
+  _symbolTableLoadCommand = symtab_command::make();
+  this->addLoadCommand(_symbolTableLoadCommand);
+ 
+  // Add dyld info load command
+  _dyldInfoLoadCommand = dyld_info_command::make();
+  this->addLoadCommand(_dyldInfoLoadCommand);
+  
+  // Add entry point load command
+  _entryPointLoadCommand = entry_point_command::make();
+  this->addLoadCommand(_entryPointLoadCommand);
+    
+  // Compute total size.
+  _size = _mh.loadCommandsSize();
+}
+
+
+void LoadCommandsChunk::updateLoadCommandContent(const lld::File &file) {
+  // Update segment/section information in segment load commands
+  segment_command_64 *lastSegment = nullptr;
+  for (ChunkSegInfo &entry : _sectionInfo) {
+    // Set section info.
+    ::strncpy(entry.section->sectname, entry.chunk->sectionName().data(), 16);
+    ::strncpy(entry.section->segname, entry.chunk->segmentName().data(), 16);
+    entry.section->addr   = entry.chunk->address();
+    entry.section->size   = entry.chunk->size();
+    entry.section->offset = entry.chunk->fileOffset();
+    entry.section->align  = entry.chunk->align2();
+    entry.section->reloff = 0;
+    entry.section->nreloc = 0;
+    entry.section->flags  = entry.chunk->flags();
+    // Adjust segment info if needed.
+    if ( entry.segment != lastSegment ) {
+      // This is first section in segment.
+      if ( strcmp(entry.segment->segname, "__TEXT") == 0 ) {
+        // __TEXT segment is special need mach_header section.
+        entry.segment->vmaddr = _writer._chunks.front()->address();
+        entry.segment->fileoff = _writer._chunks.front()->fileOffset();
+      }
+      else {
+        entry.segment->vmaddr  = entry.chunk->address();
+        entry.segment->fileoff = entry.chunk->fileOffset();
+      }
+      
+      lastSegment = entry.segment;
+    }
+    uint64_t sectionEndAddr = entry.section->addr + entry.section->size;
+    if ( entry.segment->vmaddr + entry.segment->vmsize < sectionEndAddr) {
+      uint64_t sizeToEndOfSection = sectionEndAddr - entry.segment->vmaddr;
+      entry.segment->vmsize = alignTo(sizeToEndOfSection, 12);
+      // zero-fill sections do not increase the segment's filesize
+      if ( ! entry.chunk->occupiesNoDiskSpace() ) {
+        entry.segment->filesize = alignTo(sizeToEndOfSection, 12);
+      }
+    }
+  }
+  uint64_t linkEditSize = _writer._stringsChunk->fileOffset() 
+                        + _writer._stringsChunk->size()
+                        - _writer._linkEditStartOffset;
+  _linkEditSegment->vmaddr   = _writer._linkEditStartAddress;
+  _linkEditSegment->vmsize   = alignTo(linkEditSize,12);
+  _linkEditSegment->fileoff  = _writer._linkEditStartOffset;
+  _linkEditSegment->filesize = linkEditSize;
+  
+  // Update dyld_info load command.
+  _dyldInfoLoadCommand->bind_off       = _writer._bindingInfo->fileOffset();
+  _dyldInfoLoadCommand->bind_size      = _writer._bindingInfo->size();
+  _dyldInfoLoadCommand->lazy_bind_off  = _writer._lazyBindingInfo->fileOffset();
+  _dyldInfoLoadCommand->lazy_bind_size = _writer._lazyBindingInfo->size();
+  
+  
+  // Update symbol table load command.
+  _symbolTableLoadCommand->symoff  = _writer._symbolTableChunk->fileOffset();
+  _symbolTableLoadCommand->nsyms   = _writer._symbolTableChunk->count();
+  _symbolTableLoadCommand->stroff  = _writer._stringsChunk->fileOffset();
+  _symbolTableLoadCommand->strsize = _writer._stringsChunk->size();
+
+  // Update entry point
+  if ( _entryPointLoadCommand != nullptr ) {
+    const Atom *mainAtom = file.entryPoint();
+    assert(mainAtom != nullptr);
+    uint32_t entryOffset = _writer.addressOfAtom(mainAtom) - _mh.address();
+    _entryPointLoadCommand->entryoff = entryOffset;
+  }
+}
+
+
+void LoadCommandsChunk::addSection(SectionChunk* chunk) {
+  _sectionInfo.push_back({chunk, nullptr, nullptr});
+}
+
+void LoadCommandsChunk::addLoadCommand(load_command* lc) {
+  _mh.recordLoadCommand(lc);
+  _loadCmds.push_back(lc);
+}
+
+
+
+//===----------------------------------------------------------------------===//
+//  LoadCommandPaddingChunk
+//===----------------------------------------------------------------------===//
+
+LoadCommandPaddingChunk::LoadCommandPaddingChunk(LoadCommandsChunk& lcc)
+  : _loadCommandsChunk(lcc) {
+}
+
+StringRef LoadCommandPaddingChunk::segmentName() const {
+  return StringRef("__TEXT");
+}
+
+void LoadCommandPaddingChunk::write(raw_ostream &out) {
+  assert( out.tell() == _fileOffset);
+  // Zero fill padding.
+  this->writeZeros(_size, out);
+}
+
+const char* LoadCommandPaddingChunk::info() {
+  return "padding";
+}
+
+// Segments are page sized.  Normally, any extra space not used by atoms
+// is put at the end of the last page.  But the __TEXT segment is special.
+// Any extra space is put between the load commands and the first section.
+// The padding is put there to allow the load commands to be
+// post-processed which might potentially grow them.
+void LoadCommandPaddingChunk::computeSize() {
+ // Layout __TEXT sections backwards from end of page to get padding up front.
+  uint64_t addr = 0;
+  std::vector<LoadCommandsChunk::ChunkSegInfo>& sects 
+                                        = _loadCommandsChunk._sectionInfo;
+  for (auto it=sects.rbegin(), end=sects.rend(); it != end; ++it) {
+    LoadCommandsChunk::ChunkSegInfo &entry = *it;
+    if ( !entry.chunk->segmentName().equals("__TEXT") )
+      continue;
+    addr -= entry.chunk->size();
+    addr = addr & (0 - (1 << entry.chunk->align2()));
+  }
+  // Subtract out size of mach_header and all load commands.
+  addr -= _loadCommandsChunk._mh.size();
+  addr -= _loadCommandsChunk.size();
+  // Modulo page size to get padding needed between load commands 
+  // and first section.
+  _size = (addr % 4096); 
+}
+
+//===----------------------------------------------------------------------===//
+//  LinkEditChunk
+//===----------------------------------------------------------------------===//
+
+LinkEditChunk::LinkEditChunk() {
+  _align2 = 3;
+}
+
+StringRef LinkEditChunk::segmentName() const {
+  return StringRef("__LINKEDIT");
+}
+
+  
+//===----------------------------------------------------------------------===//
+//  DyldInfoChunk
+//===----------------------------------------------------------------------===//
+DyldInfoChunk::DyldInfoChunk(MachOWriter &writer)
+ : _writer(writer) {
+}
+
+void DyldInfoChunk::write(raw_ostream &out) {
+  assert( out.tell() == _fileOffset);
+  for ( uint8_t byte : _bytes ) {
+    out.write(byte);
+  }
+}
+
+void DyldInfoChunk::append_byte(uint8_t b) {
+  _bytes.push_back(b);
+}
+
+void DyldInfoChunk::append_string(StringRef str) {
+  const char *s = str.data();
+  for (int i=str.size(); i > 0; --i) {
+    _bytes.push_back(*s++);
+  }
+  _bytes.push_back('\0');
+}
+
+void DyldInfoChunk::append_uleb128(uint64_t value) {
+  uint8_t byte;
+  do {
+    byte = value & 0x7F;
+    value &= ~0x7F;
+    if ( value != 0 )
+      byte |= 0x80;
+    _bytes.push_back(byte);
+    value = value >> 7;
+  } while( byte >= 0x80 );
+}
+
+
+
+//===----------------------------------------------------------------------===//
+//  BindingInfoChunk
+//===----------------------------------------------------------------------===//
+
+BindingInfoChunk::BindingInfoChunk(MachOWriter &writer)
+ : DyldInfoChunk(writer) {
+}
+
+const char* BindingInfoChunk::info() {
+  return "binding info";
+}
+
+void BindingInfoChunk::computeSize(const lld::File &file,
+                                    const std::vector<SectionChunk*> &chunks) {
+  for (const SectionChunk *chunk : chunks ) {
+    // skip lazy pointer section
+    if ( chunk->flags() == S_LAZY_SYMBOL_POINTERS )
+      continue;
+    // skip code sections
+    if ( chunk->flags() == (S_REGULAR | S_ATTR_PURE_INSTRUCTIONS) )
+      continue;
+    uint64_t segStartAddr = 0;
+    uint64_t segEndAddr = 0;
+    uint32_t segIndex = 0;
+    _writer.findSegment(chunk->segmentName(),
+                                    &segIndex, &segStartAddr, &segEndAddr);
+    for (const SectionChunk::AtomInfo &info : chunk->atoms() ) {
+      const DefinedAtom* atom = info.atom;
+      StringRef targetName;
+      int ordinal;
+  
+      // look for fixups pointing to shlib atoms
+      for (const Reference *ref : *atom ) {
+        const Atom *target = ref->target();
+        if ( target != nullptr ) {
+          const SharedLibraryAtom *shlTarget 
+                                        = dyn_cast<SharedLibraryAtom>(target);
+          if ( shlTarget != nullptr ) {
+            assert(ref->kind() == ReferenceKind::pointer64);
+            targetName = shlTarget->name();
+            ordinal = 1;
+          }
+        }
+      }
+      
+      if ( targetName.empty() )
+        continue;
+      
+      // write location of fixup
+      this->append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segIndex);
+      uint64_t address = _writer.addressOfAtom(atom);
+      this->append_uleb128(address - segStartAddr);
+
+      // write ordinal
+      if ( ordinal <= 0 ) {
+        // special lookups are encoded as negative numbers in BindingInfo
+        this->append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
+                                          | (ordinal & BIND_IMMEDIATE_MASK) );
+      }
+      else if ( ordinal <= 15 ) {
+        // small ordinals are encoded in opcode
+        this->append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | ordinal);
+      }
+      else {
+        this->append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+        this->append_uleb128(ordinal);
+      }
+      
+      // write binding type
+      this->append_byte(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER);
+      
+      // write symbol name and flags
+      int flags = 0;
+      this->append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags);
+      this->append_string(targetName);
+
+      // write do bind
+      this->append_byte(BIND_OPCODE_DO_BIND);
+      this->append_byte(BIND_OPCODE_DONE);
+    }
+  }
+  _size = _bytes.size();
+}
+
+
+//===----------------------------------------------------------------------===//
+//  LazyBindingInfoChunk
+//===----------------------------------------------------------------------===//
+
+LazyBindingInfoChunk::LazyBindingInfoChunk(MachOWriter &writer)
+ : DyldInfoChunk(writer) {
+}
+
+const char* LazyBindingInfoChunk::info() {
+  return "lazy binding info";
+}
+
+void LazyBindingInfoChunk::updateHelper(const DefinedAtom *lazyPointerAtom,
+                                        uint32_t offset) {
+  for (const Reference *ref : *lazyPointerAtom ) {
+    if ( ref->kind() != ReferenceKind::pointer64 )
+      continue;
+    const DefinedAtom *helperAtom = dyn_cast<DefinedAtom>(ref->target());
+    assert(helperAtom != nullptr);
+    for (const Reference *href : *helperAtom ) {
+      if ( href->kind() == ReferenceKind::lazyImm ) {
+        (const_cast<Reference*>(href))->setAddend(offset);
+        return;
+      }
+    }
+  }
+  assert(0 && "could not update helper lazy immediate value");
+}
+
+void LazyBindingInfoChunk::computeSize(const lld::File &file,
+                                    const std::vector<SectionChunk*> &chunks) {
+  for (const SectionChunk *chunk : chunks ) {
+    if ( chunk->flags() != S_LAZY_SYMBOL_POINTERS )
+      continue;
+    uint64_t segStartAddr = 0;
+    uint64_t segEndAddr = 0;
+    uint32_t segIndex = 0;
+    _writer.findSegment(chunk->segmentName(),
+                                    &segIndex, &segStartAddr, &segEndAddr);
+    for (const SectionChunk::AtomInfo &info : chunk->atoms() ) {
+      const DefinedAtom *lazyPointerAtom = info.atom;
+      assert(lazyPointerAtom->contentType() == DefinedAtom::typeLazyPointer);
+      // Update help to have offset of the lazy binding info.
+      this->updateHelper(lazyPointerAtom, _bytes.size());
+
+      // Write location of fixup.
+      this->append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segIndex);
+      uint64_t address = _writer.addressOfAtom(lazyPointerAtom);
+      this->append_uleb128(address - segStartAddr);
+
+      // write ordinal
+      int ordinal = 1;
+      if ( ordinal <= 0 ) {
+        // special lookups are encoded as negative numbers in BindingInfo
+        this->append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
+                                          | (ordinal & BIND_IMMEDIATE_MASK) );
+      }
+      else if ( ordinal <= 15 ) {
+        // small ordinals are encoded in opcode
+        this->append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | ordinal);
+      }
+      else {
+        this->append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+        this->append_uleb128(ordinal);
+      }
+      
+      // write symbol name and flags
+      int flags = 0;
+      StringRef name;
+      for (const Reference *ref : *lazyPointerAtom ) {
+        if ( ref->kind() == ReferenceKind::lazyTarget ) {
+          const Atom *shlib = ref->target();
+          assert(shlib != nullptr);
+          name = shlib->name();
+        }
+      }
+      assert(!name.empty());
+      this->append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags);
+      this->append_string(name);
+
+      // write do bind
+      this->append_byte(BIND_OPCODE_DO_BIND);
+      this->append_byte(BIND_OPCODE_DONE);
+    }
+  }
+  _size = _bytes.size();
+}
+
+
+//===----------------------------------------------------------------------===//
+//  SymbolTableChunk
+//===----------------------------------------------------------------------===//
+
+SymbolTableChunk::SymbolTableChunk(SymbolStringsChunk& str) 
+  : _stringsChunk(str) {
+}
+
+void SymbolTableChunk::write(raw_ostream &out) {
+  assert( out.tell() == _fileOffset);
+  for ( nlist_64 &sym : _globalDefinedsymbols ) {
+    sym.write(out);
+  }
+  for ( nlist_64 &sym : _localDefinedsymbols ) {
+    sym.write(out);
+  }
+  for ( nlist_64 &sym : _undefinedsymbols ) {
+    sym.write(out);
+  }
+}
+
+const char* SymbolTableChunk::info() {
+  return "symbol tables ";
+}
+
+uint32_t SymbolTableChunk::count() {
+  return _globalDefinedsymbols.size() 
+       + _localDefinedsymbols.size()
+       + _undefinedsymbols.size();
+}
+
+uint8_t SymbolTableChunk::nType(const DefinedAtom *atom) {
+  uint8_t result = N_SECT;
+  switch ( atom->scope() ) {
+    case DefinedAtom::scopeTranslationUnit:
+      break;
+    case DefinedAtom::scopeLinkageUnit:
+      result |= N_EXT | N_PEXT;
+      break;
+    case DefinedAtom::scopeGlobal:
+      result |= N_EXT;
+      break;
+  }
+  return result;
+}
+
+void SymbolTableChunk::computeSize(const lld::File &file,
+                                   const std::vector<SectionChunk*> &chunks) {
+  // Add symbols for definitions
+  unsigned int sectionIndex = 1;
+  for (const SectionChunk *chunk : chunks ) {
+    for (const SectionChunk::AtomInfo &info : chunk->atoms() ) {
+      if ( info.atom->name().empty() )
+        continue;
+      uint64_t atomAddress = chunk->address() + info.offsetInSection;
+      nlist_64 sym;
+      sym.n_strx = _stringsChunk.stringIndex(info.atom->name());
+      sym.n_type = this->nType(info.atom);
+      sym.n_sect = sectionIndex;
+      sym.n_value = atomAddress;
+      if ( info.atom->scope() == DefinedAtom::scopeGlobal )
+        _globalDefinedsymbols.push_back(sym);
+      else
+        _localDefinedsymbols.push_back(sym);
+    }
+    ++sectionIndex;
+  }
+  
+  // Add symbols for undefined/sharedLibrary symbols
+  for (const SharedLibraryAtom* atom : file.sharedLibrary() ) {
+    nlist_64 sym;
+    sym.n_strx = _stringsChunk.stringIndex(atom->name());
+    sym.n_type = N_UNDF;
+    sym.n_sect = 0;
+    sym.n_value = 0;
+    _undefinedsymbols.push_back(sym);
+  }
+  
+  _size = sizeof(nlist_64) * this->count();
+}
+
+
+//===----------------------------------------------------------------------===//
+//  SymbolStringsChunk
+//===----------------------------------------------------------------------===//
+
+SymbolStringsChunk::SymbolStringsChunk() {
+  // mach-o reserves the first byte in the string pool so that 
+  // zero is never a valid string index.
+  _strings.push_back('\0');
+}
+
+
+void SymbolStringsChunk::write(raw_ostream &out) {
+  assert( out.tell() == _fileOffset);
+  for ( char c : _strings ) {
+    out.write(c);
+  }
+}
+
+const char* SymbolStringsChunk::info() {
+  return "symbol strings ";
+}
+
+void SymbolStringsChunk::computeSize(const lld::File &file,
+                                     const std::vector<SectionChunk*>&) {
+  _size = _strings.size();
+}
+
+
+uint32_t SymbolStringsChunk::stringIndex(StringRef str) {
+  uint32_t result = _strings.size();
+  const char* s = str.data();
+  for (int i=0; i < str.size(); ++i) {
+    _strings.push_back(s[i]);
+  }
+  _strings.push_back('\0');
+  return result;
+}
+
+
+//===----------------------------------------------------------------------===//
+//  MachOWriter
+//===----------------------------------------------------------------------===//
+
+MachOWriter::MachOWriter(DarwinPlatform &platform)
+  : _platform(platform), _bindingInfo(nullptr), _lazyBindingInfo(nullptr),
+    _symbolTableChunk(nullptr), _stringsChunk(nullptr),
+    _linkEditStartOffset(0), _linkEditStartAddress(0) {
+}
+ 
+void MachOWriter::build(const lld::File &file) {
+  // Create objects for each chunk.
+  this->createChunks(file);
+  
+  // Now that SectionChunks have sizes, load commands can be laid out
+  _loadCommandsChunk->computeSize(file);
+ 
+  // Now that load commands are sized, padding can be computed
+  _paddingChunk->computeSize();
+  
+  // Now that all chunks (except linkedit) have sizes, assign file offsets
+  this->assignFileOffsets();
+  
+  // Now chunks have file offsets each atom can be assigned an address
+  this->buildAtomToAddressMap();
+  
+  // Now that atoms have address, symbol table can be build
+  this->buildLinkEdit(file);
+  
+  // Assign file offsets to linkedit chunks
+  this->assignLinkEditFileOffsets();
+  
+  // Finally, update load commands to reflect linkEdit layout
+  _loadCommandsChunk->updateLoadCommandContent(file);
+}
+
+
+void MachOWriter::createChunks(const lld::File &file) {
+  // Assign atoms to chunks, creating new chunks as needed
+  std::map<DefinedAtom::ContentType, SectionChunk*> map;
+  for (const DefinedAtom* atom : file.defined() ) {
+    assert( atom->sectionChoice() == DefinedAtom::sectionBasedOnContent );
+    DefinedAtom::ContentType type = atom->contentType();
+    auto pos = map.find(type);
+    if ( pos == map.end() ) {
+      SectionChunk *chunk = SectionChunk::make(type, _platform, *this);
+      map[type] = chunk;
+      chunk->appendAtom(atom);
+    }
+    else {
+      pos->second->appendAtom(atom);
+    }
+  }
+  
+  // Sort Chunks so ones in same segment are contiguous.
+  
+  
+  // Make chunks in __TEXT for mach_header and load commands at start.
+  MachHeaderChunk *mhc = new MachHeaderChunk(_platform, file);
+  _chunks.push_back(mhc);
+  
+  _loadCommandsChunk = new LoadCommandsChunk(*mhc, _platform, *this);
+  _chunks.push_back(_loadCommandsChunk);
+  
+  _paddingChunk = new LoadCommandPaddingChunk(*_loadCommandsChunk);
+  _chunks.push_back(_paddingChunk);
+  
+  for (auto it=map.begin(); it != map.end(); ++it) {
+     _chunks.push_back(it->second);
+     _sectionChunks.push_back(it->second);
+     _loadCommandsChunk->addSection(it->second);
+  }
+  
+  // Make LINKEDIT chunks.
+  _bindingInfo = new BindingInfoChunk(*this);
+  _lazyBindingInfo = new LazyBindingInfoChunk(*this);
+  _stringsChunk = new SymbolStringsChunk();
+  _symbolTableChunk = new SymbolTableChunk(*_stringsChunk);
+  this->addLinkEditChunk(_bindingInfo);
+  this->addLinkEditChunk(_lazyBindingInfo);
+  this->addLinkEditChunk(_symbolTableChunk);
+  this->addLinkEditChunk(_stringsChunk);
+}
+ 
+
+void MachOWriter::addLinkEditChunk(LinkEditChunk *chunk) {
+  _linkEditChunks.push_back(chunk);
+  _chunks.push_back(chunk);
+}
+
+
+void MachOWriter::buildAtomToAddressMap() {
+  DEBUG(llvm::dbgs() << "assign atom addresses:\n");
+  for (SectionChunk *chunk : _sectionChunks ) {
+    for (const SectionChunk::AtomInfo &info : chunk->atoms() ) {
+      _atomToAddress[info.atom] = chunk->address() + info.offsetInSection;
+      DEBUG(llvm::dbgs() << "   address=0x";
+            llvm::dbgs().write_hex(_atomToAddress[info.atom]);
+            llvm::dbgs() << " atom=" << info.atom;
+            llvm::dbgs() << " name=" << info.atom->name() << "\n");
+    }
+  }
+}
+
+
+//void MachOWriter::dump() {
+//  for ( Chunk *chunk : _chunks ) {
+//    fprintf(stderr, "size=0x%08llX, fileOffset=0x%08llX, address=0x%08llX %s\n",
+//          chunk->size(), chunk->fileOffset(),chunk->address(), chunk->info());
+//  }
+//}
+
+void MachOWriter::assignFileOffsets() {
+  DEBUG(llvm::dbgs() << "assign file offsets:\n");
+  uint64_t offset = 0;
+  uint64_t address = _platform.pageZeroSize();
+  for ( Chunk *chunk : _chunks ) {
+    if ( chunk->segmentName().equals("__LINKEDIT") ) {
+      _linkEditStartOffset  = Chunk::alignTo(offset, 12);
+      _linkEditStartAddress = Chunk::alignTo(address, 12);
+      break;
+    }
+    chunk->assignFileOffset(offset, address);
+  }
+}
+
+void MachOWriter::assignLinkEditFileOffsets() {
+  DEBUG(llvm::dbgs() << "assign LINKEDIT file offsets:\n");
+  uint64_t offset = _linkEditStartOffset;
+  uint64_t address = _linkEditStartAddress;
+  for ( Chunk *chunk : _linkEditChunks ) {
+    chunk->assignFileOffset(offset, address);
+  }
+}
+
+void MachOWriter::buildLinkEdit(const lld::File &file) {
+  for (LinkEditChunk *chunk : _linkEditChunks) {
+    chunk->computeSize(file, _sectionChunks);
+  }
+}
+
+
+uint64_t MachOWriter::addressOfAtom(const Atom *atom) {
+  return _atomToAddress[atom];
+}
+
+
+void MachOWriter::findSegment(StringRef segmentName, uint32_t *segIndex,
+                                uint64_t *segStartAddr, uint64_t *segEndAddr) {
+  const uint64_t kInvalidAddress = (uint64_t)(-1);
+  StringRef lastSegName("__TEXT");
+  *segIndex = 0;
+  if ( _platform.pageZeroSize() != 0 ) {
+      *segIndex = 1;
+  }
+  *segStartAddr = kInvalidAddress;
+  *segEndAddr = kInvalidAddress;
+  for (SectionChunk *chunk : _sectionChunks ) {
+    if ( ! lastSegName.equals(chunk->segmentName()) ) {
+      *segIndex += 1;
+      lastSegName = chunk->segmentName();
+    }
+    if ( chunk->segmentName().equals(segmentName) ) {
+      uint64_t  chunkEndAddr = chunk->address() + chunk->size();
+      if ( *segStartAddr == kInvalidAddress ) {
+        *segStartAddr = chunk->address();
+        *segEndAddr = chunkEndAddr;
+      }
+      else if ( *segEndAddr < chunkEndAddr ) {
+        *segEndAddr = chunkEndAddr;
+      }
+    }
+
+  }
+}
+
+
+void MachOWriter::zeroFill(int64_t amount, raw_ostream &out) {
+  for( int i=amount; i > 0; --i)
+    out.write('\0');
+}
+
+
+void MachOWriter::write(raw_ostream &out) {
+  for ( Chunk *chunk : _chunks ) {
+    if ( out.tell() != chunk->fileOffset() ) {
+      // Assume just alignment padding to start of next section.
+      assert( out.tell() < chunk->fileOffset() );
+      uint64_t padding = chunk->fileOffset() - out.tell();
+      chunk->writeZeros(padding, out);
+    }
+    chunk->write(out);
+  }
+}
+
+
+//
+// Creates a mach-o final linked image from the given atom graph and writes
+// it to the supplied output stream.
+//
+void writeExecutable(const lld::File &file, DarwinPlatform &platform, 
+                                            raw_ostream &out) {
+  MachOWriter writer(platform);
+  writer.build(file);
+  writer.write(out);
+}
+
+
+
+} // namespace darwin
+} // namespace lld
+

Added: lld/trunk/lib/Platforms/Darwin/ExecutableWriter.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Platforms/Darwin/ExecutableWriter.h?rev=154242&view=auto
==============================================================================
--- lld/trunk/lib/Platforms/Darwin/ExecutableWriter.h (added)
+++ lld/trunk/lib/Platforms/Darwin/ExecutableWriter.h Fri Apr  6 20:31:00 2012
@@ -0,0 +1,35 @@
+//===- Platforms/Darwin/ExecutableWriter.h --------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "lld/Core/LLVM.h"
+
+
+#ifndef LLD_PLATFORM_DARWIN_EXECUTABLE_WRITER_H_
+#define LLD_PLATFORM_DARWIN_EXECUTABLE_WRITER_H_
+
+namespace lld {
+
+class File;
+
+namespace darwin {
+
+class DarwinPlatform;
+
+void writeExecutable(const lld::File &file, DarwinPlatform &platform, 
+                                            raw_ostream &out);
+
+
+} // namespace darwin
+} // namespace lld
+
+
+
+#endif // LLD_PLATFORM_DARWIN_EXECUTABLE_WRITER_H_
+

Added: lld/trunk/lib/Platforms/Darwin/MachOFormat.hpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Platforms/Darwin/MachOFormat.hpp?rev=154242&view=auto
==============================================================================
--- lld/trunk/lib/Platforms/Darwin/MachOFormat.hpp (added)
+++ lld/trunk/lib/Platforms/Darwin/MachOFormat.hpp Fri Apr  6 20:31:00 2012
@@ -0,0 +1,346 @@
+//===- Platforms/Darwin/MachOFormat.hpp -----------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//
+// This file contains all the structs and constants needed to write a 
+// mach-o final linked image.  The names of the structs and constants
+// are the same as in the darwin native header <mach-o/loader.h> so
+// they will be familiar to anyone who has used that header.
+//
+
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/raw_ostream.h"
+
+
+#ifndef LLD_PLATFORM_DARWIN_MACHO_FORMAT_H_
+#define LLD_PLATFORM_DARWIN_MACHO_FORMAT_H_
+
+namespace lld {
+namespace darwin {
+
+class load_command {
+public:
+  uint32_t  cmd;  
+  uint32_t  cmdsize;
+  
+  void write(raw_ostream& out) {
+    out.write((char*)&cmd, cmdsize);
+  }
+};
+
+enum { 
+  MH_MAGIC = 0xfeedface,
+  MAGIC_64 = 0xfeedfacf 
+};
+
+enum {
+  CPU_TYPE_I386 =   0x00000007,
+  CPU_TYPE_X86_64 = 0x01000007
+};
+
+enum {
+  CPU_SUBTYPE_X86_ALL = 0x00000003,
+  CPU_SUBTYPE_X86_64_ALL = 0x00000003
+};
+
+enum {
+  MH_EXECUTE   = 0x2,
+  MH_DYLIB     = 0x6,
+  MH_BUNDLE    = 0x8
+};
+
+
+class mach_header {
+public:
+  uint32_t    magic;  
+  uint32_t    cputype;
+  uint32_t    cpusubtype;  
+  uint32_t    filetype;  
+  uint32_t    ncmds;    
+  uint32_t    sizeofcmds;  
+  uint32_t    flags;  
+   uint32_t    reserved;  
+ 
+  uint64_t size() {
+    return (magic == 0xfeedfacf) ? 32 : 28;
+  }
+  
+  void write(raw_ostream& out) {
+    out.write((char*)&magic, this->size());
+  }
+ 
+  void recordLoadCommand(const class load_command* lc) {
+    ++ncmds;
+    sizeofcmds += lc->cmdsize;
+  }
+    
+
+};
+
+enum {
+  SECTION_TYPE              = 0x000000FF,
+  S_REGULAR                 = 0x00000000,
+  S_ZEROFILL                = 0x00000001,
+  S_CSTRING_LITERALS        = 0x00000002,
+  S_NON_LAZY_SYMBOL_POINTERS= 0x00000006,
+  S_LAZY_SYMBOL_POINTERS    = 0x00000007,
+  S_SYMBOL_STUBS            = 0x00000008,
+  
+  S_ATTR_PURE_INSTRUCTIONS  = 0x80000000,
+  S_ATTR_SOME_INSTRUCTIONS  = 0x00000400
+};
+
+struct section_64 {
+  char      sectname[16];  
+  char      segname[16];  
+  uint64_t  addr;  
+  uint64_t  size;    
+  uint32_t  offset;  
+  uint32_t  align;    
+  uint32_t  reloff;  
+  uint32_t  nreloc;    
+  uint32_t  flags;    
+  uint32_t  reserved1;
+  uint32_t  reserved2;  
+  uint32_t  reserved3;
+};
+
+enum {
+  LC_SEGMENT_64 = 0x19
+};
+
+enum {
+  VM_PROT_NONE    = 0x0,
+  VM_PROT_READ    = 0x1,
+  VM_PROT_WRITE   = 0x2,
+  VM_PROT_EXECUTE = 0x4,
+};
+
+
+
+class segment_command_64 : public load_command {
+public:
+  char      segname[16];  
+  uint64_t  vmaddr;    
+  uint64_t  vmsize;    
+  uint64_t  fileoff;  
+  uint64_t  filesize;  
+  uint32_t  maxprot;  
+  uint32_t  initprot;  
+  uint32_t  nsects;    
+  uint32_t  flags;  
+  section_64 sections[];
+  
+  // The segment_command_64 load commands has a nsect trailing
+  // section_64 records appended to the end.
+  static segment_command_64* make(unsigned sectCount) {
+    unsigned size = sizeof(segment_command_64) + sectCount* sizeof(section_64);
+    segment_command_64* result = reinterpret_cast<segment_command_64*>
+                                                          (::calloc(1, size));
+    result->cmd = LC_SEGMENT_64;
+    result->cmdsize = size;
+    result->nsects = sectCount;
+    return result;
+  }
+  
+};
+
+
+enum {
+  LC_LOAD_DYLINKER = 0xe
+};
+
+
+class dylinker_command : public load_command {
+public:
+  uint32_t  name_offset;
+  char      name[];
+  
+  static dylinker_command* make(const char* path) {
+    unsigned size = (sizeof(dylinker_command) + strlen(path) + 7) & (-8);
+    dylinker_command* result = reinterpret_cast<dylinker_command*>
+                                                          (::calloc(1, size));
+    result->cmd = LC_LOAD_DYLINKER;
+    result->cmdsize = size;
+    result->name_offset = 12;
+    strcpy(result->name, path);
+    return result;
+  }
+};
+
+
+
+
+
+
+enum {
+  N_UNDF = 0x00,
+  N_EXT  = 0x01,
+  N_PEXT = 0x10,
+  N_SECT = 0x0e
+};
+
+class nlist_64 {
+public:
+  uint32_t  n_strx; 
+  uint8_t   n_type; 
+  uint8_t   n_sect;   
+  uint16_t  n_desc;   
+  uint64_t  n_value;    
+
+  void write(raw_ostream& out) {
+    out.write((char*)&n_strx, 16);
+  }
+
+
+};
+
+
+enum {
+  LC_SYMTAB  =  0x2
+};
+
+class symtab_command : public load_command {
+public:
+  uint32_t  symoff;  
+  uint32_t  nsyms;  
+  uint32_t  stroff;  
+  uint32_t  strsize;  
+
+  static symtab_command* make() {
+    unsigned size = sizeof(symtab_command);
+    symtab_command* result = reinterpret_cast<symtab_command*>
+                                                          (::calloc(1, size));
+    result->cmd = LC_SYMTAB;
+    result->cmdsize = size;
+    return result;
+  }
+};
+
+
+enum {
+  LC_MAIN = 0x80000028
+};
+
+class entry_point_command : public load_command {
+public:
+  uint64_t  entryoff;  /* file (__TEXT) offset of main() */
+  uint64_t  stacksize;/* if not zero, initial stack size */
+
+  static entry_point_command* make() {
+    unsigned size = sizeof(entry_point_command);
+    entry_point_command* result = reinterpret_cast<entry_point_command*>
+                                                          (::calloc(1, size));
+    result->cmd = LC_MAIN;
+    result->cmdsize = size;
+    return result;
+  }
+};
+
+enum {
+  LC_DYLD_INFO_ONLY = 0x80000022
+};
+
+struct dyld_info_command : public load_command {
+  uint32_t   rebase_off;  
+  uint32_t   rebase_size;  
+  uint32_t   bind_off;  
+  uint32_t   bind_size;  
+  uint32_t   weak_bind_off;  
+  uint32_t   weak_bind_size; 
+  uint32_t   lazy_bind_off;
+  uint32_t   lazy_bind_size; 
+  uint32_t   export_off;  
+  uint32_t   export_size;  
+
+  static dyld_info_command* make() {
+    unsigned size = sizeof(dyld_info_command);
+    dyld_info_command* result = reinterpret_cast<dyld_info_command*>
+    (::calloc(1, size));
+    result->cmd = LC_DYLD_INFO_ONLY;
+    result->cmdsize = size;
+    return result;
+  }
+};
+
+
+enum {
+  LC_LOAD_DYLIB = 0xC
+};
+  
+
+struct dylib_command : public load_command {
+  uint32_t  name_offset;
+  uint32_t  timestamp;
+  uint32_t  current_version;    
+  uint32_t  compatibility_version;
+  char      name[];
+  
+  static dylib_command* make(const char* path) {
+    unsigned size = (sizeof(dylib_command) + strlen(path) + 7) & (-8);
+    dylib_command* result = reinterpret_cast<dylib_command*>
+    (::calloc(1, size));
+    result->cmd = LC_LOAD_DYLIB;
+    result->cmdsize = size;
+    result->name_offset = 24;
+    result->name_offset = 24;
+    result->timestamp = 0;
+    result->current_version = 0x10000;
+    result->compatibility_version = 0x10000;
+    strcpy(result->name, path);
+    return result;
+  }
+  
+};
+
+enum {
+  BIND_TYPE_POINTER               = 1,
+  BIND_TYPE_TEXT_ABSOLUTE32        = 2,
+  BIND_TYPE_TEXT_PCREL32          = 3
+};
+
+enum {
+  BIND_SPECIAL_DYLIB_SELF             = 0,
+  BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE  = -1,
+  BIND_SPECIAL_DYLIB_FLAT_LOOKUP      =  -2
+};
+
+enum {
+  BIND_SYMBOL_FLAGS_WEAK_IMPORT           = 0x1,
+  BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION    =  0x8
+};
+
+enum {
+  BIND_OPCODE_MASK                              = 0xF0,
+  BIND_IMMEDIATE_MASK                           = 0x0F,
+  BIND_OPCODE_DONE                              = 0x00,
+  BIND_OPCODE_SET_DYLIB_ORDINAL_IMM             = 0x10,
+  BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB            = 0x20,
+  BIND_OPCODE_SET_DYLIB_SPECIAL_IMM             = 0x30,
+  BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM     = 0x40,
+  BIND_OPCODE_SET_TYPE_IMM                      = 0x50,
+  BIND_OPCODE_SET_ADDEND_SLEB                   = 0x60,
+  BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB       = 0x70,
+  BIND_OPCODE_ADD_ADDR_ULEB                     = 0x80,
+  BIND_OPCODE_DO_BIND                           = 0x90,
+  BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB             = 0xA0,
+  BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED       = 0xB0,
+  BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB  = 0xC0
+};
+
+
+
+
+} // namespace darwin
+} // namespace lld
+
+
+
+#endif // LLD_PLATFORM_DARWIN_MACHO_FORMAT_H_
+

Added: lld/trunk/lib/Platforms/Darwin/StubAtoms.hpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Platforms/Darwin/StubAtoms.hpp?rev=154242&view=auto
==============================================================================
--- lld/trunk/lib/Platforms/Darwin/StubAtoms.hpp (added)
+++ lld/trunk/lib/Platforms/Darwin/StubAtoms.hpp Fri Apr  6 20:31:00 2012
@@ -0,0 +1,372 @@
+//===- Platforms/Darwin/x86_64StubAtom.hpp --------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_PLATFORM_DARWIN_X86_64_STUB_ATOM_H_
+#define LLD_PLATFORM_DARWIN_X86_64_STUB_ATOM_H_
+
+#include <vector>
+
+#include "llvm/ADT/ArrayRef.h"
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+
+#include "DarwinReferenceKinds.h"
+
+namespace lld {
+namespace darwin {
+
+
+//
+// Generic Reference
+//
+class GenericReference : public Reference {
+public:
+                GenericReference(Reference::Kind k, uint64_t off, 
+                                const Atom *t, Reference::Addend a) 
+                      : _target(t), _offsetInAtom(off), _addend(a), _kind(k) { }
+
+  virtual uint64_t offsetInAtom() const {
+    return _offsetInAtom;
+  }
+
+  virtual Kind kind() const {
+    return _kind;
+  }
+
+  virtual void setKind(Kind k) {
+    _kind = k;
+  }
+
+  virtual const Atom* target() const {
+    return _target;
+  }
+
+  virtual Addend addend() const {
+    return _addend;
+  }
+
+  virtual void setAddend(Addend a) {
+    _addend = a;
+  }
+
+  virtual void setTarget(const Atom* newAtom) {
+    _target = newAtom;
+  }
+private:
+  const Atom*  _target;
+  uint64_t     _offsetInAtom;
+  Addend       _addend;
+  Kind         _kind;
+};
+
+
+//
+// Generic Atom base class
+//
+class BaseAtom : public DefinedAtom {
+public:
+        BaseAtom(const File &f) : _file(f) {
+          static uint32_t lastOrdinal = 0;
+          _ordinal = lastOrdinal++; 
+        }
+
+  virtual const File& file() const {
+    return _file;
+  }
+
+  virtual StringRef name() const {
+    return StringRef();
+  }
+  
+  virtual uint64_t ordinal() const {
+    return _ordinal;
+  }
+
+  virtual Scope scope() const {
+    return DefinedAtom::scopeLinkageUnit;
+  }
+  
+  virtual Interposable interposable() const {
+    return DefinedAtom::interposeNo;
+  }
+  
+  virtual Merge merge() const {
+    return DefinedAtom::mergeNo;
+  }
+  
+  virtual Alignment alignment() const {
+    return Alignment(0,0);
+  }
+  
+  virtual SectionChoice sectionChoice() const {
+    return DefinedAtom::sectionBasedOnContent;
+  }
+    
+  virtual StringRef customSectionName() const {
+    return StringRef();
+  }
+  virtual DeadStripKind deadStrip() const {
+    return DefinedAtom::deadStripNormal;
+  }
+    
+  virtual bool isThumb() const {
+    return false;
+  }
+    
+  virtual bool isAlias() const {
+    return false;
+  }
+  
+  virtual DefinedAtom::reference_iterator referencesBegin() const {
+    uintptr_t index = 0;
+    const void* it = reinterpret_cast<const void*>(index);
+    return reference_iterator(*this, it);
+  }
+
+  virtual DefinedAtom::reference_iterator referencesEnd() const {
+    uintptr_t index = _references.size();
+    const void* it = reinterpret_cast<const void*>(index);
+    return reference_iterator(*this, it);
+  }
+
+  virtual const Reference* derefIterator(const void* it) const {
+    uintptr_t index = reinterpret_cast<uintptr_t>(it);
+    assert(index < _references.size());
+    return &_references[index];
+  }
+
+  virtual void incrementIterator(const void*& it) const {
+    uintptr_t index = reinterpret_cast<uintptr_t>(it);
+    ++index;
+    it = reinterpret_cast<const void*>(index);
+  }
+  
+  void addReference(Reference::Kind kind, uint64_t offset, const Atom *target, 
+                   Reference::Addend addend) {
+    _references.push_back(GenericReference(kind, offset, target, addend));
+  }
+  
+private:
+  const File&                   _file;
+  uint32_t                      _ordinal;
+  std::vector<GenericReference> _references;
+};
+
+
+
+//
+// X86_64 Stub Atom created by the stubs pass.
+//
+class X86_64StubAtom : public BaseAtom {
+public:
+        X86_64StubAtom(const File &file, const Atom &lazyPointer) 
+                       : BaseAtom(file) {
+          this->addReference(ReferenceKind::pcRel32, 2, &lazyPointer, 0);
+        }
+
+  virtual ContentType contentType() const  {
+    return DefinedAtom::typeStub;
+  }
+
+  virtual uint64_t size() const {
+    return 6;
+  }
+
+  virtual ContentPermissions permissions() const  {
+    return DefinedAtom::permR_X;
+  }
+  
+  virtual ArrayRef<uint8_t> rawContent() const {
+    static const uint8_t instructions[] = 
+              { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp *lazyPointer
+    assert(sizeof(instructions) == this->size());
+    return ArrayRef<uint8_t>(instructions, sizeof(instructions));
+  }
+  
+};
+
+
+//
+// X86_64 Stub Helper Common Atom created by the stubs pass.
+//
+class X86_64StubHelperCommonAtom : public BaseAtom {
+public:
+  X86_64StubHelperCommonAtom(const File &file, const Atom &cache,
+                                               const Atom &binder)
+  : BaseAtom(file) {
+    this->addReference(ReferenceKind::pcRel32, 3,  &cache, 0);
+    this->addReference(ReferenceKind::pcRel32, 11, &binder, 0);
+  }
+  
+  virtual ContentType contentType() const  {
+    return DefinedAtom::typeStubHelper;
+  }
+  
+  virtual uint64_t size() const {
+    return 16;
+  }
+  
+  virtual ContentPermissions permissions() const  {
+    return DefinedAtom::permR_X;
+  }
+  
+  virtual ArrayRef<uint8_t> rawContent() const {
+    static const uint8_t instructions[] = 
+    { 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00,   // leaq cache(%rip),%r11
+      0x41, 0x53,                                 // push %r11
+      0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,         // jmp *binder(%rip)
+      0x90 };                                     // nop
+    assert(sizeof(instructions) == this->size());
+    return ArrayRef<uint8_t>(instructions, sizeof(instructions));
+  }
+  
+};
+  
+  
+
+//
+// X86_64 Stub Helper Atom created by the stubs pass.
+//
+class X86_64StubHelperAtom : public BaseAtom {
+public:
+  X86_64StubHelperAtom(const File &file, const Atom &helperCommon) 
+  : BaseAtom(file) {
+    this->addReference(ReferenceKind::lazyImm, 1, nullptr, 0);
+    this->addReference(ReferenceKind::pcRel32, 6, &helperCommon, 0);
+  }
+  
+  virtual ContentType contentType() const  {
+    return DefinedAtom::typeStubHelper;
+  }
+  
+  virtual uint64_t size() const {
+    return 10;
+  }
+  
+  virtual ContentPermissions permissions() const  {
+    return DefinedAtom::permR_X;
+  }
+  
+  virtual ArrayRef<uint8_t> rawContent() const {
+    static const uint8_t instructions[] = 
+              { 0x68, 0x00, 0x00, 0x00, 0x00,   // pushq $lazy-info-offset
+                0xE9, 0x00, 0x00, 0x00, 0x00 }; // jmp helperhelper
+    assert(sizeof(instructions) == this->size());
+    return ArrayRef<uint8_t>(instructions, sizeof(instructions));
+  }
+ 
+};
+  
+
+//
+// X86_64 Lazy Pointer Atom created by the stubs pass.
+//
+class X86_64LazyPointerAtom : public BaseAtom {
+public:
+        X86_64LazyPointerAtom(const File &file, const Atom &helper,
+                                                const Atom &shlib)
+              : BaseAtom(file) {
+                this->addReference(ReferenceKind::pointer64, 0, &helper, 0);
+                this->addReference(ReferenceKind::lazyTarget, 0, &shlib, 0);
+        }
+
+  virtual ContentType contentType() const  {
+    return DefinedAtom::typeLazyPointer;
+  }
+
+  virtual uint64_t size() const {
+    return 8;
+  }
+
+  virtual ContentPermissions permissions() const  {
+    return DefinedAtom::permRW_;
+  }
+  
+  virtual ArrayRef<uint8_t> rawContent() const {
+    static const uint8_t bytes[] = 
+                            { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    return ArrayRef<uint8_t>(bytes, 8);
+  }
+  
+};
+
+
+//
+// X86_64 NonLazy (GOT) Pointer Atom created by the stubs pass.
+//
+class X86_64NonLazyPointerAtom : public BaseAtom {
+public:
+  X86_64NonLazyPointerAtom(const File &file)
+  : BaseAtom(file) {
+  }
+  
+  X86_64NonLazyPointerAtom(const File &file, const Atom &shlib)
+  : BaseAtom(file) {
+    this->addReference(ReferenceKind::pointer64, 0, &shlib, 0);
+  }
+  
+  virtual ContentType contentType() const  {
+    return DefinedAtom::typeGOT;
+  }
+  
+  virtual uint64_t size() const {
+    return 8;
+  }
+  
+  virtual ContentPermissions permissions() const  {
+    return DefinedAtom::permRW_;
+  }
+  
+  virtual ArrayRef<uint8_t> rawContent() const {
+    static const uint8_t bytes[] = 
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    return ArrayRef<uint8_t>(bytes, 8);
+  }
+  
+};
+  
+  
+//
+// StubBinderAtom created by the stubs pass.
+//
+class StubBinderAtom : public SharedLibraryAtom {
+public:
+  StubBinderAtom(const File &f) : _file(f) { 
+  }
+          
+  virtual const File& file() const {
+    return _file;
+  }
+
+  virtual StringRef name() const {
+    return StringRef("dyld_stub_binder");
+  }
+
+  virtual StringRef loadName() const {
+    return StringRef("/usr/lib/libSystem.B.dylib");
+  }
+  
+  virtual bool canBeNullAtRuntime() const {
+    return false;
+  }
+  
+private:
+  const File  &_file;
+};
+
+
+
+} // namespace darwin 
+} // namespace lld 
+
+
+#endif // LLD_PLATFORM_DARWIN_X86_64_STUB_ATOM_H_

Added: lld/trunk/test/darwin/hello-world.objtxt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/darwin/hello-world.objtxt?rev=154242&view=auto
==============================================================================
--- lld/trunk/test/darwin/hello-world.objtxt (added)
+++ lld/trunk/test/darwin/hello-world.objtxt Fri Apr  6 20:31:00 2012
@@ -0,0 +1,35 @@
+# RUN: lld-core -platform darwin -stubs_pass %s -o %t && llvm-nm %t | FileCheck %s
+
+#
+# Test that hello-world can be linked into a mach-o executable
+#
+
+---
+atoms:
+    - name:              _main
+      type:              code
+      scope:             global
+      content:           [ 55, 48, 89, E5, 48, 8D, 3D, 00, 00, 00, 00, 
+                           E8, 00, 00, 00, 00, 31, C0, 5D, C3 ]
+      fixups:
+      - offset:          7
+        kind:            pcrel32
+        target:          LC1
+      - offset:          12
+        kind:            call32
+        target:          _printf
+
+    - ref-name:          LC1
+      scope:             hidden
+      type:              c-string
+      content:           [ 68, 65, 6C, 6C, 6F, 0A, 00 ]
+
+    - name:              _printf
+      definition:        shared-library
+      load-name:         /usr/lib/libSystem.B.dylib
+
+...
+
+# CHECK:	{{[0-9a-f]+}} s _main
+# CHECK:	00000000 u _printf
+# CHECK:	00000000 u dyld_stub_binder

Modified: lld/trunk/tools/lld-core/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/tools/lld-core/CMakeLists.txt?rev=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/tools/lld-core/CMakeLists.txt (original)
+++ lld/trunk/tools/lld-core/CMakeLists.txt Fri Apr  6 20:31:00 2012
@@ -1,6 +1,7 @@
 set(LLVM_USED_LIBS
   lldCore
   lldPasses
+  lldDarwinPlatform
   )
 
 set(LLVM_LINK_COMPONENTS

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=154242&r1=154241&r2=154242&view=diff
==============================================================================
--- lld/trunk/tools/lld-core/lld-core.cpp (original)
+++ lld/trunk/tools/lld-core/lld-core.cpp Fri Apr  6 20:31:00 2012
@@ -286,7 +286,7 @@
 
   // return entry point for output file (e.g. "main") or nullptr
   virtual StringRef entryPointName() {
-    return nullptr;
+    return StringRef();
   }
 
   // for iterating must-be-defined symbols ("main" or -u command line option)
@@ -403,14 +403,26 @@
 
 
 
-  virtual const DefinedAtom* makeStub(const Atom& shlibAtom, File& file) {
-    return new TestingStubAtom(file, shlibAtom);
+  virtual const DefinedAtom *getStub(const Atom& shlibAtom, File& file) {
+    const DefinedAtom *result = new TestingStubAtom(file, shlibAtom);
+    _stubs.push_back(result);
+    return result;
   }
   
   virtual const DefinedAtom* makeGOTEntry(const Atom& shlibAtom, File& file) {
     return new TestingGOTAtom(file, shlibAtom);
   }
-
+  
+  virtual void addStubAtoms(File &file) {
+    for (const DefinedAtom *stub : _stubs) {
+      file.addAtom(*stub);
+    }
+  }
+  
+  virtual void writeExecutable(const lld::File &, raw_ostream &out) {
+  }
+private:
+  std::vector<const DefinedAtom*> _stubs;
 };
 
 
@@ -495,6 +507,20 @@
 gDoGotPass("got_pass", 
           llvm::cl::desc("Run pass to create GOT atoms"));
 
+enum PlatformChoice {
+  platformTesting, platformDarwin
+};
+
+llvm::cl::opt<PlatformChoice> 
+platformSelected("platform",
+  llvm::cl::desc("Select platform"),
+  llvm::cl::values(
+    clEnumValN(platformTesting, "none", "link for testing"),
+    clEnumValN(platformDarwin, "darwin", "link as darwin would"),
+    clEnumValEnd));
+    
+    
+    
 int main(int argc, char *argv[]) {
   // Print a stack trace if we signal out.
   llvm::sys::PrintStackTraceOnErrorSignal();
@@ -505,12 +531,20 @@
   llvm::cl::ParseCommandLineOptions(argc, argv);
 
   // create platform for testing
-  TestingPlatform testingPlatform;
+  Platform* platform = NULL;
+  switch ( platformSelected ) {
+    case platformTesting:
+      platform = new TestingPlatform();
+      break;
+    case platformDarwin:
+      platform = createDarwinPlatform();
+      break;
+  }
   
   // read input YAML doc into object file(s)
   std::vector<const File *> files;
   if (error(yaml::parseObjectTextFileOrSTDIN(gInputFilePath, 
-                                            testingPlatform, files))) {
+                                            *platform, files))) {
     return 1;
   }
   
@@ -518,16 +552,16 @@
   TestingInputFiles inputFiles(files);
   
   // merge all atom graphs
-  Resolver resolver(testingPlatform, inputFiles);
+  Resolver resolver(*platform, inputFiles);
   resolver.resolve();
 
   // run passes
   if ( gDoGotPass ) {
-    GOTPass  addGot(resolver.resultFile(), testingPlatform);
+    GOTPass  addGot(resolver.resultFile(), *platform);
     addGot.perform();
   }
   if ( gDoStubsPass ) {
-    StubsPass  addStubs(resolver.resultFile(), testingPlatform);
+    StubsPass  addStubs(resolver.resultFile(), *platform);
     addStubs.perform();
   }
 
@@ -553,10 +587,20 @@
   // read native file
   std::unique_ptr<lld::File> natFile;
   if ( error(parseNativeObjectFileOrSTDIN(tempPath, natFile)) ) 
-	return 1;
-	
-  // write new atom graph out as YAML doc
-  yaml::writeObjectText(*natFile, testingPlatform, out);
+    return 1;
+
+  if ( platformSelected == platformTesting) {
+    // write new atom graph out as YAML doc
+    yaml::writeObjectText(resolver.resultFile() /* *natFile */, *platform, out);
+  }
+  else {
+    platform->writeExecutable(resolver.resultFile() /* *natFile */, out);
+    // HACK.  I don't see any way to set the 'executable' bit on files 
+    // in raw_fd_ostream or in llvm/Support.
+#if HAVE_SYS_STAT_H
+    ::chmod(outPath, 0777);
+#endif
+  }
 
   // delete temp .o file
   bool existed;





More information about the llvm-commits mailing list