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

