[lld] r259742 - Generate version min load commands when the platform is unknown.

Pete Cooper via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 3 18:16:09 PST 2016


Author: pete
Date: Wed Feb  3 20:16:08 2016
New Revision: 259742

URL: http://llvm.org/viewvc/llvm-project?rev=259742&view=rev
Log:
Generate version min load commands when the platform is unknown.

In the case where we are emitting to an object file, the platform is
possibly unknown, and the source object files contained load commands
for version min, we can take the maximum of those min versions and
emit in in the output object file.

This test also tests r259739.

Added:
    lld/trunk/test/mach-o/Inputs/no-version-min-load-command-object.yaml
    lld/trunk/test/mach-o/version-min-load-command-object.yaml
Modified:
    lld/trunk/lib/ReaderWriter/MachO/File.h
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp

Modified: lld/trunk/lib/ReaderWriter/MachO/File.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/File.h?rev=259742&r1=259741&r2=259742&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/File.h (original)
+++ lld/trunk/lib/ReaderWriter/MachO/File.h Wed Feb  3 20:16:08 2016
@@ -201,6 +201,16 @@ public:
     _objcConstraint = v;
   }
 
+  uint32_t minVersion() const { return _minVersion; }
+  void setMinVersion(uint32_t v) { _minVersion = v; }
+
+  LoadCommandType minVersionLoadCommandKind() const {
+    return _minVersionLoadCommandKind;
+  }
+  void setMinVersionLoadCommandKind(LoadCommandType v) {
+    _minVersionLoadCommandKind = v;
+  }
+
   uint32_t swiftVersion() const { return _swiftVersion; }
   void setSwiftVersion(uint32_t v) { _swiftVersion = v; }
 
@@ -249,6 +259,8 @@ private:
   NameToAtom                     _undefAtoms;
   MachOLinkingContext::Arch      _arch = MachOLinkingContext::arch_unknown;
   MachOLinkingContext::OS        _os = MachOLinkingContext::OS::unknown;
+  uint32_t                       _minVersion = 0;
+  LoadCommandType               _minVersionLoadCommandKind = (LoadCommandType)0;
   MachOLinkingContext::ObjCConstraint _objcConstraint =
       MachOLinkingContext::objc_unknown;
   uint32_t                       _swiftVersion = 0;

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h?rev=259742&r1=259741&r2=259742&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h Wed Feb  3 20:16:08 2016
@@ -253,6 +253,7 @@ struct NormalizedFile {
   Hex64                       sourceVersion = 0;
   PackedVersion               minOSverson = 0;
   PackedVersion               sdkVersion = 0;
+  LoadCommandType             minOSVersionKind = (LoadCommandType)0;
 
   // Maps to load commands with LINKEDIT content (final linked images only).
   Hex32                       pageSize = 0;

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp?rev=259742&r1=259741&r2=259742&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp Wed Feb  3 20:16:08 2016
@@ -471,6 +471,15 @@ readBinary(std::unique_ptr<MemoryBuffer>
     case LC_DYLD_INFO_ONLY:
       dyldInfo = reinterpret_cast<const dyld_info_command*>(lc);
       break;
+    case LC_VERSION_MIN_MACOSX:
+    case LC_VERSION_MIN_IPHONEOS:
+    case LC_VERSION_MIN_WATCHOS:
+    case LC_VERSION_MIN_TVOS:
+      // If we are emitting an object file, then we may take the load command
+      // kind from these commands and pass it on to the output
+      // file.
+      f->minOSVersionKind = (LoadCommandType)cmd;
+      break;
     }
     return false;
   });

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp?rev=259742&r1=259741&r2=259742&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp Wed Feb  3 20:16:08 2016
@@ -317,6 +317,10 @@ MachOFileLayout::MachOFileLayout(const N
                                + file.sections.size() * sectsSize
                                + sizeof(symtab_command);
     _countOfLoadCommands = 2;
+    if (file.hasMinVersionLoadCommand) {
+      _endOfLoadCommands += sizeof(version_min_command);
+      _countOfLoadCommands++;
+    }
     if (!_file.dataInCode.empty()) {
       _endOfLoadCommands += sizeof(linkedit_data_command);
       _countOfLoadCommands++;
@@ -738,6 +742,38 @@ std::error_code MachOFileLayout::writeSe
   return std::error_code();
 }
 
+static void writeVersionMinLoadCommand(const NormalizedFile &_file,
+                                       bool _swap,
+                                       uint8_t *&lc) {
+  if (!_file.hasMinVersionLoadCommand)
+    return;
+  version_min_command *vm = reinterpret_cast<version_min_command*>(lc);
+  switch (_file.os) {
+    case MachOLinkingContext::OS::unknown:
+      vm->cmd     = _file.minOSVersionKind;
+      vm->cmdsize = sizeof(version_min_command);
+      vm->version = _file.minOSverson;
+      vm->sdk     = 0;
+      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_IPHONEOS;
+      vm->cmdsize = sizeof(version_min_command);
+      vm->version = _file.minOSverson;
+      vm->sdk     = _file.sdkVersion;
+      break;
+  }
+  if (_swap)
+    swapStruct(*vm);
+  lc += sizeof(version_min_command);
+}
+
 std::error_code MachOFileLayout::writeLoadCommands() {
   std::error_code ec;
   uint8_t *lc = &_buffer[_startOfLoadCommands];
@@ -759,6 +795,11 @@ std::error_code MachOFileLayout::writeLo
     if (_swap)
       swapStruct(*st);
     lc += sizeof(symtab_command);
+
+    // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS,
+    // LC_VERSION_MIN_WATCHOS, LC_VERSION_MIN_TVOS
+    writeVersionMinLoadCommand(_file, _swap, lc);
+
     // Add LC_DATA_IN_CODE if needed.
     if (_dataInCodeSize != 0) {
       linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
@@ -872,32 +913,7 @@ std::error_code MachOFileLayout::writeLo
 
     // 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);
-    }
+    writeVersionMinLoadCommand(_file, _swap, lc);
 
     // If main executable, add LC_MAIN.
     if (_file.fileType == llvm::MachO::MH_EXECUTE) {

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp?rev=259742&r1=259741&r2=259742&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp Wed Feb  3 20:16:08 2016
@@ -128,6 +128,18 @@ public:
   void      copyEntryPointAddress(NormalizedFile &file);
   void      copySectionContent(NormalizedFile &file);
 
+  bool allSourceFilesHaveMinVersions() const {
+    return _allSourceFilesHaveMinVersions;
+  }
+
+  uint32_t minVersion() const {
+    return _minVersion;
+  }
+
+  LoadCommandType minVersionCommandType() const {
+    return _minVersionCommandType;
+  }
+
 private:
   typedef std::map<DefinedAtom::ContentType, SectionInfo*> TypeToSection;
   typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
@@ -183,6 +195,9 @@ private:
   std::vector<const Atom *>     _machHeaderAliasAtoms;
   bool                          _hasTLVDescriptors;
   bool                          _subsectionsViaSymbols;
+  bool                          _allSourceFilesHaveMinVersions = true;
+  LoadCommandType               _minVersionCommandType = (LoadCommandType)0;
+  uint32_t                      _minVersion = 0;
 };
 
 Util::~Util() {
@@ -378,11 +393,25 @@ void Util::processDefinedAtoms(const lld
 }
 
 void Util::processAtomAttributes(const DefinedAtom *atom) {
-  // If the file doesn't use subsections via symbols, then make sure we don't
-  // add that flag to the final output file if we have a relocatable file.
-  if (auto *machoFile = dyn_cast<mach_o::MachOFile>(&atom->file()))
+  if (auto *machoFile = dyn_cast<mach_o::MachOFile>(&atom->file())) {
+    // If the file doesn't use subsections via symbols, then make sure we don't
+    // add that flag to the final output file if we have a relocatable file.
     if (!machoFile->subsectionsViaSymbols())
       _subsectionsViaSymbols = false;
+
+    // All the source files must have min versions for us to output an object
+    // file with a min version.
+    if (auto v = machoFile->minVersion())
+      _minVersion = std::max(_minVersion, v);
+    else
+      _allSourceFilesHaveMinVersions = false;
+
+    // If we don't have a platform load command, but one of the source files
+    // does, then take the one from the file.
+    if (!_minVersionCommandType)
+      if (auto v = machoFile->minVersionLoadCommandKind())
+        _minVersionCommandType = v;
+  }
 }
 
 void Util::assignAtomToSection(const DefinedAtom *atom) {
@@ -1245,14 +1274,31 @@ normalizedFromAtoms(const lld::File &ato
   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.
+
+  // If we are emitting an object file, then the min version is the maximum
+  // of the min's of all the source files and the cmdline.
+  if (normFile.fileType == llvm::MachO::MH_OBJECT)
+    normFile.minOSverson = std::max(context.osMinVersion(), util.minVersion());
+  else
+    normFile.minOSverson = context.osMinVersion();
+
+  normFile.minOSVersionKind = util.minVersionCommandType();
+
   normFile.sdkVersion = context.sdkVersion();
 
   if (context.generateVersionLoadCommand() &&
       context.os() != MachOLinkingContext::OS::unknown)
     normFile.hasMinVersionLoadCommand = true;
+  else if (normFile.fileType == llvm::MachO::MH_OBJECT &&
+           util.allSourceFilesHaveMinVersions() &&
+           ((normFile.os != MachOLinkingContext::OS::unknown) ||
+            util.minVersionCommandType())) {
+    // If we emit an object file, then it should contain a min version load
+    // command if all of the source files also contained min version commands.
+    // Also, we either need to have a platform, or found a platform from the
+    // source object files.
+    normFile.hasMinVersionLoadCommand = true;
+  }
   normFile.pageSize = context.pageSize();
   normFile.rpaths = context.rpaths();
   util.addDependentDylibs(atomFile, normFile);

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp?rev=259742&r1=259741&r2=259742&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp Wed Feb  3 20:16:08 2016
@@ -1061,6 +1061,8 @@ normalizedObjectToAtoms(MachOFile *file,
   file->setFlags(normalizedFile.flags);
   file->setArch(normalizedFile.arch);
   file->setOS(normalizedFile.os);
+  file->setMinVersion(normalizedFile.minOSverson);
+  file->setMinVersionLoadCommandKind(normalizedFile.minOSVersionKind);
 
   // Sort references in each atom to their canonical order.
   for (const DefinedAtom* defAtom : file->defined()) {

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp?rev=259742&r1=259741&r2=259742&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp Wed Feb  3 20:16:08 2016
@@ -524,6 +524,14 @@ struct ScalarEnumerationTraits<LoadComma
                         llvm::MachO::LC_LOAD_UPWARD_DYLIB);
     io.enumCase(value, "LC_LAZY_LOAD_DYLIB",
                         llvm::MachO::LC_LAZY_LOAD_DYLIB);
+    io.enumCase(value, "LC_VERSION_MIN_MACOSX",
+                        llvm::MachO::LC_VERSION_MIN_MACOSX);
+    io.enumCase(value, "LC_VERSION_MIN_IPHONEOS",
+                        llvm::MachO::LC_VERSION_MIN_IPHONEOS);
+    io.enumCase(value, "LC_VERSION_MIN_TVOS",
+                        llvm::MachO::LC_VERSION_MIN_TVOS);
+    io.enumCase(value, "LC_VERSION_MIN_WATCHOS",
+                        llvm::MachO::LC_VERSION_MIN_WATCHOS);
   }
 };
 
@@ -692,6 +700,7 @@ struct MappingTraits<NormalizedFile> {
     io.mapOptional("source-version",   file.sourceVersion,  Hex64(0));
     io.mapOptional("OS",               file.os);
     io.mapOptional("min-os-version",   file.minOSverson,    PackedVersion(0));
+    io.mapOptional("min-os-version-kind",   file.minOSVersionKind, (LoadCommandType)0);
     io.mapOptional("sdk-version",      file.sdkVersion,     PackedVersion(0));
     io.mapOptional("segments",         file.segments);
     io.mapOptional("sections",         file.sections);

Added: lld/trunk/test/mach-o/Inputs/no-version-min-load-command-object.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/Inputs/no-version-min-load-command-object.yaml?rev=259742&view=auto
==============================================================================
--- lld/trunk/test/mach-o/Inputs/no-version-min-load-command-object.yaml (added)
+++ lld/trunk/test/mach-o/Inputs/no-version-min-load-command-object.yaml Wed Feb  3 20:16:08 2016
@@ -0,0 +1,22 @@
+
+# This object file has no version min and so will prevent any -r link from emitting
+# a 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:            _main2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...

Added: lld/trunk/test/mach-o/version-min-load-command-object.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/version-min-load-command-object.yaml?rev=259742&view=auto
==============================================================================
--- lld/trunk/test/mach-o/version-min-load-command-object.yaml (added)
+++ lld/trunk/test/mach-o/version-min-load-command-object.yaml Wed Feb  3 20:16:08 2016
@@ -0,0 +1,35 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r -macosx_version_min 10.8 && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r %p/Inputs/no-version-min-load-command-object.yaml && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN
+
+# If we are emitting an object file, then we only emit a min version load command if the source object file(s) all have
+# version(s) and either known platforms or contain min version load commands themselves.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+min-os-version-kind: LC_VERSION_MIN_MACOSX
+min-os-version: 10.8
+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 n/a
+
+# NO_VERSION_MIN-NOT: LC_VERSION_MIN_MACOSX
\ No newline at end of file




More information about the llvm-commits mailing list