]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/HeaderAndLoadCommands.hpp
ld64-409.12.tar.gz
[apple/ld64.git] / src / ld / HeaderAndLoadCommands.hpp
index 088571530b81b9ec7f68ef075eba51c9a45f191b..e03c59c35c5a7fb53e46c92b4e2e7ebbc98f2b92 100644 (file)
@@ -49,6 +49,12 @@ public:
 
        virtual void setUUID(const uint8_t digest[16]) = 0;
        virtual void recopyUUIDCommand() = 0;
+       virtual const uint8_t* getUUID() const = 0;
+       virtual bool bitcodeBundleCommand(uint64_t& cmdOffset, uint64_t& cmdEnd,
+                                                                         uint64_t& sectOffset, uint64_t& sectEnd) const = 0;
+       virtual void linkeditCmdInfo(uint64_t& offset, uint64_t& size) const = 0;
+       virtual void symbolTableCmdInfo(uint64_t& offset, uint64_t& size) const = 0;
+
 };
 
 template <typename A>
@@ -63,12 +69,20 @@ public:
        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 bool                                                            lcBuildVersionDisabled() const;
+
        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();
-       
+       virtual const uint8_t* getUUID() const                          { return &_uuid[0]; }
+       virtual bool bitcodeBundleCommand(uint64_t& cmdOffset, uint64_t& cmdEnd,
+                                                                         uint64_t& sectOffset, uint64_t& sectEnd) const;
+       virtual void linkeditCmdInfo(uint64_t& offset, uint64_t& size) const;
+       virtual void symbolTableCmdInfo(uint64_t& offset, uint64_t& size) const;
+
+
 private:
        typedef typename A::P                                           P;
        typedef typename A::P::E                                        E;
@@ -85,15 +99,16 @@ private:
        uint32_t                                        commandsCount() const;
        uint32_t                                        threadLoadCommandSize() const;
        uint8_t*                                        copySingleSegmentLoadCommand(uint8_t* p) const;
-       uint8_t*                                        copySegmentLoadCommands(uint8_t* p) const;
+       uint8_t*                                        copySegmentLoadCommands(uint8_t* p, uint8_t* base) const;
        uint8_t*                                        copyDyldInfoLoadCommand(uint8_t* p) const;
-       uint8_t*                                        copySymbolTableLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copySymbolTableLoadCommand(uint8_t* p, uint8_t* base) 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*                                        copyVersionLoadCommand(uint8_t* p, const ld::Platform& platform, uint32_t minVersion, uint32_t sdkVersion) const;
+       uint8_t*                                        copyBuildVersionLoadCommand(uint8_t* p, const ld::Platform& platform, uint32_t minVersion, uint32_t sdkVersion) const;
        uint8_t*                                        copySourceVersionLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyThreadsLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyEntryPointLoadCommand(uint8_t* p) const;
@@ -107,9 +122,10 @@ private:
        uint8_t*                                        copySubUmbrellaLoadCommand(uint8_t* p, const char* name) const;
        uint8_t*                                        copyFunctionStartsLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyDataInCodeLoadCommand(uint8_t* p) const;
-       uint8_t*                                        copyDependentDRLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyDyldEnvLoadCommand(uint8_t* p, const char* env) const;
-       
+       uint8_t*                                        copyLinkerOptionsLoadCommand(uint8_t* p, const std::vector<const char*>&) const;
+       uint8_t*                                        copyOptimizationHintsLoadCommand(uint8_t* p) const;
+
        uint32_t                                        sectionFlags(ld::Internal::FinalSection* sect) const;
        bool                                            sectionTakesNoDiskSpace(ld::Internal::FinalSection* sect) const;
        
@@ -135,7 +151,9 @@ private:
        bool                                            _hasFunctionStartsLoadCommand;
        bool                                            _hasDataInCodeLoadCommand;
        bool                                            _hasSourceVersionLoadCommand;
-       bool                                            _hasDependentDRInfo;
+       bool                                            _hasOptimizationHints;
+       bool                                            _simulatorSupportDylib;
+       ld::VersionSet                          _platforms;
        uint32_t                                        _dylibLoadCommmandsCount;
        uint32_t                                        _allowableClientLoadCommmandsCount;
        uint32_t                                        _dyldEnvironExrasCount;
@@ -143,6 +161,10 @@ private:
        std::vector<const char*>        _subUmbrellaNames;
        uint8_t                                         _uuid[16];
        mutable macho_uuid_command<P>*  _uuidCmdInOutputBuffer;
+       mutable uint32_t                        _linkeditCmdOffset;
+       mutable uint32_t                        _symboltableCmdOffset;
+       std::vector< std::vector<const char*> >  _linkerOptions;
+       std::unordered_set<uint64_t>&   _toolsVersions;
        
        static ld::Section                      _s_section;
        static ld::Section                      _s_preload_section;
@@ -160,8 +182,9 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
                                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)
+                               (opts.outputKind() == Options::kPreload) ? ld::Atom::Alignment(0) : ld::Atom::Alignment(log2(opts.segmentAlignment())) ),
+               _options(opts), _state(state), _writer(writer), _address(0), _uuidCmdInOutputBuffer(NULL), _linkeditCmdOffset(0), _symboltableCmdOffset(0),
+               _toolsVersions(state.toolsVersions)
 {
        bzero(_uuid, 16);
        _hasDyldInfoLoadCommand = opts.makeCompressedDyldInfo();
@@ -174,6 +197,7 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
        _hasRoutinesLoadCommand = (opts.initFunctionName() != NULL);
        _hasSymbolTableLoadCommand = true;
        _hasUUIDLoadCommand = (opts.UUIDMode() != Options::kUUIDNone);
+       _hasOptimizationHints = (_state.someObjectHasOptimizationHints && (opts.outputKind() == Options::kObjectFile));
        switch ( opts.outputKind() ) {
                case Options::kDynamicExecutable:
                case Options::kDynamicLibrary:
@@ -192,6 +216,20 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
                                        break;
                                }
                        }
+                       for (const char* frameworkName : _state.unprocessedLinkerOptionFrameworks) {
+                               std::vector<const char*>* lo = new std::vector<const char*>();
+                               lo->push_back("-framework");
+                               lo->push_back(frameworkName);
+                               _linkerOptions.push_back(*lo);
+                       };
+                       for (const char* libName : _state.unprocessedLinkerOptionLibraries) {
+                               std::vector<const char*>* lo = new std::vector<const char*>();
+                               char * s = new char[strlen(libName)+3];
+                               strcpy(s, "-l");
+                               strcat(s, libName);
+                               lo->push_back(s);
+                               _linkerOptions.push_back(*lo);
+                       };
                        break;
                case Options::kStaticExecutable:
                        _hasDynamicSymbolTableLoadCommand = opts.positionIndependentExecutable();
@@ -202,14 +240,31 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
        }
        _hasRPathLoadCommands = (_options.rpaths().size() != 0);
        _hasSubFrameworkLoadCommand = (_options.umbrellaName() != NULL);
+       _platforms = _options.platforms();
+       if ( _platforms.empty() && (!_state.derivedPlatforms.empty()) )
+               _platforms = _state.derivedPlatforms;
+       if (_platforms.contains(ld::kPlatform_macOS) &&
+               ((strcmp(_options.installPath(), "/usr/lib/system/libsystem_kernel.dylib") == 0)
+                || (strcmp(_options.installPath(), "/usr/lib/system/libsystem_platform.dylib") == 0)
+                || (strcmp(_options.installPath(), "/usr/lib/system/libsystem_pthread.dylib") == 0)
+                || (strcmp(_options.installPath(), "/usr/lib/system/libsystem_platform_debug.dylib") == 0)
+                || (strcmp(_options.installPath(), "/usr/lib/system/libsystem_pthread_debug.dylib") == 0)
+                || (strcmp(_options.installPath(), "/System/Library/PrivateFrameworks/SiriUI.framework/Versions/A/SiriUI") == 0))) {
+               _simulatorSupportDylib = true;
+       } else {
+               _simulatorSupportDylib = false;
+       }
        _hasVersionLoadCommand = _options.addVersionLoadCommand();
+       // in ld -r mode, only if all input .o files have load command, then add one to output
+       if ( !_hasVersionLoadCommand && (_options.outputKind() == Options::kObjectFile) && !state.objectFileFoundWithNoVersion )
+               _hasVersionLoadCommand = true;
        _hasFunctionStartsLoadCommand = _options.addFunctionStarts();
        _hasDataInCodeLoadCommand = _options.addDataInCodeInfo();
        _hasSourceVersionLoadCommand = _options.needsSourceVersionLoadCommand();
-       _hasDependentDRInfo = _options.needsDependentDRInfo();
        _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) {
@@ -304,6 +359,46 @@ unsigned int HeaderAndLoadCommandsAtom<A>::segmentCount() const
        return count;
 }
 
+template <typename A>
+bool HeaderAndLoadCommandsAtom<A>::bitcodeBundleCommand(uint64_t &cmdOffset, uint64_t &cmdEnd,
+                                                                                                               uint64_t &sectOffset, uint64_t &sectEnd) const
+{
+       if ( _options.outputKind() == Options::kObjectFile ) {
+               return false;
+       }
+       cmdOffset = sizeof(macho_header<P>);
+       const char* lastSegName = "";
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = _state.sections.begin(); it != _state.sections.end(); ++it) {
+               if ( strcmp(lastSegName, (*it)->segmentName()) != 0 ) {
+                       lastSegName = (*it)->segmentName();
+                       cmdOffset += sizeof(macho_segment_command<P>);
+               }
+               if ( strcmp((*it)->segmentName(), "__LLVM") == 0 && strcmp((*it)->sectionName(), "__bundle") == 0 ) {
+                       sectOffset = (*it)->fileOffset;
+                       sectEnd = (*(it + 1))->fileOffset;
+                       cmdEnd = cmdOffset + sizeof(macho_section<P>);
+                       return true;
+               }
+               if ( ! (*it)->isSectionHidden() )
+                       cmdOffset += sizeof(macho_section<P>);
+       }
+       return false;
+}
+
+template <typename A>
+void HeaderAndLoadCommandsAtom<A>::linkeditCmdInfo(uint64_t &offset, uint64_t &size) const
+{
+       offset = _linkeditCmdOffset;
+       size = sizeof(macho_segment_command<P>);
+}
+
+template <typename A>
+void HeaderAndLoadCommandsAtom<A>::symbolTableCmdInfo(uint64_t &offset, uint64_t &size) const
+{
+       offset = _symboltableCmdOffset;
+       size = sizeof(macho_symtab_command<P>);
+}
+
 
 template <typename A>
 uint64_t HeaderAndLoadCommandsAtom<A>::size() const
@@ -334,9 +429,22 @@ uint64_t HeaderAndLoadCommandsAtom<A>::size() const
        if ( _hasUUIDLoadCommand )
                sz += sizeof(macho_uuid_command<P>);
 
-       if ( _hasVersionLoadCommand )
-               sz += sizeof(macho_version_min_command<P>);
-       
+       if ( _hasVersionLoadCommand ) {
+               if (_simulatorSupportDylib) {
+#if 0
+//FIXME hack to workaround simulator issues without cctools changes
+                       sz += sizeof(macho_version_min_command<P>);
+                       sz += (_options.platforms().count() * alignedSize(sizeof(macho_build_version_command<P>) + sizeof(macho_build_tool_version<P>)*_toolsVersions.size()));
+#else
+                       sz += sizeof(macho_version_min_command<P>);
+#endif
+               } else if (_options.platforms().minOS(ld::supportsLCBuildVersion) && !lcBuildVersionDisabled()) {
+                       sz += (_options.platforms().count() * alignedSize(sizeof(macho_build_version_command<P>) + sizeof(macho_build_tool_version<P>)*_toolsVersions.size()));
+               } else {
+                       sz += sizeof(macho_version_min_command<P>);
+               }
+       }
+
        if ( _hasSourceVersionLoadCommand )
                sz += sizeof(macho_source_version_command<P>);
                
@@ -394,7 +502,18 @@ uint64_t HeaderAndLoadCommandsAtom<A>::size() const
        if ( _hasDataInCodeLoadCommand )
                sz += sizeof(macho_linkedit_data_command<P>);
 
-       if ( _hasDependentDRInfo ) 
+       if ( !_linkerOptions.empty() ) {
+               for (ld::relocatable::File::LinkerOptionsList::const_iterator it = _linkerOptions.begin(); it != _linkerOptions.end(); ++it) {
+                       uint32_t s = sizeof(macho_linker_option_command<P>);
+                       const std::vector<const char*>& options = *it;
+                       for (std::vector<const char*>::const_iterator t=options.begin(); t != options.end(); ++t) {
+                               s += (strlen(*t) + 1);
+                       }
+                       sz += alignedSize(s);
+               }
+       }
+       
+       if ( _hasOptimizationHints )
                sz += sizeof(macho_linkedit_data_command<P>);
                
        return sz;
@@ -425,9 +544,22 @@ uint32_t HeaderAndLoadCommandsAtom<A>::commandsCount() const
                
        if ( _hasUUIDLoadCommand )
                ++count;
-       
-       if ( _hasVersionLoadCommand )
-               ++count;
+
+       if ( _hasVersionLoadCommand ) {
+               if (_simulatorSupportDylib) {
+#if 0
+                       //FIXME hack to workaround simulator issues without cctools changes
+                       ++count;
+                       count += _options.platforms().count();
+#else
+                       ++count;
+#endif
+               } else if (_options.platforms().minOS(ld::supportsLCBuildVersion) && !lcBuildVersionDisabled()) {
+                       count += _options.platforms().count();
+               } else {
+                       ++count;
+               }
+       }
 
        if ( _hasSourceVersionLoadCommand )
                ++count;
@@ -465,7 +597,13 @@ uint32_t HeaderAndLoadCommandsAtom<A>::commandsCount() const
        if ( _hasDataInCodeLoadCommand )
                ++count;
 
-       if ( _hasDependentDRInfo ) 
+       if ( !_linkerOptions.empty() ) {
+               for (ld::relocatable::File::LinkerOptionsList::const_iterator it = _linkerOptions.begin(); it != _linkerOptions.end(); ++it) {
+                       ++count;
+               }
+       }
+
+       if ( _hasOptimizationHints )
                ++count;
                
        return count;
@@ -525,14 +663,10 @@ uint32_t HeaderAndLoadCommandsAtom<A>::flags() const
                                        bits |= MH_FORCE_FLAT;
                                        break;
                        }
-                       if ( _writer.hasWeakExternalSymbols || _writer.overridesWeakExternalSymbols )
+                       if ( _state.hasWeakExternalSymbols || _writer.overridesWeakExternalSymbols )
                                bits |= MH_WEAK_DEFINES;
-                       if ( _writer.usesWeakExternalSymbols || _writer.hasWeakExternalSymbols )
+                       if ( _writer.usesWeakExternalSymbols || _state.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() ) {
@@ -542,10 +676,17 @@ uint32_t HeaderAndLoadCommandsAtom<A>::flags() const
                                bits |= MH_PIE;
                        if ( _options.markAutoDeadStripDylib() ) 
                                bits |= MH_DEAD_STRIPPABLE_DYLIB;
-                       if ( _writer.hasThreadLocalVariableDefinitions )
+                       if ( _state.hasThreadLocalVariableDefinitions )
                                bits |= MH_HAS_TLV_DESCRIPTORS;
                        if ( _options.hasNonExecutableHeap() )
                                bits |= MH_NO_HEAP_EXECUTION;
+                       if ( _options.markAppExtensionSafe() && (_options.outputKind() == Options::kDynamicLibrary) )
+                               bits |= MH_APP_EXTENSION_SAFE;
+#if 0
+                       //FIXME hack to workaround simulator issues without cctools changes
+                       if (_simulatorSupportDylib)
+                               bits |= MH_SIM_SUPPORT;
+#endif
                }
                if ( _options.hasExecutableStack() )
                        bits |= MH_ALLOW_STACK_EXECUTION;
@@ -556,11 +697,12 @@ uint32_t HeaderAndLoadCommandsAtom<A>::flags() const
 template <> uint32_t HeaderAndLoadCommandsAtom<x86>::magic() const             { return MH_MAGIC; }
 template <> uint32_t HeaderAndLoadCommandsAtom<x86_64>::magic() const  { return MH_MAGIC_64; }
 template <> uint32_t HeaderAndLoadCommandsAtom<arm>::magic() const             { return MH_MAGIC; }
+template <> uint32_t HeaderAndLoadCommandsAtom<arm64>::magic() const           { return MH_MAGIC_64; }
 
 template <> uint32_t HeaderAndLoadCommandsAtom<x86>::cpuType() const   { return CPU_TYPE_I386; }
 template <> uint32_t HeaderAndLoadCommandsAtom<x86_64>::cpuType() const        { return CPU_TYPE_X86_64; }
 template <> uint32_t HeaderAndLoadCommandsAtom<arm>::cpuType() const   { return CPU_TYPE_ARM; }
-
+template <> uint32_t HeaderAndLoadCommandsAtom<arm64>::cpuType() const { return CPU_TYPE_ARM64; }
 
 
 template <>
@@ -572,10 +714,10 @@ uint32_t HeaderAndLoadCommandsAtom<x86>::cpuSubType() const
 template <>
 uint32_t HeaderAndLoadCommandsAtom<x86_64>::cpuSubType() const
 {
-       if ( (_options.outputKind() == Options::kDynamicExecutable) && (_options.macosxVersionMin() >= ld::mac10_5) )
-               return (CPU_SUBTYPE_X86_64_ALL | 0x80000000);
+       if ( (_options.outputKind() == Options::kDynamicExecutable) && (_state.cpuSubType == CPU_SUBTYPE_X86_64_ALL) && _options.platforms().minOS(ld::mac10_5) )
+               return (_state.cpuSubType | 0x80000000);
        else
-               return CPU_SUBTYPE_X86_64_ALL;
+               return _state.cpuSubType;
 }
 
 template <>
@@ -584,6 +726,12 @@ uint32_t HeaderAndLoadCommandsAtom<arm>::cpuSubType() const
        return _state.cpuSubType;
 }
 
+template <>
+uint32_t HeaderAndLoadCommandsAtom<arm64>::cpuSubType() const
+{
+       return _state.cpuSubType;
+}
+
 
 
 template <typename A>
@@ -625,7 +773,7 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copySingleSegmentLoadCommand(uint8_t* p)
                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) )
+               if ( !sectionTakesNoDiskSpace(fsect) )
                        cmd->set_filesize(fsect->fileOffset + fsect->size - cmd->fileoff());
                ++msect;
        }
@@ -637,6 +785,7 @@ struct SegInfo {
                                                                                                SegInfo(const char* n, const Options&);
        const char*                                                                     segName;
        uint32_t                                                                        nonHiddenSectionCount;
+       uint32_t                                                                        nonSectCreateSections;
        uint32_t                                                                        maxProt;
        uint32_t                                                                        initProt;
        std::vector<ld::Internal::FinalSection*>        sections;
@@ -644,7 +793,7 @@ struct SegInfo {
 
 
 SegInfo::SegInfo(const char* n, const Options& opts) 
-       : segName(n), nonHiddenSectionCount(0), maxProt(opts.maxSegProtection(n)), initProt(opts.initialSegProtection(n)) 
+       : segName(n), nonHiddenSectionCount(0), nonSectCreateSections(0), maxProt(opts.maxSegProtection(n)), initProt(opts.initialSegProtection(n))
 { 
 }
 
@@ -667,6 +816,8 @@ uint32_t HeaderAndLoadCommandsAtom<A>::sectionFlags(ld::Internal::FinalSection*
                                return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
                        else if ( (strncmp(sect->sectionName(), "__objc_nlcatlist", 16) == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
                                return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+                       else if (  (_options.outputKind() == Options::kObjectFile) && !sect->atoms.empty() && sect->atoms.front()->dontDeadStripIfReferencesLive() )
+                               return S_REGULAR | S_ATTR_LIVE_SUPPORT;
                        else
                                return S_REGULAR;
                case ld::Section::typeCode:
@@ -697,6 +848,9 @@ uint32_t HeaderAndLoadCommandsAtom<A>::sectionFlags(ld::Internal::FinalSection*
                case ld::Section::typeTempLTO:
                        assert(0 && "typeTempLTO should not make it to final linked image");
                        return S_REGULAR;
+               case ld::Section::typeTempAlias:
+                       assert(0 && "typeAlias 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;
@@ -719,6 +873,8 @@ uint32_t HeaderAndLoadCommandsAtom<A>::sectionFlags(ld::Internal::FinalSection*
                        return S_DTRACE_DOF;
                case ld::Section::typeUnwindInfo:
                        return S_REGULAR;
+               case ld::Section::typeThreadStarts:
+                       return S_REGULAR;
                case ld::Section::typeObjCClassRefs:
                case ld::Section::typeObjC2CategoryList:
                        return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
@@ -783,6 +939,8 @@ uint32_t HeaderAndLoadCommandsAtom<A>::sectionFlags(ld::Internal::FinalSection*
                        return S_REGULAR;
                case ld::Section::typeDebug:
                        return S_REGULAR | S_ATTR_DEBUG;
+               case ld::Section::typeSectCreate:
+                       return S_REGULAR;
        }
        return S_REGULAR;
 }
@@ -807,7 +965,7 @@ bool HeaderAndLoadCommandsAtom<A>::sectionTakesNoDiskSpace(ld::Internal::FinalSe
 
 
 template <typename A>
-uint8_t* HeaderAndLoadCommandsAtom<A>::copySegmentLoadCommands(uint8_t* p) const
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySegmentLoadCommands(uint8_t* p, uint8_t* base) const
 {
        // group sections into segments
        std::vector<SegInfo> segs;
@@ -827,6 +985,9 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copySegmentLoadCommands(uint8_t* p) const
                }
                if ( ! sect->isSectionHidden() ) 
                        segs.back().nonHiddenSectionCount++;
+               if ( sect->type() != ld::Section::typeSectCreate )
+                       segs.back().nonSectCreateSections++;
+
                segs.back().sections.push_back(sect);
        }
        // write out segment load commands for each section with trailing sections
@@ -863,7 +1024,9 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copySegmentLoadCommands(uint8_t* p) const
                segCmd->set_maxprot(si.maxProt);
                segCmd->set_initprot(si.initProt);
                segCmd->set_nsects(si.nonHiddenSectionCount);
-               segCmd->set_flags(0);
+               segCmd->set_flags(si.nonSectCreateSections ? 0 : SG_NORELOC); // FIXME, really should check all References
+               if ( strcmp(segCmd->segname(), "__LINKEDIT") == 0 )
+                       _linkeditCmdOffset = p - base;
                p += sizeof(macho_segment_command<P>);
                macho_section<P>* msect = (macho_section<P>*)p;
                for (std::vector<ld::Internal::FinalSection*>::iterator sit = si.sections.begin(); sit != si.sections.end(); ++sit) {
@@ -891,8 +1054,9 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copySegmentLoadCommands(uint8_t* p) const
 
 
 template <typename A>
-uint8_t* HeaderAndLoadCommandsAtom<A>::copySymbolTableLoadCommand(uint8_t* p) const
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySymbolTableLoadCommand(uint8_t* p, uint8_t* base) const
 {
+       _symboltableCmdOffset = p - base;
        // build LC_SYMTAB command
        macho_symtab_command<P>*   symbolTableCmd = (macho_symtab_command<P>*)p;
        symbolTableCmd->set_cmd(LC_SYMTAB);
@@ -1043,27 +1207,74 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copyUUIDLoadCommand(uint8_t* p) const
 
 
 template <typename A>
-uint8_t* HeaderAndLoadCommandsAtom<A>::copyVersionLoadCommand(uint8_t* p) const
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyVersionLoadCommand(uint8_t* p, const ld::Platform& platform, uint32_t minVersion, uint32_t sdkVersion) const
 {
        macho_version_min_command<P>* cmd = (macho_version_min_command<P>*)p;
-       ld::MacVersionMin macVersion = _options.macosxVersionMin();
-       ld::IOSVersionMin iOSVersion = _options.iOSVersionMin();
-       assert( (macVersion != ld::macVersionUnset) || (iOSVersion != ld::iOSVersionUnset) );
-       if ( macVersion != ld::macVersionUnset ) {
-               cmd->set_cmd(LC_VERSION_MIN_MACOSX);
-               cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
-               cmd->set_version((uint32_t)macVersion);
-               cmd->set_sdk(_options.sdkVersion());
-       }
-       else {
-               cmd->set_cmd(LC_VERSION_MIN_IPHONEOS);
-               cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
-               cmd->set_version((uint32_t)iOSVersion);
-               cmd->set_sdk(_options.sdkVersion());
+       switch (platform) {
+               case ld::kPlatform_macOS:
+                       cmd->set_cmd(LC_VERSION_MIN_MACOSX);
+                       cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
+                       cmd->set_version(minVersion);
+                       cmd->set_sdk(sdkVersion);
+                       break;
+               case ld::kPlatform_iOS:
+               case ld::kPlatform_iOSSimulator:
+                       cmd->set_cmd(LC_VERSION_MIN_IPHONEOS);
+                       cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
+                       cmd->set_version(minVersion);
+                       cmd->set_sdk(sdkVersion);
+                       break;
+               case ld::kPlatform_watchOS:
+               case ld::kPlatform_watchOSSimulator:
+                       cmd->set_cmd(LC_VERSION_MIN_WATCHOS);
+                       cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
+                       cmd->set_version(minVersion);
+                       cmd->set_sdk(sdkVersion);
+                       break;
+               case ld::kPlatform_tvOS:
+               case ld::kPlatform_tvOSSimulator:
+                       cmd->set_cmd(LC_VERSION_MIN_TVOS);
+                       cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
+                       cmd->set_version(minVersion);
+                       cmd->set_sdk(sdkVersion);
+                       break;
+               case ld::kPlatform_unknown:
+                       assert(0 && "unknown platform");
+                       break;
+               case ld::kPlatform_iOSMac:
+                       assert(0 && "iOSMac uses LC_BUILD_VERSION");
+                       break;
+               case ld::kPlatform_bridgeOS:
+                       assert(0 && "bridgeOS uses LC_BUILD_VERSION");
+                       break;
        }
        return p + sizeof(macho_version_min_command<P>);
 }
 
+
+
+template <typename A>
+       uint8_t* HeaderAndLoadCommandsAtom<A>::copyBuildVersionLoadCommand(uint8_t* p, const ld::Platform& platform, uint32_t minVersion, uint32_t sdkVersion) const
+{
+       macho_build_version_command<P>* cmd = (macho_build_version_command<P>*)p;
+       
+       cmd->set_cmd(LC_BUILD_VERSION);
+       cmd->set_cmdsize(alignedSize(sizeof(macho_build_version_command<P>) + sizeof(macho_build_tool_version<P>)*_toolsVersions.size()));
+       cmd->set_platform(platform);
+       cmd->set_minos(minVersion);
+       cmd->set_sdk(sdkVersion);
+       cmd->set_ntools(_toolsVersions.size());
+       macho_build_tool_version<P>* tools = (macho_build_tool_version<P>*)(p + sizeof(macho_build_version_command<P>));
+       for (uint64_t tool : _toolsVersions) {
+               tools->set_tool((uint64_t)tool >> 32);
+               tools->set_version(tool & 0xFFFFFFFF);
+               ++tools;
+       }
+
+       return p + cmd->cmdsize();
+}
+
+
 template <typename A>
 uint8_t* HeaderAndLoadCommandsAtom<A>::copySourceVersionLoadCommand(uint8_t* p) const
 {
@@ -1100,7 +1311,7 @@ uint8_t* HeaderAndLoadCommandsAtom<x86>::copyThreadsLoadCommand(uint8_t* p) cons
 template <>
 uint32_t HeaderAndLoadCommandsAtom<x86_64>::threadLoadCommandSize() const
 {
-       return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4); 
+       return this->alignedSize(16 + 42*4);    // base size + x86_THREAD_STATE64_COUNT * 4
 }
 
 template <>
@@ -1111,8 +1322,8 @@ uint8_t* HeaderAndLoadCommandsAtom<x86_64>::copyThreadsLoadCommand(uint8_t* p) c
        macho_thread_command<P>* cmd = (macho_thread_command<P>*)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_flavor(4);                             // x86_THREAD_STATE64
+       cmd->set_count(42);                             // x86_THREAD_STATE64_COUNT
        cmd->set_thread_register(16, start);            // rip 
        if ( _options.hasCustomStack() )
                cmd->set_thread_register(7, _options.customStackAddr());        // r1
@@ -1144,6 +1355,28 @@ uint8_t* HeaderAndLoadCommandsAtom<arm>::copyThreadsLoadCommand(uint8_t* p) cons
 }
 
 
+template <>
+uint32_t HeaderAndLoadCommandsAtom<arm64>::threadLoadCommandSize() const
+{
+       return this->alignedSize(16 + 34 * 8); // base size + ARM_EXCEPTION_STATE64_COUNT * 4
+}
+
+template <>
+uint8_t* HeaderAndLoadCommandsAtom<arm64>::copyThreadsLoadCommand(uint8_t* p) const
+{
+       assert(_state.entryPoint != NULL);
+       pint_t start = _state.entryPoint->finalAddress(); 
+       macho_thread_command<P>* cmd = (macho_thread_command<P>*)p;
+       cmd->set_cmd(LC_UNIXTHREAD);
+       cmd->set_cmdsize(threadLoadCommandSize());
+       cmd->set_flavor(6);      // ARM_THREAD_STATE64
+       cmd->set_count(68);      // ARM_EXCEPTION_STATE64_COUNT
+       cmd->set_thread_register(32, start);            // pc 
+       if ( _options.hasCustomStack() )
+               cmd->set_thread_register(31, _options.customStackAddr());       // sp 
+       return p + threadLoadCommandSize();
+}
+
 
 template <typename A>
 uint8_t* HeaderAndLoadCommandsAtom<A>::copyEntryPointLoadCommand(uint8_t* p) const
@@ -1165,7 +1398,7 @@ template <typename A>
 uint8_t* HeaderAndLoadCommandsAtom<A>::copyEncryptionLoadCommand(uint8_t* p) const
 {
        macho_encryption_info_command<P>* cmd = (macho_encryption_info_command<P>*)p;
-       cmd->set_cmd(LC_ENCRYPTION_INFO);
+       cmd->set_cmd(sizeof(typename A::P::uint_t) == 4 ? LC_ENCRYPTION_INFO : LC_ENCRYPTION_INFO_64);
        cmd->set_cmdsize(sizeof(macho_encryption_info_command<P>));
        assert(_writer.encryptedTextStartOffset() != 0);
        assert(_writer.encryptedTextEndOffset() != 0);
@@ -1193,14 +1426,21 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copyDylibLoadCommand(uint8_t* p, const ld
 {
        uint32_t sz = alignedSize(sizeof(macho_dylib_command<P>) + strlen(dylib->installPath()) + 1);
        macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)p;
+       bool weakLink = dylib->forcedWeakLinked() || dylib->allSymbolsAreWeakImported();
+       bool upward = dylib->willBeUpwardDylib() && _options.useUpwardDylibs();
+       bool reExport = dylib->willBeReExported() && _options.useSimplifiedDylibReExports();
+       if ( weakLink && upward )
+               warning("cannot weak upward link.  Dropping weak for %s", dylib->installPath());
+       if ( weakLink && reExport )
+               warning("cannot weak re-export a dylib.  Dropping weak for %s", dylib->installPath());
        if ( dylib->willBeLazyLoadedDylib() )
                cmd->set_cmd(LC_LAZY_LOAD_DYLIB);
-       else if ( dylib->forcedWeakLinked() || dylib->allSymbolsAreWeakImported() )
-               cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
-       else if ( dylib->willBeReExported() && _options.useSimplifiedDylibReExports() )
+       else if ( reExport )
                cmd->set_cmd(LC_REEXPORT_DYLIB);
-       else if ( dylib->willBeUpwardDylib() && _options.useUpwardDylibs() )
+       else if ( upward )
                cmd->set_cmd(LC_LOAD_UPWARD_DYLIB);
+       else if ( weakLink )
+               cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
        else
                cmd->set_cmd(LC_LOAD_DYLIB);
        cmd->set_cmdsize(sz);
@@ -1311,16 +1551,49 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copyDataInCodeLoadCommand(uint8_t* p) con
 
 
 template <typename A>
-uint8_t* HeaderAndLoadCommandsAtom<A>::copyDependentDRLoadCommand(uint8_t* p) const
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyLinkerOptionsLoadCommand(uint8_t* p, const std::vector<const char*>& options) const
+{
+       macho_linker_option_command<P>* cmd = (macho_linker_option_command<P>*)p;
+       cmd->set_cmd(LC_LINKER_OPTION);
+       cmd->set_count(options.size());
+       char* buffer = cmd->buffer();
+       uint32_t sz = sizeof(macho_linker_option_command<P>);
+       for (std::vector<const char*>::const_iterator it=options.begin(); it != options.end(); ++it) {
+               const char* opt = *it;
+               uint32_t len = strlen(opt);
+               strcpy(buffer, opt);
+               sz += (len + 1);
+               buffer += (len + 1);
+       }
+       sz = alignedSize(sz);
+       cmd->set_cmdsize(sz);   
+       return p + sz;
+}
+
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyOptimizationHintsLoadCommand(uint8_t* p) const
 {
        macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)p;
-       cmd->set_cmd(LC_DYLIB_CODE_SIGN_DRS);
+       cmd->set_cmd(LC_LINKER_OPTIMIZATION_HINTS);
        cmd->set_cmdsize(sizeof(macho_linkedit_data_command<P>));
-       cmd->set_dataoff(_writer.dependentDRsSection->fileOffset);
-       cmd->set_datasize(_writer.dependentDRsSection->size);
+       cmd->set_dataoff(_writer.optimizationHintsSection->fileOffset);
+       cmd->set_datasize(_writer.optimizationHintsSection->size);
        return p + sizeof(macho_linkedit_data_command<P>);
 }
 
+template <typename A>
+bool HeaderAndLoadCommandsAtom<A>::lcBuildVersionDisabled() const {
+       static std::once_flag envChecked;
+       static bool disabled = false;
+       std::call_once(envChecked, [&](){
+               if (getenv("LD_FORCE_LEGACY_VERSION_LOAD_CMDS") != nullptr ) {
+                       disabled = true;
+               }
+       });
+       return disabled;
+}
 
 template <typename A>
 void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
@@ -1338,12 +1611,12 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
        mh->set_flags(this->flags());
 
        // copy load commands
-       uint8_t* p = &buffer[sizeof(macho_header<P>)];
+       __block uint8_t* p = &buffer[sizeof(macho_header<P>)];
        
        if ( _options.outputKind() == Options::kObjectFile )
                p = this->copySingleSegmentLoadCommand(p);
        else
-               p = this->copySegmentLoadCommands(p);
+               p = this->copySegmentLoadCommands(p, buffer);
        
        if ( _hasDylibIDLoadCommand )
                p = this->copyDylibIDLoadCommand(p);
@@ -1352,7 +1625,7 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
                p = this->copyDyldInfoLoadCommand(p);
                
        if ( _hasSymbolTableLoadCommand )
-               p = this->copySymbolTableLoadCommand(p);
+               p = this->copySymbolTableLoadCommand(p, buffer);
 
        if ( _hasDynamicSymbolTableLoadCommand )
                p = this->copyDynamicSymbolTableLoadCommand(p);
@@ -1365,9 +1638,33 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
                
        if ( _hasUUIDLoadCommand )
                p = this->copyUUIDLoadCommand(p);
-       
-       if ( _hasVersionLoadCommand )
-               p = this->copyVersionLoadCommand(p);
+
+       if ( _hasVersionLoadCommand ) {
+               if (_simulatorSupportDylib) {
+#if 0
+                       //FIXME hack to workaround simulator issues without cctools changes
+                       p = this->copyVersionLoadCommand(p, ld::kPlatform_macOS, 0, _options.sdkVersion());
+                       _options.platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                               p = this->copyBuildVersionLoadCommand(p, platform, version, _options.sdkVersion());
+                       });
+#else
+                       _options.platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                               if (platform == ld::kPlatform_macOS) {
+                                       p = this->copyVersionLoadCommand(p, platform, version, _options.sdkVersion());
+                               }
+                       });
+#endif
+               } else if (_options.platforms().minOS(ld::supportsLCBuildVersion) && !lcBuildVersionDisabled()) {
+                       _options.platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                               p = this->copyBuildVersionLoadCommand(p, platform, version, _options.sdkVersion());
+                       });
+               } else {
+                       assert(_platforms.count() == 1 && "LC_BUILD_VERSION required when there are multiple platforms");
+                       _options.platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                               p = this->copyVersionLoadCommand(p, platform, version, _options.sdkVersion());
+                       });
+               }
+       }
 
        if ( _hasSourceVersionLoadCommand )
                p = this->copySourceVersionLoadCommand(p);
@@ -1384,7 +1681,7 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
        if ( _hasSplitSegInfoLoadCommand )
                p = this->copySplitSegInfoLoadCommand(p);
                
-       for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
+       for (uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
                p = this->copyDylibLoadCommand(p, _writer.dylibByOrdinal(ord));
        }
 
@@ -1425,9 +1722,15 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
 
        if ( _hasDataInCodeLoadCommand )
                p = this->copyDataInCodeLoadCommand(p);
+
+       if ( !_linkerOptions.empty() ) {
+               for (ld::relocatable::File::LinkerOptionsList::const_iterator it = _linkerOptions.begin(); it != _linkerOptions.end(); ++it) {
+                       p = this->copyLinkerOptionsLoadCommand(p, *it);
+               }
+       }
        
-       if ( _hasDependentDRInfo ) 
-               p = this->copyDependentDRLoadCommand(p);
+       if ( _hasOptimizationHints )
+               p = this->copyOptimizationHintsLoadCommand(p);
  
 }