summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/MachO/WriterMachO.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib/ReaderWriter/MachO/WriterMachO.cpp')
-rw-r--r--lld/lib/ReaderWriter/MachO/WriterMachO.cpp1491
1 files changed, 27 insertions, 1464 deletions
diff --git a/lld/lib/ReaderWriter/MachO/WriterMachO.cpp b/lld/lib/ReaderWriter/MachO/WriterMachO.cpp
index 08d54e79f2a..ae739846f4e 100644
--- a/lld/lib/ReaderWriter/MachO/WriterMachO.cpp
+++ b/lld/lib/ReaderWriter/MachO/WriterMachO.cpp
@@ -12,1488 +12,51 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/Format.h"
+#include "llvm/Support/MachO.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
-
-#include "lld/Core/DefinedAtom.h"
#include "lld/Core/File.h"
-#include "lld/Core/Reference.h"
-#include "lld/Core/SharedLibraryAtom.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
-#include "lld/ReaderWriter/MachOFormat.hpp"
-#include <vector>
-#include <map>
-#include <string.h>
-#include "ReferenceKinds.h"
+#include "MachONormalizedFile.h"
#include "ExecutableAtoms.hpp"
+using lld::mach_o::normalized::NormalizedFile;
+
namespace lld {
namespace mach_o {
-class LoadCommandPaddingChunk;
-class SymbolStringsChunk;
-class MachOWriter;
-
-//
-// 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 ~Chunk() { }
- virtual StringRef segmentName() const = 0;
- virtual bool occupiesNoDiskSpace();
- virtual void write(uint8_t *fileBuffer) = 0;
- 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,
- MachOWriter &writer);
- virtual StringRef segmentName() const;
- virtual bool occupiesNoDiskSpace();
- virtual void write(uint8_t *fileBuffer);
- 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,
- MachOWriter &writer);
-
- StringRef _segmentName;
- StringRef _sectionName;
- 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(const MachOLinkingContext &context, const File &file);
- virtual StringRef segmentName() const;
- virtual void write(uint8_t *fileBuffer);
- virtual const char* info();
- void recordLoadCommand(load_command*);
- uint64_t loadCommandsSize();
-
-private:
- uint32_t magic(uint32_t cpuType);
-
- 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 &, const MachOLinkingContext &,
- MachOWriter &);
- virtual StringRef segmentName() const;
- virtual void write(uint8_t *fileBuffer);
- virtual const char* info();
- void computeSize(const lld::File &file);
- void addSection(SectionChunk*);
- void updateLoadCommandContent(const lld::File &file);
-
-private:
- friend LoadCommandPaddingChunk;
-
- void addLoadCommand(load_command* lc);
- void setMachOSection(SectionChunk *chunk,
- segment_command *seg, uint32_t index);
- uint32_t permissionsFromSections(
- const SmallVector<SectionChunk*,16> &);
- bool use64BitMachO() const;
-
- struct ChunkSegInfo {
- SectionChunk *chunk;
- segment_command *segment;
- section_64 *section;
- };
-
- MachHeaderChunk &_mh;
- const MachOLinkingContext &_context;
- MachOWriter &_writer;
- segment_command *_linkEditSegment;
- symtab_command *_symbolTableLoadCommand;
- entry_point_command *_entryPointLoadCommand;
- thread_command *_threadLoadCommand;
- dyld_info_command *_dyldInfoLoadCommand;
- std::vector<load_command*> _loadCmds;
- std::vector<ChunkSegInfo> _sectionInfo;
- llvm::StringMap<uint32_t> _dylibNamesToOrdinal;
-};
-
-
-
-//
-// 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(uint8_t *fileBuffer);
- 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(MachOWriter &);
- virtual void write(uint8_t *fileBuffer);
-
-protected:
- void append_byte(uint8_t);
- void append_uleb128(uint64_t);
- void append_string(StringRef);
-
- 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(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(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(SymbolStringsChunk&, MachOWriter&);
- virtual void write(uint8_t *fileBuffer);
- virtual void computeSize(const lld::File &file,
- const std::vector<SectionChunk*>&);
- virtual const char* info();
- uint32_t count();
-
-private:
- uint8_t nType(const DefinedAtom*);
-
- MachOWriter &_writer;
- SymbolStringsChunk &_stringsChunk;
- std::vector<nlist> _globalDefinedsymbols;
- std::vector<nlist> _localDefinedsymbols;
- std::vector<nlist> _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(uint8_t *fileBuffer);
- 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 Writer {
public:
- MachOWriter(const MachOLinkingContext &context);
-
- virtual error_code writeFile(const lld::File &file, StringRef path);
- virtual bool createImplicitFiles(std::vector<std::unique_ptr<File> > &);
-
- uint64_t addressOfAtom(const Atom *atom);
- void findSegment(StringRef segmentName, uint32_t *segIndex,
- uint64_t *segStartAddr, uint64_t *segEndAddr);
-
- const std::vector<Chunk*> chunks() { return _chunks; }
- mach_o::KindHandler &kindHandler() { return _referenceKindHandler; }
-
- bool use64BitMachO() const;
-
-private:
- friend LoadCommandsChunk;
- friend LazyBindingInfoChunk;
- friend BindingInfoChunk;
-
- void build(const lld::File &file);
- 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;
-
- const MachOLinkingContext &_context;
- mach_o::KindHandler &_referenceKindHandler;
- std::unique_ptr<CRuntimeFile> _cRuntimeFile;
- 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;
- const DefinedAtom *_entryAtom;
- 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;
-}
-
-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_WITH_TYPE("WriterMachO-layout", llvm::dbgs()
- << " fileOffset="
- << llvm::format("0x%08X", _fileOffset)
- << " address="
- << llvm::format("0x%016X", _address)
- << " info=" << this->info() << "\n");
-}
-
-
-
-//===----------------------------------------------------------------------===//
-// SectionChunk
-//===----------------------------------------------------------------------===//
-
-SectionChunk::SectionChunk(StringRef seg, StringRef sect,
- uint32_t flags, MachOWriter &writer)
- : _segmentName(seg), _sectionName(sect), _writer(writer),
- _flags(flags), _permissions(0) {
-
-}
-
-SectionChunk* SectionChunk::make(DefinedAtom::ContentType type,
- MachOWriter &writer) {
- switch ( type ) {
- case DefinedAtom::typeCode:
- return new SectionChunk("__TEXT", "__text",
- S_REGULAR | S_ATTR_PURE_INSTRUCTIONS, writer);
- break;
- case DefinedAtom::typeCString:
- return new SectionChunk("__TEXT", "__cstring",
- S_CSTRING_LITERALS, writer);
- break;
- case DefinedAtom::typeStub:
- return new SectionChunk("__TEXT", "__stubs",
- S_SYMBOL_STUBS | S_ATTR_PURE_INSTRUCTIONS, writer);
- break;
- case DefinedAtom::typeStubHelper:
- return new SectionChunk("__TEXT", "__stub_helper",
- S_REGULAR | S_ATTR_PURE_INSTRUCTIONS, writer);
- break;
- case DefinedAtom::typeLazyPointer:
- return new SectionChunk("__DATA", "__la_symbol_ptr",
- S_LAZY_SYMBOL_POINTERS, writer);
- break;
- case DefinedAtom::typeGOT:
- return new SectionChunk("__DATA", "__got",
- S_NON_LAZY_SYMBOL_POINTERS, 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(uint8_t *chunkBuffer) {
- // Each section's content is just its atoms' content.
- for (const AtomInfo &atomInfo : _atoms ) {
- // Copy raw content of atom to file buffer.
- ArrayRef<uint8_t> content = atomInfo.atom->rawContent();
- uint64_t contentSize = content.size();
- if ( contentSize == 0 )
- continue;
- uint8_t* atomContent = chunkBuffer + atomInfo.offsetInSection;
- ::memcpy(atomContent, content.data(), contentSize);
- // Apply fixups to file buffer
- 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;
- _writer.kindHandler().applyFixup(ref->kind(), ref->addend(),
- &atomContent[offset], fixupAddress,
- targetAddress);
+ MachOWriter(const MachOLinkingContext &ctxt) : _context(ctxt) { }
+
+ virtual error_code writeFile(const lld::File &file, StringRef path) {
+ // Construct empty normalized file from atoms.
+ ErrorOr<std::unique_ptr<NormalizedFile>> nFile =
+ normalized::normalizedFromAtoms(file, _context);
+ if (!nFile)
+ return nFile;
+
+ // For debugging, write out yaml form of normalized file.
+ //writeYaml(*nFile->get(), llvm::errs());
+
+ // Write normalized file as mach-o binary.
+ return writeBinary(*nFile->get(), path);
+ }
+
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File> > &r) {
+ if (_context.outputFileType() == llvm::MachO::MH_EXECUTE) {
+ // When building main executables, add _main as required entry point.
+ r.emplace_back(new CRuntimeFile(_context));
}
- }
-}
-
-
-//===----------------------------------------------------------------------===//
-// MachHeaderChunk
-//===----------------------------------------------------------------------===//
-
-MachHeaderChunk::MachHeaderChunk(const MachOLinkingContext &context,
- const File &file) {
- // Set up mach_header based on options
- _mh.magic = this->magic(context.getCPUType());
- _mh.cputype = context.getCPUType();
- _mh.cpusubtype = context.getCPUSubType();
- _mh.filetype = context.outputFileType();
- _mh.ncmds = 0;
- _mh.sizeofcmds = 0;
- _mh.flags = 0;
- _mh.reserved = 0;
-
- _size = _mh.size();
-}
-
-
-StringRef MachHeaderChunk::segmentName() const {
- return StringRef("__TEXT");
-}
-
-void MachHeaderChunk::write(uint8_t *chunkBuffer) {
- _mh.copyTo(chunkBuffer);
-}
-
-const char* MachHeaderChunk::info() {
- return "mach_header";
-}
-
-void MachHeaderChunk::recordLoadCommand(load_command* lc) {
- _mh.recordLoadCommand(lc);
-}
-
-uint64_t MachHeaderChunk::loadCommandsSize() {
- return _mh.sizeofcmds;
-}
-
-uint32_t MachHeaderChunk::magic(uint32_t cpuType) {
- switch ( cpuType ) {
- case CPU_TYPE_ARM:
- case CPU_TYPE_I386:
- return MH_MAGIC;
- case CPU_TYPE_X86_64:
- return MH_MAGIC_64;
- }
- llvm_unreachable("file CPU type not supported");
- return 0;
-}
-
-
-
-//===----------------------------------------------------------------------===//
-// LoadCommandsChunk
-//===----------------------------------------------------------------------===//
-
-LoadCommandsChunk::LoadCommandsChunk(MachHeaderChunk &mh,
- const MachOLinkingContext &context,
- MachOWriter &writer)
- : _mh(mh), _context(context), _writer(writer), _linkEditSegment(nullptr),
- _symbolTableLoadCommand(nullptr), _entryPointLoadCommand(nullptr),
- _threadLoadCommand(nullptr), _dyldInfoLoadCommand(nullptr) {}
-
-StringRef LoadCommandsChunk::segmentName() const {
- return StringRef("__TEXT");
-}
-
-void LoadCommandsChunk::write(uint8_t *chunkBuffer) {
- uint8_t* p = chunkBuffer;
- for ( load_command* lc : _loadCmds ) {
- assert( ((uintptr_t)p & 0x3) == 0);
- lc->copyTo(p);
- p += lc->cmdsize;
- }
-}
-
-const char* LoadCommandsChunk::info() {
- return "load commands";
-}
-
-void LoadCommandsChunk::setMachOSection(SectionChunk *chunk,
- segment_command *seg, uint32_t index) {
- for (ChunkSegInfo &entry : _sectionInfo) {
- if ( entry.chunk == chunk ) {
- entry.section = &(seg->sections[index]);
- entry.segment = seg;
- return;
- }
- }
- assert(0 && "setMachOSection() chunk not found");
-}
-
-uint32_t LoadCommandsChunk::permissionsFromSections(
- const SmallVector<SectionChunk*,16> &sections) {
- uint32_t result = 0;
- for (SectionChunk *chunk : sections) {
- result |= chunk->permissions();
- }
- return result;
-}
-
-void LoadCommandsChunk::computeSize(const lld::File &file) {
- const bool is64 = _writer.use64BitMachO();
- // Main executables have a __PAGEZERO segment.
- uint64_t pageZeroSize = _context.pageZeroSize();
- if (pageZeroSize != 0) {
- assert(is64 || (pageZeroSize < 0xFFFFFFFF));
- segment_command* pzSegCmd = new segment_command(0, is64);
- 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* segCmd = new segment_command(sections.size(), is64);
- 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* segCmd = new segment_command(sections.size(), is64);
- 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 = new segment_command(0, is64);
- strcpy(_linkEditSegment->segname, "__LINKEDIT");
- _linkEditSegment->initprot = VM_PROT_READ;
- _linkEditSegment->maxprot = VM_PROT_READ;
- this->addLoadCommand(_linkEditSegment);
-
- // Add dyld load command.
- this->addLoadCommand(new dylinker_command("/usr/lib/dyld", is64));
-
- // Add dylib load commands.
- 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(new dylib_command(it->first(), is64));
- }
-
- // Add symbol table load command
- _symbolTableLoadCommand = new symtab_command(is64);
- this->addLoadCommand(_symbolTableLoadCommand);
-
- // Add dyld info load command
- _dyldInfoLoadCommand = new dyld_info_command(is64);
- this->addLoadCommand(_dyldInfoLoadCommand);
-
- // Add entry point load command to main executables
- if (_context.addEntryPointLoadCommand()) {
- _entryPointLoadCommand = new entry_point_command(is64);
- this->addLoadCommand(_entryPointLoadCommand);
- } else if (_context.addUnixThreadLoadCommand()) {
- _threadLoadCommand = new thread_command(_context.getCPUType(), is64);
- this->addLoadCommand(_threadLoadCommand);
- }
-
- // Compute total size.
- _size = _mh.loadCommandsSize();
-}
-
-
-void LoadCommandsChunk::updateLoadCommandContent(const lld::File &file) {
- // Update segment/section information in segment load commands
- segment_command *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 = _writer._entryAtom;
- assert(mainAtom != nullptr);
- uint32_t entryOffset = _writer.addressOfAtom(mainAtom) - _mh.address();
- _entryPointLoadCommand->entryoff = entryOffset;
- }
- else if ( _threadLoadCommand != nullptr ) {
- const Atom *startAtom = _writer._entryAtom;
- assert(startAtom != nullptr);
- _threadLoadCommand->setPC(_writer.addressOfAtom(startAtom));
- }
-
-}
-
-
-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(uint8_t *chunkBuffer) {
- // Zero fill padding.
-}
-
-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(uint8_t *chunkBuffer) {
- ::memcpy(chunkBuffer, &_bytes[0], _bytes.size());
-}
-
-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(_writer.kindHandler().isPointer(ref->kind()));
- targetName = shlTarget->name();
- ordinal = 1; // FIXME
- }
- }
- }
-
- 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";
-}
-
-//
-// Called when lazy-binding-info is being laid out in __LINKEDIT. We need
-// to find the helper atom which contains the instruction which loads an
-// immediate value that is the offset into the lazy-binding-info, and set
-// that immediate value to be the offset parameter.
-void LazyBindingInfoChunk::updateHelper(const DefinedAtom *lazyPointerAtom,
- uint32_t offset) {
- for (const Reference *ref : *lazyPointerAtom ) {
- if ( ! _writer.kindHandler().isPointer(ref->kind() ) )
- continue;
- const Atom *targ = ref->target();
- const DefinedAtom *helperAtom = dyn_cast<DefinedAtom>(targ);
- assert(helperAtom != nullptr);
- // Found helper atom. Search it for Reference that is lazy immediate value.
- for (const Reference *href : *helperAtom ) {
- if ( _writer.kindHandler().isLazyImmediate(href->kind()) ) {
- (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 ( _writer.kindHandler().isLazyTarget(ref->kind()) ) {
- 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, MachOWriter &wrtr)
- : _writer(wrtr), _stringsChunk(str) {
-}
-
-void SymbolTableChunk::write(uint8_t *chunkBuffer) {
- const bool is64 = _writer.use64BitMachO();
- const unsigned nlistSize = nlist::size(is64);
- uint8_t *p = chunkBuffer;
- for ( nlist &sym : _globalDefinedsymbols ) {
- sym.copyTo(p, is64);
- p += nlistSize;
- }
- for ( nlist &sym : _localDefinedsymbols ) {
- sym.copyTo(p, is64);
- p += nlistSize;
- }
- for ( nlist &sym : _undefinedsymbols ) {
- sym.copyTo(p, is64);
- p += nlistSize;
- }
-}
-
-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 sym;
- sym.n_strx = _stringsChunk.stringIndex(info.atom->name());
- sym.n_type = this->nType(info.atom);
- sym.n_sect = sectionIndex;
- sym.n_desc = 0;
- 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 sym;
- sym.n_strx = _stringsChunk.stringIndex(atom->name());
- sym.n_type = N_UNDF;
- sym.n_sect = 0;
- sym.n_desc = 0;
- sym.n_value = 0;
- _undefinedsymbols.push_back(sym);
- }
-
- _size = nlist::size(_writer.use64BitMachO()) * 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(uint8_t *chunkBuffer) {
- ::memcpy(chunkBuffer, &_strings[0], _strings.size());
-}
-
-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(const MachOLinkingContext &context)
- : _context(context), _referenceKindHandler(context.kindHandler()),
- _cRuntimeFile(new CRuntimeFile(context)), _bindingInfo(nullptr),
- _lazyBindingInfo(nullptr), _symbolTableChunk(nullptr),
- _stringsChunk(nullptr), _entryAtom(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, *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(_context, file);
- _chunks.push_back(mhc);
-
- _loadCommandsChunk = new LoadCommandsChunk(*mhc, _context, *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);
- 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_WITH_TYPE("WriterMachO-layout", llvm::dbgs()
- << "assign atom addresses:\n");
- const bool lookForEntry = _context.outputTypeHasEntry();
- for (SectionChunk *chunk : _sectionChunks) {
- for (const SectionChunk::AtomInfo &info : chunk->atoms()) {
- _atomToAddress[info.atom] = chunk->address() + info.offsetInSection;
- if (lookForEntry && (info.atom->contentType() == DefinedAtom::typeCode) &&
- (info.atom->size() != 0) &&
- info.atom->name() == _context.entrySymbolName()) {
- _entryAtom = info.atom;
- }
- DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs()
- << " address="
- << llvm::format("0x%016X", _atomToAddress[info.atom])
- << " atom=" << info.atom
- << " 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_WITH_TYPE("WriterMachO-layout", llvm::dbgs()
- << "assign file offsets:\n");
- uint64_t offset = 0;
- uint64_t address = _context.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_WITH_TYPE("WriterMachO-layout", 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 (_context.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;
- }
- }
- }
-}
-
-bool MachOWriter::use64BitMachO() const {
- switch (_context.arch()) {
- case MachOLinkingContext::arch_x86_64:
return true;
- case MachOLinkingContext::arch_x86:
- case MachOLinkingContext::arch_armv6:
- case MachOLinkingContext::arch_armv7:
- case MachOLinkingContext::arch_armv7s:
- return false;
- default:
- llvm_unreachable("Unknown mach-o arch");
}
-}
-
-
-//
-// Creates a mach-o final linked image from the given atom graph and writes
-// it to the supplied output stream.
-//
-error_code MachOWriter::writeFile(const lld::File &file, StringRef path) {
- this->build(file);
-
-// FIXME: re-enable when FileOutputBuffer is in LLVMSupport.a
- uint64_t totalSize = _chunks.back()->fileOffset() + _chunks.back()->size();
-
- OwningPtr<llvm::FileOutputBuffer> buffer;
- error_code ec = llvm::FileOutputBuffer::create(path,
- totalSize, buffer,
- llvm::FileOutputBuffer::F_executable);
- if ( ec )
- return ec;
-
- DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs() << "writeFile:\n");
- for ( Chunk *chunk : _chunks ) {
- DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs()
- << " fileOffset="
- << llvm::format("0x%08X", chunk->fileOffset())
- << " chunk="
- << chunk->info()
- << "\n");
- chunk->write(buffer->getBufferStart()+chunk->fileOffset());
- }
- return buffer->commit();
-}
+private:
+ const MachOLinkingContext &_context;
+ };
-bool
-MachOWriter::createImplicitFiles(std::vector<std::unique_ptr<File> > &result) {
- result.push_back(std::move(_cRuntimeFile));
- return true;
-}
} // namespace mach_o
OpenPOWER on IntegriCloud