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.

llvm-svn: 154242
This commit is contained in:
Nick Kledzik 2012-04-07 01:31:00 +00:00
parent c4d558a43e
commit b334be1ed2
31 changed files with 2906 additions and 89 deletions

View File

@ -251,7 +251,7 @@ public:
/// 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 @@ public:
/// 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;
}

View File

@ -49,6 +49,12 @@ public:
/// 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 @@ protected:
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 @@ protected:
/// 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>

View File

@ -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 @@ class DefinedAtom;
/// 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 @@ public:
/// 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_

View File

@ -58,6 +58,9 @@ public:
/// 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() {}

View File

@ -80,10 +80,11 @@ private:
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 @@ private:
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;

View File

@ -77,7 +77,7 @@ private:
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 {

View File

@ -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_

View File

@ -1,2 +1,3 @@
add_subdirectory(Core)
add_subdirectory(Passes)
add_subdirectory(Platforms)

View File

@ -4,6 +4,7 @@ add_lld_library(lldCore
NativeFileFormat.h
NativeReader.cpp
NativeWriter.cpp
Platform.cpp
Resolver.cpp
SymbolTable.cpp
YamlKeyValues.cpp

View File

@ -18,5 +18,8 @@ StringRef File::translationUnitSource() const {
return StringRef();
}
const Atom *File::entryPoint() const {
return nullptr;
}
}

View File

@ -193,6 +193,9 @@ struct NativeAbsoluteAtomIvarsV1 {
// 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 @@ struct NativeReferenceIvarsV1 {
};
//
// The NCS_ReferencesArrayV2 chunk contains an array of these structs
//

View File

@ -20,6 +20,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include <vector>
#include <memory>
namespace lld {
@ -202,6 +203,7 @@ public:
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 @@ private:
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 @@ inline void NativeReferenceV1::setTarget(const Atom* newAtom) {
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

View File

@ -430,11 +430,13 @@ private:
}
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;
}

19
lld/lib/Core/Platform.cpp Normal file
View File

@ -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() {}
}

View File

@ -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 @@ void Resolver::checkDylibSymbolCollisions() {
// 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 @@ void Resolver::resolve() {
this->linkTimeOptimize();
this->tweakAtoms();
this->_result.addAtoms(_atoms);
this->_result._mainAtom = this->entryPoint();
}
void Resolver::MergedFile::addAtom(const Atom& atom) {

View File

@ -179,7 +179,7 @@ void YAML::parse(llvm::MemoryBuffer *mb, std::vector<const Entry *> &entries) {
}
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 @@ public:
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 @@ public:
}
virtual StringRef loadName() const {
return _loadName;
if ( _loadName == nullptr )
return StringRef();
else
return StringRef(_loadName);
}
virtual bool canBeNullAtRuntime() const {

View File

@ -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@GOTPCREL(%rip), %rax
// movq foo@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

View File

@ -30,9 +30,6 @@ void StubsPass::perform() {
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 @@ void StubsPass::perform() {
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 @@ void StubsPass::perform() {
}
}
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);
}

View File

@ -0,0 +1 @@
add_subdirectory(Darwin)

View File

@ -0,0 +1,5 @@
add_lld_library(lldDarwinPlatform
DarwinPlatform.cpp
DarwinReferenceKinds.cpp
ExecutableWriter.cpp
)

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -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_

File diff suppressed because it is too large Load Diff

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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

View File

@ -1,6 +1,7 @@
set(LLVM_USED_LIBS
lldCore
lldPasses
lldDarwinPlatform
)
set(LLVM_LINK_COMPONENTS

View File

@ -286,7 +286,7 @@ public:
// 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 @@ public:
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 @@ llvm::cl::opt<bool>
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 @@ int main(int argc, char *argv[]) {
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 @@ int main(int argc, char *argv[]) {
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 @@ int main(int argc, char *argv[]) {
// 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;