[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> §ions) {
+ 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