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>
// 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 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;
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;
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;
bool _hasFunctionStartsLoadCommand;
bool _hasDataInCodeLoadCommand;
bool _hasSourceVersionLoadCommand;
- bool _hasDependentDRInfo;
+ bool _hasOptimizationHints;
+ bool _simulatorSupportDylib;
+ ld::VersionSet _platforms;
uint32_t _dylibLoadCommmandsCount;
uint32_t _allowableClientLoadCommmandsCount;
uint32_t _dyldEnvironExrasCount;
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;
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();
_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:
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();
}
_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) {
return count;
}
+template <typename A>
+bool HeaderAndLoadCommandsAtom<A>::bitcodeBundleCommand(uint64_t &cmdOffset, uint64_t &cmdEnd,
+ uint64_t §Offset, uint64_t §End) 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
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>);
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;
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;
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;
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() ) {
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;
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 <>
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 <>
return _state.cpuSubType;
}
+template <>
+uint32_t HeaderAndLoadCommandsAtom<arm64>::cpuSubType() const
+{
+ return _state.cpuSubType;
+}
+
template <typename A>
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;
}
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;
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))
{
}
return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
else if ( (strncmp(sect->sectionName(), "__objc_nlclslist", 16) == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
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:
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;
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;
return S_REGULAR;
case ld::Section::typeDebug:
return S_REGULAR | S_ATTR_DEBUG;
+ case ld::Section::typeSectCreate:
+ return S_REGULAR;
}
return S_REGULAR;
}
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;
}
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
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) {
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);
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
{
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 <>
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
}
+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
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);
{
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);
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
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);
p = this->copyDyldInfoLoadCommand(p);
if ( _hasSymbolTableLoadCommand )
- p = this->copySymbolTableLoadCommand(p);
+ p = this->copySymbolTableLoadCommand(p, buffer);
if ( _hasDynamicSymbolTableLoadCommand )
p = this->copyDynamicSymbolTableLoadCommand(p);
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);
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));
}
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);
}