[lld] r259718 - Add generation of LC_VERSION_MIN load commands.

Pete Cooper via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 3 14:28:29 PST 2016


Author: pete
Date: Wed Feb  3 16:28:29 2016
New Revision: 259718

URL: http://llvm.org/viewvc/llvm-project?rev=259718&view=rev
Log:
Add generation of LC_VERSION_MIN load commands.

If the command line contains something like -macosx_version_min and we
don't explicitly disable generation with -no_version_load_command then
we generate the LC_VERSION_MIN command in the output file.

There's a couple of FIXME's in here.  These will be handled soon with
more tests but I didn't want to grow this patch any more than it already was.

rdar://problem/24472630

Added:
    lld/trunk/test/mach-o/version-min-load-command.yaml
Modified:
    lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
    lld/trunk/lib/Driver/DarwinLdDriver.cpp
    lld/trunk/lib/Driver/DarwinLdOptions.td
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp

Modified: lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h?rev=259718&r1=259717&r2=259718&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h Wed Feb  3 16:28:29 2016
@@ -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;

Modified: lld/trunk/lib/Driver/DarwinLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdDriver.cpp?rev=259718&r1=259717&r2=259718&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/DarwinLdDriver.cpp Wed Feb  3 16:28:29 2016
@@ -299,6 +299,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRe
 
   // 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::ArrayRe
       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::ArrayRe
     }
   }
 
+  // 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;

Modified: lld/trunk/lib/Driver/DarwinLdOptions.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdOptions.td?rev=259718&r1=259717&r2=259718&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdOptions.td (original)
+++ lld/trunk/lib/Driver/DarwinLdOptions.td Wed Feb  3 16:28:29 2016
@@ -33,6 +33,10 @@ def iphoneos_version_min : Separate<["-"
 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>;

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h?rev=259718&r1=259717&r2=259718&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h Wed Feb  3 16:28:29 2016
@@ -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;

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp?rev=259718&r1=259717&r2=259718&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp Wed Feb  3 16:28:29 2016
@@ -450,10 +450,21 @@ uint32_t MachOFileLayout::loadCommandsSi
     ++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::writeLo
       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::writeLo
       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;

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp?rev=259718&r1=259717&r2=259718&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp Wed Feb  3 16:28:29 2016
@@ -1244,6 +1244,15 @@ normalizedFromAtoms(const lld::File &ato
   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);

Added: lld/trunk/test/mach-o/version-min-load-command.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/version-min-load-command.yaml?rev=259718&view=auto
==============================================================================
--- lld/trunk/test/mach-o/version-min-load-command.yaml (added)
+++ lld/trunk/test/mach-o/version-min-load-command.yaml Wed Feb  3 16:28:29 2016
@@ -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




More information about the llvm-commits mailing list