X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/07feaf2cb00322d025073eb8ec22189ada5e4180..a645023da60d22e86be13f7b4d97adeff8bc6665:/src/ld/HeaderAndLoadCommands.hpp?ds=inline diff --git a/src/ld/HeaderAndLoadCommands.hpp b/src/ld/HeaderAndLoadCommands.hpp new file mode 100644 index 0000000..2c97dba --- /dev/null +++ b/src/ld/HeaderAndLoadCommands.hpp @@ -0,0 +1,1391 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-* + * + * Copyright (c) 2009 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef __HEADER_LOAD_COMMANDS_HPP__ +#define __HEADER_LOAD_COMMANDS_HPP__ + +#include +#include +#include +#include + +#include + +#include "MachOFileAbstraction.hpp" +#include "Options.h" +#include "ld.hpp" + +namespace ld { +namespace tool { + +class HeaderAndLoadCommandsAbtract : public ld::Atom +{ +public: + HeaderAndLoadCommandsAbtract(const ld::Section& sect, ld::Atom::Definition d, + ld::Atom::Combine c, ld::Atom::Scope s, ld::Atom::ContentType ct, + ld::Atom::SymbolTableInclusion i, bool dds, bool thumb, bool al, + ld::Atom::Alignment a) : ld::Atom(sect, d, c, s, ct, i, dds, thumb, al, a) { } + + virtual void setUUID(const uint8_t digest[16]) = 0; + virtual void recopyUUIDCommand() = 0; +}; + +template +class HeaderAndLoadCommandsAtom : public HeaderAndLoadCommandsAbtract +{ +public: + HeaderAndLoadCommandsAtom(const Options& opts, ld::Internal& state, + OutputFile& writer); + + // overrides of ld::Atom + virtual ld::File* file() const { return NULL; } + virtual bool translationUnitSource(const char** dir, const char** nm) const + { return false; } + virtual const char* name() const { return "mach-o header and load commands"; } + virtual uint64_t size() const; + virtual uint64_t objectAddress() const { return _address; } + virtual void copyRawContent(uint8_t buffer[]) const; + + // overrides of HeaderAndLoadCommandsAbtract + virtual void setUUID(const uint8_t digest[16]) { memcpy(_uuid, digest, 16); } + virtual void recopyUUIDCommand(); + +private: + typedef typename A::P P; + typedef typename A::P::E E; + typedef typename A::P::uint_t pint_t; + + unsigned int nonHiddenSectionCount() const; + unsigned int segmentCount() const; + static uint32_t alignedSize(uint32_t x); + uint32_t magic() const; + uint32_t cpuType() const; + uint32_t cpuSubType() const; + uint32_t flags() const; + uint32_t fileType() const; + uint32_t commandsCount() const; + uint32_t threadLoadCommandSize() const; + uint8_t* copySingleSegmentLoadCommand(uint8_t* p) const; + uint8_t* copySegmentLoadCommands(uint8_t* p) const; + uint8_t* copyDyldInfoLoadCommand(uint8_t* p) const; + uint8_t* copySymbolTableLoadCommand(uint8_t* p) const; + uint8_t* copyDynamicSymbolTableLoadCommand(uint8_t* p) const; + uint8_t* copyDyldLoadCommand(uint8_t* p) const; + uint8_t* copyDylibIDLoadCommand(uint8_t* p) const; + uint8_t* copyRoutinesLoadCommand(uint8_t* p) const; + uint8_t* copyUUIDLoadCommand(uint8_t* p) const; + uint8_t* copyVersionLoadCommand(uint8_t* p) const; + uint8_t* copyThreadsLoadCommand(uint8_t* p) const; + uint8_t* copyEncryptionLoadCommand(uint8_t* p) const; + uint8_t* copySplitSegInfoLoadCommand(uint8_t* p) const; + uint8_t* copyDylibLoadCommand(uint8_t* p, const ld::dylib::File*) const; + uint8_t* copyRPathLoadCommand(uint8_t* p, const char*) const; + uint8_t* copySubFrameworkLoadCommand(uint8_t* p) const; + uint8_t* copyAllowableClientLoadCommand(uint8_t* p, const char* client) const; + uint8_t* copySubLibraryLoadCommand(uint8_t* p, const char* name) const; + uint8_t* copySubUmbrellaLoadCommand(uint8_t* p, const char* name) const; + uint8_t* copyFunctionStartsLoadCommand(uint8_t* p) const; + uint8_t* copyDyldEnvLoadCommand(uint8_t* p, const char* env) const; + + uint32_t sectionFlags(ld::Internal::FinalSection* sect) const; + bool sectionTakesNoDiskSpace(ld::Internal::FinalSection* sect) const; + + + const Options& _options; + ld::Internal& _state; + OutputFile& _writer; + pint_t _address; + bool _hasDyldInfoLoadCommand; + bool _hasDyldLoadCommand; + bool _hasDylibIDLoadCommand; + bool _hasThreadLoadCommand; + bool _hasEncryptionLoadCommand; + bool _hasSplitSegInfoLoadCommand; + bool _hasRoutinesLoadCommand; + bool _hasUUIDLoadCommand; + bool _hasSymbolTableLoadCommand; + bool _hasDynamicSymbolTableLoadCommand; + bool _hasRPathLoadCommands; + bool _hasSubFrameworkLoadCommand; + bool _hasVersionLoadCommand; + bool _hasFunctionStartsLoadCommand; + uint32_t _dylibLoadCommmandsCount; + uint32_t _allowableClientLoadCommmandsCount; + uint32_t _dyldEnvironExrasCount; + std::vector _subLibraryNames; + std::vector _subUmbrellaNames; + uint8_t _uuid[16]; + mutable macho_uuid_command

* _uuidCmdInOutputBuffer; + + static ld::Section _s_section; + static ld::Section _s_preload_section; +}; + +template +ld::Section HeaderAndLoadCommandsAtom::_s_section("__TEXT", "__mach_header", ld::Section::typeMachHeader, true); +template +ld::Section HeaderAndLoadCommandsAtom::_s_preload_section("__HEADER", "__mach_header", ld::Section::typeMachHeader, true); + + +template +HeaderAndLoadCommandsAtom::HeaderAndLoadCommandsAtom(const Options& opts, ld::Internal& state, OutputFile& writer) + : HeaderAndLoadCommandsAbtract((opts.outputKind() == Options::kPreload) ? _s_preload_section : _s_section, + ld::Atom::definitionRegular, ld::Atom::combineNever, + ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified, + ld::Atom::symbolTableNotIn, false, false, false, + (opts.outputKind() == Options::kPreload) ? ld::Atom::Alignment(0) : ld::Atom::Alignment(12) ), + _options(opts), _state(state), _writer(writer), _address(0), _uuidCmdInOutputBuffer(NULL) +{ + bzero(_uuid, 16); + _hasDyldInfoLoadCommand = opts.makeCompressedDyldInfo(); + _hasDyldLoadCommand = ((opts.outputKind() == Options::kDynamicExecutable) || (_options.outputKind() == Options::kDyld)); + _hasDylibIDLoadCommand = (opts.outputKind() == Options::kDynamicLibrary); + _hasThreadLoadCommand = _hasDyldLoadCommand || (opts.outputKind() == Options::kStaticExecutable) + || (opts.outputKind() == Options::kPreload) + || (opts.outputKind() == Options::kDyld); + _hasEncryptionLoadCommand = opts.makeEncryptable(); + _hasSplitSegInfoLoadCommand = opts.sharedRegionEligible(); + _hasRoutinesLoadCommand = (opts.initFunctionName() != NULL); + _hasSymbolTableLoadCommand = true; + _hasUUIDLoadCommand = (opts.UUIDMode() != Options::kUUIDNone); + switch ( opts.outputKind() ) { + case Options::kDynamicExecutable: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kDyld: + case Options::kKextBundle: + _hasDynamicSymbolTableLoadCommand = true; + break; + case Options::kObjectFile: + if ( ! state.someObjectFileHasDwarf ) + _hasUUIDLoadCommand = false; + _hasDynamicSymbolTableLoadCommand = false; + for (std::vector::iterator it = _state.sections.begin(); it != _state.sections.end(); ++it) { + if ( (*it)->type() == ld::Section::typeNonLazyPointer ) { + _hasDynamicSymbolTableLoadCommand = true; + break; + } + } + break; + case Options::kStaticExecutable: + _hasDynamicSymbolTableLoadCommand = false; + break; + case Options::kPreload: + _hasDynamicSymbolTableLoadCommand = opts.positionIndependentExecutable(); + break; + } + _hasRPathLoadCommands = (_options.rpaths().size() != 0); + _hasSubFrameworkLoadCommand = (_options.umbrellaName() != NULL); + _hasVersionLoadCommand = _options.addVersionLoadCommand(); + _hasFunctionStartsLoadCommand = _options.addFunctionStarts(); + _dylibLoadCommmandsCount = _writer.dylibCount(); + _allowableClientLoadCommmandsCount = _options.allowableClients().size(); + _dyldEnvironExrasCount = _options.dyldEnvironExtras().size(); + if ( ! _options.useSimplifiedDylibReExports() ) { + // target OS does not support LC_REEXPORT_DYLIB, so use old complicated load commands + for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) { + const ld::dylib::File* dylib = _writer.dylibByOrdinal(ord); + if ( dylib->willBeReExported() ) { + // if child says it is an sub-framework of the image being created, then nothing to do here + bool isSubFramework = false; + const char* childInUmbrella = dylib->parentUmbrella(); + if ( childInUmbrella != NULL ) { + const char* myLeaf = strrchr(_options.installPath(), '/'); + if ( myLeaf != NULL ) { + if ( strcmp(childInUmbrella, &myLeaf[1]) == 0 ) + isSubFramework = true; + } + } + // LC_SUB_FRAMEWORK is in child, so do nothing in parent + if ( ! isSubFramework ) { + // this dylib also needs a sub_x load command + bool isFrameworkReExport = false; + const char* lastSlash = strrchr(dylib->installPath(), '/'); + if ( lastSlash != NULL ) { + char frameworkName[strlen(lastSlash)+20]; + sprintf(frameworkName, "/%s.framework/", &lastSlash[1]); + isFrameworkReExport = (strstr(dylib->installPath(), frameworkName) != NULL); + } + if ( isFrameworkReExport ) { + // needs a LC_SUB_UMBRELLA command + _subUmbrellaNames.push_back(&lastSlash[1]); + } + else { + // needs a LC_SUB_LIBRARY command + const char* nameStart = &lastSlash[1]; + if ( lastSlash == NULL ) + nameStart = dylib->installPath(); + int len = strlen(nameStart); + const char* dot = strchr(nameStart, '.'); + if ( dot != NULL ) + len = dot - nameStart; + char* subLibName = new char[len+1]; + strlcpy(subLibName, nameStart, len+1); + _subLibraryNames.push_back(subLibName); + } + } + } + } + } +} + +template +uint32_t HeaderAndLoadCommandsAtom::alignedSize(uint32_t size) +{ + if ( sizeof(pint_t) == 4 ) + return ((size+3) & (-4)); // 4-byte align all load commands for 32-bit mach-o + else + return ((size+7) & (-8)); // 8-byte align all load commands for 64-bit mach-o +} + + +template +unsigned int HeaderAndLoadCommandsAtom::nonHiddenSectionCount() const +{ + unsigned int count = 0; + for (std::vector::iterator it = _state.sections.begin(); it != _state.sections.end(); ++it) { + if ( ! (*it)->isSectionHidden() && ((*it)->type() != ld::Section::typeTentativeDefs) ) + ++count; + } + return count; +} + +template +unsigned int HeaderAndLoadCommandsAtom::segmentCount() const +{ + if ( _options.outputKind() == Options::kObjectFile ) { + // .o files have one anonymous segment that contains all sections + return 1; + } + + unsigned int count = 0; + const char* lastSegName = ""; + for (std::vector::iterator it = _state.sections.begin(); it != _state.sections.end(); ++it) { + if ( _options.outputKind() == Options::kPreload ) { + if ( (*it)->type() == ld::Section::typeMachHeader ) + continue; // for -preload, don't put hidden __HEADER segment into output + if ( (*it)->type() == ld::Section::typeLinkEdit ) + continue; // for -preload, don't put hidden __LINKEDIT segment into output + } + if ( strcmp(lastSegName, (*it)->segmentName()) != 0 ) { + lastSegName = (*it)->segmentName(); + ++count; + } + } + return count; +} + + +template +uint64_t HeaderAndLoadCommandsAtom::size() const +{ + uint32_t sz = sizeof(macho_header

); + + sz += sizeof(macho_segment_command

) * this->segmentCount(); + sz += sizeof(macho_section

) * this->nonHiddenSectionCount(); + + if ( _hasDylibIDLoadCommand ) + sz += alignedSize(sizeof(macho_dylib_command

) + strlen(_options.installPath()) + 1); + + if ( _hasDyldInfoLoadCommand ) + sz += sizeof(macho_dyld_info_command

); + + if ( _hasSymbolTableLoadCommand ) + sz += sizeof(macho_symtab_command

); + + if ( _hasDynamicSymbolTableLoadCommand ) + sz += sizeof(macho_dysymtab_command

); + + if ( _hasDyldLoadCommand ) + sz += alignedSize(sizeof(macho_dylinker_command

) + strlen(_options.dyldInstallPath()) + 1); + + if ( _hasRoutinesLoadCommand ) + sz += sizeof(macho_routines_command

); + + if ( _hasUUIDLoadCommand ) + sz += sizeof(macho_uuid_command

); + + if ( _hasVersionLoadCommand ) + sz += sizeof(macho_version_min_command

); + + if ( _hasThreadLoadCommand ) + sz += this->threadLoadCommandSize(); + + if ( _hasEncryptionLoadCommand ) + sz += sizeof(macho_encryption_info_command

); + + if ( _hasSplitSegInfoLoadCommand ) + sz += sizeof(macho_linkedit_data_command

); + + for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) { + sz += alignedSize(sizeof(macho_dylib_command

) + strlen(_writer.dylibByOrdinal(ord)->installPath()) + 1); + } + + if ( _hasRPathLoadCommands ) { + const std::vector& rpaths = _options.rpaths(); + for (std::vector::const_iterator it = rpaths.begin(); it != rpaths.end(); ++it) { + sz += alignedSize(sizeof(macho_rpath_command

) + strlen(*it) + 1); + } + } + + if ( _hasSubFrameworkLoadCommand ) + sz += alignedSize(sizeof(macho_sub_framework_command

) + strlen(_options.umbrellaName()) + 1); + + for (std::vector::const_iterator it = _subLibraryNames.begin(); it != _subLibraryNames.end(); ++it) { + sz += alignedSize(sizeof(macho_sub_library_command

) + strlen(*it) + 1); + } + + for (std::vector::const_iterator it = _subUmbrellaNames.begin(); it != _subUmbrellaNames.end(); ++it) { + sz += alignedSize(sizeof(macho_sub_umbrella_command

) + strlen(*it) + 1); + } + + if ( _allowableClientLoadCommmandsCount != 0 ) { + const std::vector& clients = _options.allowableClients(); + for (std::vector::const_iterator it = clients.begin(); it != clients.end(); ++it) { + sz += alignedSize(sizeof(macho_sub_client_command

) + strlen(*it) + 1); + } + } + + if ( _dyldEnvironExrasCount != 0 ) { + const std::vector& extras = _options.dyldEnvironExtras(); + for (std::vector::const_iterator it = extras.begin(); it != extras.end(); ++it) { + sz += alignedSize(sizeof(macho_dylinker_command

) + strlen(*it) + 1); + } + } + + if ( _hasFunctionStartsLoadCommand ) + sz += sizeof(macho_linkedit_data_command

); + + return sz; +} + +template +uint32_t HeaderAndLoadCommandsAtom::commandsCount() const +{ + uint32_t count = this->segmentCount(); + + if ( _hasDylibIDLoadCommand ) + ++count; + + if ( _hasDyldInfoLoadCommand ) + ++count; + + if ( _hasSymbolTableLoadCommand ) + ++count; + + if ( _hasDynamicSymbolTableLoadCommand ) + ++count; + + if ( _hasDyldLoadCommand ) + ++count; + + if ( _hasRoutinesLoadCommand ) + ++count; + + if ( _hasUUIDLoadCommand ) + ++count; + + if ( _hasVersionLoadCommand ) + ++count; + + if ( _hasThreadLoadCommand ) + ++count; + + if ( _hasEncryptionLoadCommand ) + ++count; + + if ( _hasSplitSegInfoLoadCommand ) + ++count; + + count += _dylibLoadCommmandsCount; + + count += _options.rpaths().size(); + + if ( _hasSubFrameworkLoadCommand ) + ++count; + + count += _subLibraryNames.size(); + + count += _subUmbrellaNames.size(); + + count += _allowableClientLoadCommmandsCount; + + count += _dyldEnvironExrasCount; + + if ( _hasFunctionStartsLoadCommand ) + ++count; + + return count; +} + +template +uint32_t HeaderAndLoadCommandsAtom::fileType() const +{ + switch ( _options.outputKind() ) { + case Options::kDynamicExecutable: + case Options::kStaticExecutable: + return MH_EXECUTE; + case Options::kDynamicLibrary: + return MH_DYLIB; + case Options::kDynamicBundle: + return MH_BUNDLE; + case Options::kObjectFile: + return MH_OBJECT; + case Options::kDyld: + return MH_DYLINKER; + case Options::kPreload: + return MH_PRELOAD; + case Options::kKextBundle: + return MH_KEXT_BUNDLE; + } + throw "unknonwn mach-o file type"; +} + +template +uint32_t HeaderAndLoadCommandsAtom::flags() const +{ + uint32_t bits = 0; + if ( _options.outputKind() == Options::kObjectFile ) { + if ( _state.allObjectFilesScatterable ) + bits = MH_SUBSECTIONS_VIA_SYMBOLS; + } + else { + if ( _options.outputKind() == Options::kStaticExecutable ) { + bits |= MH_NOUNDEFS; + } + else if ( _options.outputKind() == Options::kPreload ) { + bits |= MH_NOUNDEFS; + if ( _options.positionIndependentExecutable() ) + bits |= MH_PIE; + } + else { + bits = MH_DYLDLINK; + switch ( _options.nameSpace() ) { + case Options::kTwoLevelNameSpace: + bits |= MH_TWOLEVEL | MH_NOUNDEFS; + break; + case Options::kFlatNameSpace: + break; + case Options::kForceFlatNameSpace: + bits |= MH_FORCE_FLAT; + break; + } + if ( _writer.hasWeakExternalSymbols || _writer.overridesWeakExternalSymbols ) + bits |= MH_WEAK_DEFINES; + if ( _writer.usesWeakExternalSymbols || _writer.hasWeakExternalSymbols ) + bits |= MH_BINDS_TO_WEAK; + if ( _options.prebind() ) + bits |= MH_PREBOUND; + if ( _options.splitSeg() ) + bits |= MH_SPLIT_SEGS; + if ( (_options.outputKind() == Options::kDynamicLibrary) + && _writer._noReExportedDylibs + && _options.useSimplifiedDylibReExports() ) { + bits |= MH_NO_REEXPORTED_DYLIBS; + } + if ( _options.positionIndependentExecutable() && ! _writer.pieDisabled ) + bits |= MH_PIE; + if ( _options.markAutoDeadStripDylib() ) + bits |= MH_DEAD_STRIPPABLE_DYLIB; + if ( _writer.hasThreadLocalVariableDefinitions ) + bits |= MH_HAS_TLV_DESCRIPTORS; + if ( _options.hasNonExecutableHeap() ) + bits |= MH_NO_HEAP_EXECUTION; + } + if ( _options.hasExecutableStack() ) + bits |= MH_ALLOW_STACK_EXECUTION; + } + return bits; +} + +template <> uint32_t HeaderAndLoadCommandsAtom::magic() const { return MH_MAGIC; } +template <> uint32_t HeaderAndLoadCommandsAtom::magic() const { return MH_MAGIC_64; } +template <> uint32_t HeaderAndLoadCommandsAtom::magic() const { return MH_MAGIC; } +template <> uint32_t HeaderAndLoadCommandsAtom::magic() const { return MH_MAGIC_64; } +template <> uint32_t HeaderAndLoadCommandsAtom::magic() const { return MH_MAGIC; } + +template <> uint32_t HeaderAndLoadCommandsAtom::cpuType() const { return CPU_TYPE_POWERPC; } +template <> uint32_t HeaderAndLoadCommandsAtom::cpuType() const { return CPU_TYPE_POWERPC64; } +template <> uint32_t HeaderAndLoadCommandsAtom::cpuType() const { return CPU_TYPE_I386; } +template <> uint32_t HeaderAndLoadCommandsAtom::cpuType() const { return CPU_TYPE_X86_64; } +template <> uint32_t HeaderAndLoadCommandsAtom::cpuType() const { return CPU_TYPE_ARM; } + + +template <> +uint32_t HeaderAndLoadCommandsAtom::cpuSubType() const +{ + return _state.cpuSubType; +} + +template <> +uint32_t HeaderAndLoadCommandsAtom::cpuSubType() const +{ + if ( (_options.outputKind() == Options::kDynamicExecutable) && (_options.macosxVersionMin() >= ld::mac10_5) ) + return (CPU_SUBTYPE_POWERPC_ALL | 0x80000000); + else + return CPU_SUBTYPE_POWERPC_ALL; +} + +template <> +uint32_t HeaderAndLoadCommandsAtom::cpuSubType() const +{ + return CPU_SUBTYPE_I386_ALL; +} + +template <> +uint32_t HeaderAndLoadCommandsAtom::cpuSubType() const +{ + if ( (_options.outputKind() == Options::kDynamicExecutable) && (_options.macosxVersionMin() >= ld::mac10_5) ) + return (CPU_SUBTYPE_X86_64_ALL | 0x80000000); + else + return CPU_SUBTYPE_X86_64_ALL; +} + +template <> +uint32_t HeaderAndLoadCommandsAtom::cpuSubType() const +{ + return _state.cpuSubType; +} + + + +template +uint8_t* HeaderAndLoadCommandsAtom::copySingleSegmentLoadCommand(uint8_t* p) const +{ + // in .o files there is just one segment load command with a blank name + // and all sections under it + macho_segment_command

* cmd = (macho_segment_command

*)p; + cmd->set_cmd(macho_segment_command

::CMD); + cmd->set_segname(""); + cmd->set_vmaddr(_options.baseAddress()); + cmd->set_vmsize(0); // updated after sections set + cmd->set_fileoff(0); // updated after sections set + cmd->set_filesize(0); // updated after sections set + cmd->set_maxprot(VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE); + cmd->set_initprot(VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE); + cmd->set_nsects(this->nonHiddenSectionCount()); + cmd->set_flags(0); + // add sections array + macho_section

* msect = (macho_section

*)&p[sizeof(macho_segment_command

)]; + for (std::vector::iterator sit = _state.sections.begin(); sit != _state.sections.end(); ++sit) { + ld::Internal::FinalSection* fsect = *sit; + if ( fsect->isSectionHidden() ) + continue; + if ( fsect->type() == ld::Section::typeTentativeDefs ) + continue; + msect->set_sectname(fsect->sectionName()); + msect->set_segname(fsect->segmentName()); + msect->set_addr(fsect->address); + msect->set_size(fsect->size); + msect->set_offset(fsect->fileOffset); + msect->set_align(fsect->alignment); + msect->set_reloff((fsect->relocCount == 0) ? 0 : _writer.sectionRelocationsSection->fileOffset + fsect->relocStart * sizeof(macho_relocation_info

)); + msect->set_nreloc(fsect->relocCount); + msect->set_flags(sectionFlags(fsect)); + msect->set_reserved1(fsect->indirectSymTabStartIndex); + msect->set_reserved2(fsect->indirectSymTabElementSize); + // update segment info + if ( cmd->fileoff() == 0 ) + cmd->set_fileoff(fsect->fileOffset); + cmd->set_vmsize(fsect->address + fsect->size - cmd->vmaddr()); + if ( (fsect->type() != ld::Section::typeZeroFill) && (fsect->type() != ld::Section::typeTentativeDefs) ) + cmd->set_filesize(fsect->fileOffset + fsect->size - cmd->fileoff()); + ++msect; + } + cmd->set_cmdsize(sizeof(macho_segment_command

) + cmd->nsects()*sizeof(macho_section

)); + return p + cmd->cmdsize(); +} + +struct SegInfo { + SegInfo(const char* n, const Options&); + const char* segName; + uint32_t nonHiddenSectionCount; + uint32_t maxProt; + uint32_t initProt; + std::vector sections; +}; + + +SegInfo::SegInfo(const char* n, const Options& opts) + : segName(n), nonHiddenSectionCount(0), maxProt(opts.maxSegProtection(n)), initProt(opts.initialSegProtection(n)) +{ +} + + +template +uint32_t HeaderAndLoadCommandsAtom::sectionFlags(ld::Internal::FinalSection* sect) const +{ + uint32_t bits; + switch ( sect->type() ) { + case ld::Section::typeUnclassified: + if ( strcmp(sect->segmentName(), "__OBJC") == 0 ) + return S_REGULAR | S_ATTR_NO_DEAD_STRIP; + else if ( (strcmp(sect->sectionName(), "__objc_classlist") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) ) + return S_REGULAR | S_ATTR_NO_DEAD_STRIP; + else if ( (strcmp(sect->sectionName(), "__objc_catlist") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) ) + return S_REGULAR | S_ATTR_NO_DEAD_STRIP; + else if ( (strncmp(sect->sectionName(), "__objc_superrefs", 16) == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) ) + return S_REGULAR | S_ATTR_NO_DEAD_STRIP; + else + return S_REGULAR; + case ld::Section::typeCode: + bits = S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS; + if ( sect->hasLocalRelocs && ! _writer.pieDisabled ) + bits |= S_ATTR_LOC_RELOC; + if ( sect->hasExternalRelocs ) + bits |= S_ATTR_EXT_RELOC; + return bits; + case ld::Section::typePageZero: + return S_REGULAR; + case ld::Section::typeImportProxies: + return S_REGULAR; + case ld::Section::typeLinkEdit: + return S_REGULAR; + case ld::Section::typeMachHeader: + return S_REGULAR; + case ld::Section::typeStack: + return S_REGULAR; + case ld::Section::typeLiteral4: + return S_4BYTE_LITERALS; + case ld::Section::typeLiteral8: + return S_8BYTE_LITERALS; + case ld::Section::typeLiteral16: + return S_16BYTE_LITERALS; + case ld::Section::typeConstants: + return S_REGULAR; + case ld::Section::typeTempLTO: + assert(0 && "typeTempLTO should not make it to final linked image"); + return S_REGULAR; + case ld::Section::typeAbsoluteSymbols: + assert(0 && "typeAbsoluteSymbols should not make it to final linked image"); + return S_REGULAR; + case ld::Section::typeCString: + case ld::Section::typeNonStdCString: + return S_CSTRING_LITERALS; + case ld::Section::typeCStringPointer: + return S_LITERAL_POINTERS | S_ATTR_NO_DEAD_STRIP; + case ld::Section::typeUTF16Strings: + return S_REGULAR; + case ld::Section::typeCFString: + return S_REGULAR; + case ld::Section::typeObjC1Classes: + return S_REGULAR | S_ATTR_NO_DEAD_STRIP; + case ld::Section::typeCFI: + return S_REGULAR; + case ld::Section::typeLSDA: + return S_REGULAR; + case ld::Section::typeDtraceDOF: + return S_DTRACE_DOF; + case ld::Section::typeUnwindInfo: + return S_REGULAR; + case ld::Section::typeObjCClassRefs: + case ld::Section::typeObjC2CategoryList: + return S_REGULAR | S_ATTR_NO_DEAD_STRIP; + case ld::Section::typeZeroFill: + if ( _options.optimizeZeroFill() ) + return S_ZEROFILL; + else + return S_REGULAR; + case ld::Section::typeTentativeDefs: + assert(0 && "typeTentativeDefs should not make it to final linked image"); + return S_REGULAR; + case ld::Section::typeLazyPointer: + case ld::Section::typeLazyPointerClose: + return S_LAZY_SYMBOL_POINTERS; + case ld::Section::typeStubClose: + case ld::Section::typeStub: + if ( sect->hasLocalRelocs ) + return S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_LOC_RELOC; + else + return S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS; + case ld::Section::typeNonLazyPointer: + return S_NON_LAZY_SYMBOL_POINTERS; + case ld::Section::typeDyldInfo: + return S_REGULAR; + case ld::Section::typeLazyDylibPointer: + return S_LAZY_DYLIB_SYMBOL_POINTERS; + case ld::Section::typeStubHelper: + if ( sect->hasLocalRelocs ) + return S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_LOC_RELOC; + else + return S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS; + case ld::Section::typeInitializerPointers: + return S_MOD_INIT_FUNC_POINTERS; + case ld::Section::typeTerminatorPointers: + return S_MOD_TERM_FUNC_POINTERS; + case ld::Section::typeTLVInitialValues: + return S_THREAD_LOCAL_REGULAR; + case ld::Section::typeTLVZeroFill: + return S_THREAD_LOCAL_ZEROFILL; + case ld::Section::typeTLVDefs: + return S_THREAD_LOCAL_VARIABLES; + case ld::Section::typeTLVInitializerPointers: + return S_THREAD_LOCAL_INIT_FUNCTION_POINTERS; + case ld::Section::typeTLVPointers: + return S_THREAD_LOCAL_VARIABLE_POINTERS; + case ld::Section::typeFirstSection: + assert(0 && "typeFirstSection should not make it to final linked image"); + return S_REGULAR; + case ld::Section::typeLastSection: + assert(0 && "typeLastSection should not make it to final linked image"); + return S_REGULAR; + } + return S_REGULAR; +} + + +template +bool HeaderAndLoadCommandsAtom::sectionTakesNoDiskSpace(ld::Internal::FinalSection* sect) const +{ + switch ( sect->type() ) { + case ld::Section::typeZeroFill: + case ld::Section::typeTLVZeroFill: + return _options.optimizeZeroFill(); + case ld::Section::typeAbsoluteSymbols: + case ld::Section::typeTentativeDefs: + case ld::Section::typeLastSection: + return true; + default: + break; + } + return false; +} + + +template +uint8_t* HeaderAndLoadCommandsAtom::copySegmentLoadCommands(uint8_t* p) const +{ + // group sections into segments + std::vector segs; + const char* lastSegName = ""; + for (std::vector::iterator it = _state.sections.begin(); it != _state.sections.end(); ++it) { + ld::Internal::FinalSection* sect = *it; + if ( _options.outputKind() == Options::kPreload ) { + if ( (*it)->type() == ld::Section::typeMachHeader ) + continue; // for -preload, don't put hidden __HEADER segment into output + if ( (*it)->type() == ld::Section::typeLinkEdit ) + continue; // for -preload, don't put hidden __LINKEDIT segment into output + } + if ( strcmp(lastSegName, sect->segmentName()) != 0 ) { + SegInfo si(sect->segmentName(), _options); + segs.push_back(si); + lastSegName = sect->segmentName(); + } + if ( ! sect->isSectionHidden() ) + segs.back().nonHiddenSectionCount++; + segs.back().sections.push_back(sect); + } + // write out segment load commands for each section with trailing sections + for (std::vector::iterator it = segs.begin(); it != segs.end(); ++it) { + SegInfo& si = *it; + ld::Internal::FinalSection* lastNonZeroFillSection = NULL; + for (int i=si.sections.size()-1; i >= 0; --i) { + if ( !sectionTakesNoDiskSpace(si.sections[i]) ) { + lastNonZeroFillSection = si.sections[i]; + break; + } + } + uint64_t vmsize = si.sections.back()->address + si.sections.back()->size - si.sections.front()->address; + vmsize = ((vmsize+_options.segmentAlignment()-1) & (-_options.segmentAlignment())); + uint64_t filesize = 0; + if ( lastNonZeroFillSection != NULL ) { + filesize = lastNonZeroFillSection->address + lastNonZeroFillSection->size - si.sections.front()->address; + // round up all segments to page aligned, except __LINKEDIT + if ( (si.sections[0]->type() != ld::Section::typeLinkEdit) && (si.sections[0]->type() != ld::Section::typeImportProxies) ) + filesize = (filesize + _options.segmentAlignment()-1) & (-_options.segmentAlignment()); + } + if ( si.sections.front()->type() == ld::Section::typePageZero ) + filesize = 0; + else if ( si.sections.front()->type() == ld::Section::typeStack ) + filesize = 0; + macho_segment_command

* segCmd = (macho_segment_command

*)p; + segCmd->set_cmd(macho_segment_command

::CMD); + segCmd->set_cmdsize(sizeof(macho_segment_command

) + si.nonHiddenSectionCount*sizeof(macho_section

)); + segCmd->set_segname(si.sections.front()->segmentName()); + segCmd->set_vmaddr(si.sections.front()->address); + segCmd->set_vmsize(vmsize); + segCmd->set_fileoff(si.sections.front()->fileOffset); + segCmd->set_filesize(filesize); + segCmd->set_maxprot(si.maxProt); + segCmd->set_initprot(si.initProt); + segCmd->set_nsects(si.nonHiddenSectionCount); + segCmd->set_flags(0); + p += sizeof(macho_segment_command

); + macho_section

* msect = (macho_section

*)p; + for (std::vector::iterator sit = si.sections.begin(); sit != si.sections.end(); ++sit) { + ld::Internal::FinalSection* fsect = *sit; + if ( ! fsect->isSectionHidden() ) { + msect->set_sectname(fsect->sectionName()); + msect->set_segname(fsect->segmentName()); + msect->set_addr(fsect->address); + msect->set_size(fsect->size); + msect->set_offset(sectionTakesNoDiskSpace(fsect) ? 0 : fsect->fileOffset); + msect->set_align(fsect->alignment); + msect->set_reloff(0); + msect->set_nreloc(0); + msect->set_flags(sectionFlags(fsect)); + msect->set_reserved1(fsect->indirectSymTabStartIndex); + msect->set_reserved2(fsect->indirectSymTabElementSize); + p += sizeof(macho_section

); + ++msect; + } + } + } + + return p; +} + + +template +uint8_t* HeaderAndLoadCommandsAtom::copySymbolTableLoadCommand(uint8_t* p) const +{ + // build LC_SYMTAB command + macho_symtab_command

* symbolTableCmd = (macho_symtab_command

*)p; + symbolTableCmd->set_cmd(LC_SYMTAB); + symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command

)); + symbolTableCmd->set_nsyms(_writer.symbolTableSection->size/sizeof(macho_nlist

)); + symbolTableCmd->set_symoff(_writer.symbolTableSection->size == 0 ? 0 : _writer.symbolTableSection->fileOffset); + symbolTableCmd->set_stroff(_writer.stringPoolSection->size == 0 ? 0 : _writer.stringPoolSection->fileOffset ); + symbolTableCmd->set_strsize(_writer.stringPoolSection->size); + return p + sizeof(macho_symtab_command

); +} + +template +uint8_t* HeaderAndLoadCommandsAtom::copyDynamicSymbolTableLoadCommand(uint8_t* p) const +{ + // build LC_SYMTAB command + macho_dysymtab_command

* dynamicSymbolTableCmd = (macho_dysymtab_command

*)p; + dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB); + dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command

)); + dynamicSymbolTableCmd->set_ilocalsym(0); + dynamicSymbolTableCmd->set_nlocalsym(_writer._localSymbolsCount); + dynamicSymbolTableCmd->set_iextdefsym(dynamicSymbolTableCmd->ilocalsym()+dynamicSymbolTableCmd->nlocalsym()); + dynamicSymbolTableCmd->set_nextdefsym(_writer._globalSymbolsCount); + dynamicSymbolTableCmd->set_iundefsym(dynamicSymbolTableCmd->iextdefsym()+dynamicSymbolTableCmd->nextdefsym()); + dynamicSymbolTableCmd->set_nundefsym(_writer._importSymbolsCount); + + // FIX ME: support for 10.3 dylibs which need modules + //if ( fWriter.fModuleInfoAtom != NULL ) { + // dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset()); + // dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount); + // dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset()); + // dynamicSymbolTableCmd->set_nmodtab(1); + // dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset()); + // dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount()); + //} + + bool hasIndirectSymbols = ( (_writer.indirectSymbolTableSection != NULL) && (_writer.indirectSymbolTableSection->size != 0) ); + dynamicSymbolTableCmd->set_indirectsymoff(hasIndirectSymbols ? _writer.indirectSymbolTableSection->fileOffset : 0); + dynamicSymbolTableCmd->set_nindirectsyms( hasIndirectSymbols ? _writer.indirectSymbolTableSection->size/sizeof(uint32_t) : 0); + + // FIX ME: support for classic relocations + if ( _options.outputKind() != Options::kObjectFile ) { + bool hasExternalRelocs = ( (_writer.externalRelocationsSection != NULL) && (_writer.externalRelocationsSection->size != 0) ); + dynamicSymbolTableCmd->set_extreloff(hasExternalRelocs ? _writer.externalRelocationsSection->fileOffset : 0); + dynamicSymbolTableCmd->set_nextrel( hasExternalRelocs ? _writer.externalRelocationsSection->size/8 : 0); + bool hasLocalRelocs = ( (_writer.localRelocationsSection != NULL) && (_writer.localRelocationsSection->size != 0) ); + dynamicSymbolTableCmd->set_locreloff(hasLocalRelocs ? _writer.localRelocationsSection->fileOffset : 0); + dynamicSymbolTableCmd->set_nlocrel (hasLocalRelocs ? _writer.localRelocationsSection->size/8 : 0); + } + return p + sizeof(macho_dysymtab_command

); +} + + +template +uint8_t* HeaderAndLoadCommandsAtom::copyDyldInfoLoadCommand(uint8_t* p) const +{ + // build LC_DYLD_INFO command + macho_dyld_info_command

* cmd = (macho_dyld_info_command

*)p; + + cmd->set_cmd(LC_DYLD_INFO_ONLY); + cmd->set_cmdsize(sizeof(macho_dyld_info_command

)); + if ( _writer.rebaseSection->size != 0 ) { + cmd->set_rebase_off(_writer.rebaseSection->fileOffset); + cmd->set_rebase_size(_writer.rebaseSection->size); + } + if ( _writer.bindingSection->size != 0 ) { + cmd->set_bind_off(_writer.bindingSection->fileOffset); + cmd->set_bind_size(_writer.bindingSection->size); + } + if ( _writer.weakBindingSection->size != 0 ) { + cmd->set_weak_bind_off(_writer.weakBindingSection->fileOffset); + cmd->set_weak_bind_size(_writer.weakBindingSection->size); + } + if ( _writer.lazyBindingSection->size != 0 ) { + cmd->set_lazy_bind_off(_writer.lazyBindingSection->fileOffset); + cmd->set_lazy_bind_size(_writer.lazyBindingSection->size); + } + if ( _writer.exportSection->size != 0 ) { + cmd->set_export_off(_writer.exportSection->fileOffset); + cmd->set_export_size(_writer.exportSection->size); + } + return p + sizeof(macho_dyld_info_command

); +} + + +template +uint8_t* HeaderAndLoadCommandsAtom::copyDyldLoadCommand(uint8_t* p) const +{ + uint32_t sz = alignedSize(sizeof(macho_dylinker_command

) + strlen(_options.dyldInstallPath()) + 1); + macho_dylinker_command

* cmd = (macho_dylinker_command

*)p; + if ( _options.outputKind() == Options::kDyld ) + cmd->set_cmd(LC_ID_DYLINKER); + else + cmd->set_cmd(LC_LOAD_DYLINKER); + cmd->set_cmdsize(sz); + cmd->set_name_offset(); + strcpy((char*)&p[sizeof(macho_dylinker_command

)], _options.dyldInstallPath()); + return p + sz; +} + + +template +uint8_t* HeaderAndLoadCommandsAtom::copyDylibIDLoadCommand(uint8_t* p) const +{ + uint32_t sz = alignedSize(sizeof(macho_dylib_command

) + strlen(_options.installPath()) + 1); + macho_dylib_command

* cmd = (macho_dylib_command

*)p; + cmd->set_cmd(LC_ID_DYLIB); + cmd->set_cmdsize(sz); + cmd->set_name_offset(); + cmd->set_timestamp(1); // needs to be some constant value that is different than DylibLoadCommandsAtom uses + cmd->set_current_version(_options.currentVersion()); + cmd->set_compatibility_version(_options.compatibilityVersion()); + strcpy((char*)&p[sizeof(macho_dylib_command

)], _options.installPath()); + return p + sz; +} + +template +uint8_t* HeaderAndLoadCommandsAtom::copyRoutinesLoadCommand(uint8_t* p) const +{ + pint_t initAddr = _state.entryPoint->finalAddress(); + if ( _state.entryPoint->isThumb() ) + initAddr |= 1ULL; + macho_routines_command

* cmd = (macho_routines_command

*)p; + cmd->set_cmd(macho_routines_command

::CMD); + cmd->set_cmdsize(sizeof(macho_routines_command

)); + cmd->set_init_address(initAddr); + return p + sizeof(macho_routines_command

); +} + + +template +void HeaderAndLoadCommandsAtom::recopyUUIDCommand() +{ + assert(_uuidCmdInOutputBuffer != NULL); + _uuidCmdInOutputBuffer->set_uuid(_uuid); +} + + +template +uint8_t* HeaderAndLoadCommandsAtom::copyUUIDLoadCommand(uint8_t* p) const +{ + macho_uuid_command

* cmd = (macho_uuid_command

*)p; + cmd->set_cmd(LC_UUID); + cmd->set_cmdsize(sizeof(macho_uuid_command

)); + cmd->set_uuid(_uuid); + _uuidCmdInOutputBuffer = cmd; // save for later re-write by recopyUUIDCommand() + return p + sizeof(macho_uuid_command

); +} + + +template +uint8_t* HeaderAndLoadCommandsAtom::copyVersionLoadCommand(uint8_t* p) const +{ + macho_version_min_command

* cmd = (macho_version_min_command

*)p; + ld::MacVersionMin macVersion = _options.macosxVersionMin(); + ld::IPhoneVersionMin iphoneOSVersion = _options.iphoneOSVersionMin(); + assert( (macVersion != ld::macVersionUnset) || (iphoneOSVersion != ld::iPhoneVersionUnset) ); + if ( macVersion != ld::macVersionUnset ) { + cmd->set_cmd(LC_VERSION_MIN_MACOSX); + cmd->set_cmdsize(sizeof(macho_version_min_command

)); + cmd->set_version((uint32_t)macVersion); + cmd->set_reserved(0); + } + else { + cmd->set_cmd(LC_VERSION_MIN_IPHONEOS); + cmd->set_cmdsize(sizeof(macho_version_min_command

)); + cmd->set_version((uint32_t)iphoneOSVersion); + cmd->set_reserved(0); + } + return p + sizeof(macho_version_min_command

); +} + + +template <> +uint32_t HeaderAndLoadCommandsAtom::threadLoadCommandSize() const +{ + return this->alignedSize(16 + 40*4); // base size + PPC_THREAD_STATE_COUNT * 4 +} + + +template <> +uint8_t* HeaderAndLoadCommandsAtom::copyThreadsLoadCommand(uint8_t* p) const +{ + assert(_state.entryPoint != NULL); + pint_t start = _state.entryPoint->finalAddress(); + macho_thread_command* cmd = (macho_thread_command*)p; + cmd->set_cmd(LC_UNIXTHREAD); + cmd->set_cmdsize(threadLoadCommandSize()); + cmd->set_flavor(1); // PPC_THREAD_STATE + cmd->set_count(40); // PPC_THREAD_STATE_COUNT; + cmd->set_thread_register(0, start); + if ( _options.hasCustomStack() ) + cmd->set_thread_register(3, _options.customStackAddr()); // r1 + return p + threadLoadCommandSize(); +} + +template <> +uint32_t HeaderAndLoadCommandsAtom::threadLoadCommandSize() const +{ + return this->alignedSize(16 + 76*4); // base size + PPC_THREAD_STATE64_COUNT * 4 +} + +template <> +uint8_t* HeaderAndLoadCommandsAtom::copyThreadsLoadCommand(uint8_t* p) const +{ + assert(_state.entryPoint != NULL); + pint_t start = _state.entryPoint->finalAddress(); + macho_thread_command* cmd = (macho_thread_command*)p; + cmd->set_cmd(LC_UNIXTHREAD); + cmd->set_cmdsize(threadLoadCommandSize()); + cmd->set_flavor(5); // PPC_THREAD_STATE64 + cmd->set_count(76); // PPC_THREAD_STATE64_COUNT; + cmd->set_thread_register(0, start); + if ( _options.hasCustomStack() ) + cmd->set_thread_register(3, _options.customStackAddr()); // r1 + return p + threadLoadCommandSize(); +} + +template <> +uint32_t HeaderAndLoadCommandsAtom::threadLoadCommandSize() const +{ + return this->alignedSize(16 + 16*4); // base size + i386_THREAD_STATE_COUNT * 4 +} + +template <> +uint8_t* HeaderAndLoadCommandsAtom::copyThreadsLoadCommand(uint8_t* p) const +{ + assert(_state.entryPoint != NULL); + pint_t start = _state.entryPoint->finalAddress(); + macho_thread_command

* cmd = (macho_thread_command

*)p; + cmd->set_cmd(LC_UNIXTHREAD); + cmd->set_cmdsize(threadLoadCommandSize()); + cmd->set_flavor(1); // i386_THREAD_STATE + cmd->set_count(16); // i386_THREAD_STATE_COUNT; + cmd->set_thread_register(10, start); + if ( _options.hasCustomStack() ) + cmd->set_thread_register(7, _options.customStackAddr()); // r1 + return p + threadLoadCommandSize(); +} + +template <> +uint32_t HeaderAndLoadCommandsAtom::threadLoadCommandSize() const +{ + return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4); +} + +template <> +uint8_t* HeaderAndLoadCommandsAtom::copyThreadsLoadCommand(uint8_t* p) const +{ + assert(_state.entryPoint != NULL); + pint_t start = _state.entryPoint->finalAddress(); + macho_thread_command

* cmd = (macho_thread_command

*)p; + cmd->set_cmd(LC_UNIXTHREAD); + cmd->set_cmdsize(threadLoadCommandSize()); + cmd->set_flavor(x86_THREAD_STATE64); + cmd->set_count(x86_THREAD_STATE64_COUNT); + cmd->set_thread_register(16, start); // rip + if ( _options.hasCustomStack() ) + cmd->set_thread_register(7, _options.customStackAddr()); // r1 + return p + threadLoadCommandSize(); +} + +template <> +uint32_t HeaderAndLoadCommandsAtom::threadLoadCommandSize() const +{ + return this->alignedSize(16 + 17 * 4); // base size + ARM_THREAD_STATE_COUNT * 4 +} + +template <> +uint8_t* HeaderAndLoadCommandsAtom::copyThreadsLoadCommand(uint8_t* p) const +{ + assert(_state.entryPoint != NULL); + pint_t start = _state.entryPoint->finalAddress(); + if ( _state.entryPoint->isThumb() ) + start |= 1ULL; + macho_thread_command

* cmd = (macho_thread_command

*)p; + cmd->set_cmd(LC_UNIXTHREAD); + cmd->set_cmdsize(threadLoadCommandSize()); + cmd->set_flavor(1); + cmd->set_count(17); + cmd->set_thread_register(15, start); // pc + if ( _options.hasCustomStack() ) + cmd->set_thread_register(13, _options.customStackAddr()); // sp + return p + threadLoadCommandSize(); +} + +template +uint8_t* HeaderAndLoadCommandsAtom::copyEncryptionLoadCommand(uint8_t* p) const +{ + macho_encryption_info_command

* cmd = (macho_encryption_info_command

*)p; + cmd->set_cmd(LC_ENCRYPTION_INFO); + cmd->set_cmdsize(sizeof(macho_encryption_info_command

)); + assert(_writer.encryptedTextStartOffset() != 0); + assert(_writer.encryptedTextEndOffset() != 0); + cmd->set_cryptoff(_writer.encryptedTextStartOffset()); + cmd->set_cryptsize(_writer.encryptedTextEndOffset()-_writer.encryptedTextStartOffset()); + cmd->set_cryptid(0); + return p + sizeof(macho_encryption_info_command

); +} + + +template +uint8_t* HeaderAndLoadCommandsAtom::copySplitSegInfoLoadCommand(uint8_t* p) const +{ + macho_linkedit_data_command

* cmd = (macho_linkedit_data_command

*)p; + cmd->set_cmd(LC_SEGMENT_SPLIT_INFO); + cmd->set_cmdsize(sizeof(macho_linkedit_data_command

)); + cmd->set_dataoff(_writer.splitSegInfoSection->fileOffset); + cmd->set_datasize(_writer.splitSegInfoSection->size); + return p + sizeof(macho_linkedit_data_command

); +} + + +template +uint8_t* HeaderAndLoadCommandsAtom::copyDylibLoadCommand(uint8_t* p, const ld::dylib::File* dylib) const +{ + uint32_t sz = alignedSize(sizeof(macho_dylib_command

) + strlen(dylib->installPath()) + 1); + macho_dylib_command

* cmd = (macho_dylib_command

*)p; + // If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB + bool autoWeakLoadDylib = false; // FIX + //( (fWriter.fDylibReadersWithWeakImports.count(fInfo.reader) > 0) + //&& (fWriter.fDylibReadersWithNonWeakImports.count(fInfo.reader) == 0) ); + if ( dylib->willBeLazyLoadedDylib() ) + cmd->set_cmd(LC_LAZY_LOAD_DYLIB); + else if ( dylib->willBeWeakLinked() || autoWeakLoadDylib ) + cmd->set_cmd(LC_LOAD_WEAK_DYLIB); + else if ( dylib->willBeReExported() && _options.useSimplifiedDylibReExports() ) + cmd->set_cmd(LC_REEXPORT_DYLIB); + else if ( dylib->willBeUpwardDylib() && _options.useUpwardDylibs() ) + cmd->set_cmd(LC_LOAD_UPWARD_DYLIB); + else + cmd->set_cmd(LC_LOAD_DYLIB); + cmd->set_cmdsize(sz); + cmd->set_timestamp(2); // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses + cmd->set_current_version(dylib->currentVersion()); + cmd->set_compatibility_version(dylib->compatibilityVersion()); + cmd->set_name_offset(); + strcpy((char*)&p[sizeof(macho_dylib_command

)], dylib->installPath()); + return p + sz; +} + +template +uint8_t* HeaderAndLoadCommandsAtom::copyRPathLoadCommand(uint8_t* p, const char* path) const +{ + uint32_t sz = alignedSize(sizeof(macho_rpath_command

) + strlen(path) + 1); + macho_rpath_command

* cmd = (macho_rpath_command

*)p; + cmd->set_cmd(LC_RPATH); + cmd->set_cmdsize(sz); + cmd->set_path_offset(); + strcpy((char*)&p[sizeof(macho_rpath_command

)], path); + return p + sz; +} + +template +uint8_t* HeaderAndLoadCommandsAtom::copySubFrameworkLoadCommand(uint8_t* p) const +{ + const char* umbrellaName = _options.umbrellaName(); + uint32_t sz = alignedSize(sizeof(macho_sub_framework_command

) + strlen(umbrellaName) + 1); + macho_sub_framework_command

* cmd = (macho_sub_framework_command

*)p; + cmd->set_cmd(LC_SUB_FRAMEWORK); + cmd->set_cmdsize(sz); + cmd->set_umbrella_offset(); + strcpy((char*)&p[sizeof(macho_sub_framework_command

)], umbrellaName); + return p + sz; +} + + +template +uint8_t* HeaderAndLoadCommandsAtom::copyAllowableClientLoadCommand(uint8_t* p, const char* client) const +{ + uint32_t sz = alignedSize(sizeof(macho_sub_client_command

) + strlen(client) + 1); + macho_sub_client_command

* cmd = (macho_sub_client_command

*)p; + cmd->set_cmd(LC_SUB_CLIENT); + cmd->set_cmdsize(sz); + cmd->set_client_offset(); + strcpy((char*)&p[sizeof(macho_sub_client_command

)], client); + return p + sz; +} + +template +uint8_t* HeaderAndLoadCommandsAtom::copyDyldEnvLoadCommand(uint8_t* p, const char* env) const +{ + uint32_t sz = alignedSize(sizeof(macho_dylinker_command

) + strlen(env) + 1); + macho_dylinker_command

* cmd = (macho_dylinker_command

*)p; + cmd->set_cmd(LC_DYLD_ENVIRONMENT); + cmd->set_cmdsize(sz); + cmd->set_name_offset(); + strcpy((char*)&p[sizeof(macho_dylinker_command

)], env); + return p + sz; +} + +template +uint8_t* HeaderAndLoadCommandsAtom::copySubUmbrellaLoadCommand(uint8_t* p, const char* nm) const +{ + uint32_t sz = alignedSize(sizeof(macho_sub_umbrella_command

) + strlen(nm) + 1); + macho_sub_umbrella_command

* cmd = (macho_sub_umbrella_command

*)p; + cmd->set_cmd(LC_SUB_UMBRELLA); + cmd->set_cmdsize(sz); + cmd->set_sub_umbrella_offset(); + strcpy((char*)&p[sizeof(macho_sub_umbrella_command

)], nm); + return p + sz; +} + +template +uint8_t* HeaderAndLoadCommandsAtom::copySubLibraryLoadCommand(uint8_t* p, const char* nm) const +{ + uint32_t sz = alignedSize(sizeof(macho_sub_library_command

) + strlen(nm) + 1); + macho_sub_library_command

* cmd = (macho_sub_library_command

*)p; + cmd->set_cmd(LC_SUB_LIBRARY); + cmd->set_cmdsize(sz); + cmd->set_sub_library_offset(); + strcpy((char*)&p[sizeof(macho_sub_library_command

)], nm); + return p + sz; +} + +template +uint8_t* HeaderAndLoadCommandsAtom::copyFunctionStartsLoadCommand(uint8_t* p) const +{ + macho_linkedit_data_command

* cmd = (macho_linkedit_data_command

*)p; + cmd->set_cmd(LC_FUNCTION_STARTS); + cmd->set_cmdsize(sizeof(macho_linkedit_data_command

)); + cmd->set_dataoff(_writer.functionStartsSection->fileOffset); + cmd->set_datasize(_writer.functionStartsSection->size); + return p + sizeof(macho_linkedit_data_command

); +} + + +template +void HeaderAndLoadCommandsAtom::copyRawContent(uint8_t buffer[]) const +{ + macho_header

* mh = (macho_header

*)buffer; + bzero(buffer, this->size()); + + // copy mach_header + mh->set_magic(this->magic()); + mh->set_cputype(this->cpuType()); + mh->set_cpusubtype(this->cpuSubType()); + mh->set_filetype(this->fileType()); + mh->set_ncmds(this->commandsCount()); + mh->set_sizeofcmds(this->size()-sizeof(macho_header

)); + mh->set_flags(this->flags()); + + // copy load commands + uint8_t* p = &buffer[sizeof(macho_header

)]; + + if ( _options.outputKind() == Options::kObjectFile ) + p = this->copySingleSegmentLoadCommand(p); + else + p = this->copySegmentLoadCommands(p); + + if ( _hasDylibIDLoadCommand ) + p = this->copyDylibIDLoadCommand(p); + + if ( _hasDyldInfoLoadCommand ) + p = this->copyDyldInfoLoadCommand(p); + + if ( _hasSymbolTableLoadCommand ) + p = this->copySymbolTableLoadCommand(p); + + if ( _hasDynamicSymbolTableLoadCommand ) + p = this->copyDynamicSymbolTableLoadCommand(p); + + if ( _hasDyldLoadCommand ) + p = this->copyDyldLoadCommand(p); + + if ( _hasRoutinesLoadCommand ) + p = this->copyRoutinesLoadCommand(p); + + if ( _hasUUIDLoadCommand ) + p = this->copyUUIDLoadCommand(p); + + if ( _hasVersionLoadCommand ) + p = this->copyVersionLoadCommand(p); + + if ( _hasThreadLoadCommand ) + p = this->copyThreadsLoadCommand(p); + + if ( _hasEncryptionLoadCommand ) + p = this->copyEncryptionLoadCommand(p); + + if ( _hasSplitSegInfoLoadCommand ) + p = this->copySplitSegInfoLoadCommand(p); + + for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) { + p = this->copyDylibLoadCommand(p, _writer.dylibByOrdinal(ord)); + } + + if ( _hasRPathLoadCommands ) { + const std::vector& rpaths = _options.rpaths(); + for (std::vector::const_iterator it = rpaths.begin(); it != rpaths.end(); ++it) { + p = this->copyRPathLoadCommand(p, *it); + } + } + + if ( _hasSubFrameworkLoadCommand ) + p = this->copySubFrameworkLoadCommand(p); + + for (std::vector::const_iterator it = _subLibraryNames.begin(); it != _subLibraryNames.end(); ++it) { + p = this->copySubLibraryLoadCommand(p, *it); + } + + for (std::vector::const_iterator it = _subUmbrellaNames.begin(); it != _subUmbrellaNames.end(); ++it) { + p = this->copySubUmbrellaLoadCommand(p, *it); + } + + if ( _allowableClientLoadCommmandsCount != 0 ) { + const std::vector& clients = _options.allowableClients(); + for (std::vector::const_iterator it = clients.begin(); it != clients.end(); ++it) { + p = this->copyAllowableClientLoadCommand(p, *it); + } + } + + if ( _dyldEnvironExrasCount != 0 ) { + const std::vector& extras = _options.dyldEnvironExtras(); + for (std::vector::const_iterator it = extras.begin(); it != extras.end(); ++it) { + p = this->copyDyldEnvLoadCommand(p, *it); + } + } + + if ( _hasFunctionStartsLoadCommand ) + p = this->copyFunctionStartsLoadCommand(p); + +} + + + +} // namespace tool +} // namespace ld + +#endif // __HEADER_LOAD_COMMANDS_HPP__