forked from OSchip/llvm-project
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:
parent
c4d558a43e
commit
b334be1ed2
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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_
|
|
@ -1,2 +1,3 @@
|
|||
add_subdirectory(Core)
|
||||
add_subdirectory(Passes)
|
||||
add_subdirectory(Platforms)
|
||||
|
|
|
@ -4,6 +4,7 @@ add_lld_library(lldCore
|
|||
NativeFileFormat.h
|
||||
NativeReader.cpp
|
||||
NativeWriter.cpp
|
||||
Platform.cpp
|
||||
Resolver.cpp
|
||||
SymbolTable.cpp
|
||||
YamlKeyValues.cpp
|
||||
|
|
|
@ -18,5 +18,8 @@ StringRef File::translationUnitSource() const {
|
|||
return StringRef();
|
||||
}
|
||||
|
||||
const Atom *File::entryPoint() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() {}
|
||||
|
||||
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(Darwin)
|
|
@ -0,0 +1,5 @@
|
|||
add_lld_library(lldDarwinPlatform
|
||||
DarwinPlatform.cpp
|
||||
DarwinReferenceKinds.cpp
|
||||
ExecutableWriter.cpp
|
||||
)
|
|
@ -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
|
|
@ -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_
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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
|
@ -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_
|
||||
|
|
@ -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_
|
||||
|
|
@ -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_
|
|
@ -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
|
|
@ -1,6 +1,7 @@
|
|||
set(LLVM_USED_LIBS
|
||||
lldCore
|
||||
lldPasses
|
||||
lldDarwinPlatform
|
||||
)
|
||||
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue