diff options
-rw-r--r-- | lld/include/lld/ReaderWriter/MachOLinkingContext.h | 9 | ||||
-rw-r--r-- | lld/lib/Driver/DarwinLdDriver.cpp | 50 | ||||
-rw-r--r-- | lld/lib/Driver/DarwinLdOptions.td | 4 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/MachO/MachONormalizedFile.h | 1 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp | 48 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp | 9 | ||||
-rw-r--r-- | lld/test/mach-o/version-min-load-command.yaml | 32 |
7 files changed, 151 insertions, 2 deletions
diff --git a/lld/include/lld/ReaderWriter/MachOLinkingContext.h b/lld/include/lld/ReaderWriter/MachOLinkingContext.h index ec413b13894..976c2754fd2 100644 --- a/lld/include/lld/ReaderWriter/MachOLinkingContext.h +++ b/lld/include/lld/ReaderWriter/MachOLinkingContext.h @@ -149,6 +149,12 @@ public: const StringRefVector &sysLibRoots() const { return _syslibRoots; } bool PIE() const { return _pie; } void setPIE(bool pie) { _pie = pie; } + bool generateVersionLoadCommand() const { + return _generateVersionLoadCommand; + } + void setGenerateVersionLoadCommand(bool v) { + _generateVersionLoadCommand = v; + } uint64_t stackSize() const { return _stackSize; } void setStackSize(uint64_t stackSize) { _stackSize = stackSize; } @@ -158,6 +164,8 @@ public: ObjCConstraint objcConstraint() const { return _objcConstraint; } + uint32_t osMinVersion() const { return _osMinVersion; } + uint32_t swiftVersion() const { return _swiftVersion; } /// \brief Checks whether a given path on the filesystem exists. @@ -430,6 +438,7 @@ private: bool _keepPrivateExterns; bool _demangle; bool _mergeObjCCategories = true; + bool _generateVersionLoadCommand = false; StringRef _bundleLoader; mutable std::unique_ptr<mach_o::ArchHandler> _archHandler; mutable std::unique_ptr<Writer> _writer; diff --git a/lld/lib/Driver/DarwinLdDriver.cpp b/lld/lib/Driver/DarwinLdDriver.cpp index de40d2a23d6..f883ac6a8fe 100644 --- a/lld/lib/Driver/DarwinLdDriver.cpp +++ b/lld/lib/Driver/DarwinLdDriver.cpp @@ -299,6 +299,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static ) llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE; + bool isStaticExecutable = false; if (llvm::opt::Arg *kind = parsedArgs.getLastArg( OPT_dylib, OPT_relocatable, OPT_bundle, OPT_static, OPT_preload)) { switch (kind->getOption().getID()) { @@ -313,6 +314,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, break; case OPT_static: fileType = llvm::MachO::MH_EXECUTE; + isStaticExecutable = true; break; case OPT_preload: fileType = llvm::MachO::MH_PRELOAD; @@ -742,6 +744,54 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, } } + // Handle -version_load_command or -no_version_load_command + { + bool flagOn = false; + bool flagOff = false; + if (auto *arg = parsedArgs.getLastArg(OPT_version_load_command, + OPT_no_version_load_command)) { + flagOn = arg->getOption().getID() == OPT_version_load_command; + flagOff = arg->getOption().getID() == OPT_no_version_load_command; + } + + // default to adding version load command for dynamic code, + // static code must opt-in + switch (ctx.outputMachOType()) { + case llvm::MachO::MH_OBJECT: + ctx.setGenerateVersionLoadCommand(false); + break; + case llvm::MachO::MH_EXECUTE: + // dynamic executables default to generating a version load command, + // while static exectuables only generate it if required. + if (isStaticExecutable) { + if (flagOn) + ctx.setGenerateVersionLoadCommand(true); + } else { + if (!flagOff) + ctx.setGenerateVersionLoadCommand(true); + } + break; + case llvm::MachO::MH_PRELOAD: + case llvm::MachO::MH_KEXT_BUNDLE: + if (flagOn) + ctx.setGenerateVersionLoadCommand(true); + break; + case llvm::MachO::MH_DYLINKER: + case llvm::MachO::MH_DYLIB: + case llvm::MachO::MH_BUNDLE: + if (!flagOff) + ctx.setGenerateVersionLoadCommand(true); + break; + case llvm::MachO::MH_FVMLIB: + case llvm::MachO::MH_DYLDLINK: + case llvm::MachO::MH_DYLIB_STUB: + case llvm::MachO::MH_DSYM: + // We don't generate load commands for these file types, even if + // forced on. + break; + } + } + // Handle stack_size if (llvm::opt::Arg *stackSize = parsedArgs.getLastArg(OPT_stack_size)) { uint64_t stackSizeVal; diff --git a/lld/lib/Driver/DarwinLdOptions.td b/lld/lib/Driver/DarwinLdOptions.td index 2045293b308..dd37cbba2bc 100644 --- a/lld/lib/Driver/DarwinLdOptions.td +++ b/lld/lib/Driver/DarwinLdOptions.td @@ -33,6 +33,10 @@ def iphoneos_version_min : Separate<["-"], "iphoneos_version_min">, def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">, MetaVarName<"<version>">, HelpText<"Minimum iOS simulator version">, Group<grp_opts>; +def version_load_command : Flag<["-"], "version_load_command">, + HelpText<"Force generation of a version load command">, Group<grp_opts>; +def no_version_load_command : Flag<["-"], "no_version_load_command">, + HelpText<"Disable generation of a version load command">, Group<grp_opts>; def mllvm : Separate<["-"], "mllvm">, MetaVarName<"<option>">, HelpText<"Options to pass to LLVM during LTO">, Group<grp_opts>; diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h index cccf180f104..d2b4806565d 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h @@ -245,6 +245,7 @@ struct NormalizedFile { PackedVersion compatVersion = 0; // dylibs only PackedVersion currentVersion = 0; // dylibs only bool hasUUID = false; + bool hasMinVersionLoadCommand = false; std::vector<StringRef> rpaths; Hex64 entryAddress = 0; Hex64 stackSize = 0; diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp index 4fc989f031f..d46cf2ce386 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp @@ -450,10 +450,21 @@ uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) { ++count; } - // If main executable add LC_LOAD_DYLINKER and LC_MAIN + // If main executable add LC_LOAD_DYLINKER if (_file.fileType == llvm::MachO::MH_EXECUTE) { size += pointerAlign(sizeof(dylinker_command) + dyldPath().size()+1); ++count; + } + + // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS, + // LC_VERSION_MIN_TVOS + if (_file.hasMinVersionLoadCommand) { + size += sizeof(version_min_command); + ++count; + } + + // If main executable add LC_MAIN + if (_file.fileType == llvm::MachO::MH_EXECUTE) { size += sizeof(entry_point_command); ++count; } @@ -844,7 +855,7 @@ std::error_code MachOFileLayout::writeLoadCommands() { lc += sizeof(dysymtab_command); } - // If main executable, add LC_LOAD_DYLINKER and LC_MAIN. + // If main executable, add LC_LOAD_DYLINKER if (_file.fileType == llvm::MachO::MH_EXECUTE) { // Build LC_LOAD_DYLINKER load command. uint32_t size=pointerAlign(sizeof(dylinker_command)+dyldPath().size()+1); @@ -857,6 +868,39 @@ std::error_code MachOFileLayout::writeLoadCommands() { memcpy(lc+sizeof(dylinker_command), dyldPath().data(), dyldPath().size()); lc[sizeof(dylinker_command)+dyldPath().size()] = '\0'; lc += size; + } + + // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS, + // LC_VERSION_MIN_TVOS + if (_file.hasMinVersionLoadCommand) { + version_min_command *vm = reinterpret_cast<version_min_command*>(lc); + switch (_file.os) { + case MachOLinkingContext::OS::unknown: + // TODO: We need to emit the load command if we managed to derive + // a platform from one of the files we are linking. + llvm_unreachable("Version commands for unknown OS aren't supported"); + break; + case MachOLinkingContext::OS::macOSX: + vm->cmd = LC_VERSION_MIN_MACOSX; + vm->cmdsize = sizeof(version_min_command); + vm->version = _file.minOSverson; + vm->sdk = _file.sdkVersion; + break; + case MachOLinkingContext::OS::iOS: + case MachOLinkingContext::OS::iOS_simulator: + vm->cmd = LC_VERSION_MIN_MACOSX; + vm->cmdsize = sizeof(version_min_command); + vm->version = _file.minOSverson; + vm->sdk = _file.sdkVersion; + break; + } + if (_swap) + swapStruct(*vm); + lc += sizeof(version_min_command); + } + + // If main executable, add LC_MAIN. + if (_file.fileType == llvm::MachO::MH_EXECUTE) { // Build LC_MAIN load command. entry_point_command* ep = reinterpret_cast<entry_point_command*>(lc); ep->cmd = LC_MAIN; diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp index ea15c3e101e..c09634d115e 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp @@ -1244,6 +1244,15 @@ normalizedFromAtoms(const lld::File &atomFile, normFile.installName = context.installName(); normFile.currentVersion = context.currentVersion(); normFile.compatVersion = context.compatibilityVersion(); + normFile.os = context.os(); + normFile.minOSverson = context.osMinVersion(); + // FIXME: We need to get the SDK version from the system. For now the min + // OS version is better than nothing. + normFile.sdkVersion = context.osMinVersion(); + + if (context.generateVersionLoadCommand() && + context.os() != MachOLinkingContext::OS::unknown) + normFile.hasMinVersionLoadCommand = true; normFile.pageSize = context.pageSize(); normFile.rpaths = context.rpaths(); util.addDependentDylibs(atomFile, normFile); diff --git a/lld/test/mach-o/version-min-load-command.yaml b/lld/test/mach-o/version-min-load-command.yaml new file mode 100644 index 00000000000..95f7c8e9109 --- /dev/null +++ b/lld/test/mach-o/version-min-load-command.yaml @@ -0,0 +1,32 @@ +# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s +# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -static -version_load_command && llvm-objdump -private-headers %t | FileCheck %s +# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -no_version_load_command && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN +# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -static -version_load_command -no_version_load_command && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN +# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN + +--- !mach-o +arch: x86_64 +file-type: MH_OBJECT +flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ] +sections: + - segment: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + address: 0x0000000000000000 + content: [ 0x00, 0x00, 0x00, 0x00 ] +global-symbols: + - name: _main + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000000 +... + +# CHECK: Load command {{[0-9]*}} +# CHECK: cmd LC_VERSION_MIN_MACOSX +# CHECK: cmdsize 16 +# CHECK: version 10.8 +# CHECK: sdk 10.8 + +# NO_VERSION_MIN-NOT: LC_VERSION_MIN_MACOSX |