[lld] r222300 - [mach-o] propagate dylib version numbers

Nick Kledzik kledzik at apple.com
Tue Nov 18 18:21:54 PST 2014


Author: kledzik
Date: Tue Nov 18 20:21:53 2014
New Revision: 222300

URL: http://llvm.org/viewvc/llvm-project?rev=222300&view=rev
Log:
[mach-o] propagate dylib version numbers

Mach-o does not use a simple SO_NEEDED to track dependent dylibs.  Instead,
the linker copies four things from each dylib to each client: the runtime path
(aka "install name"), the build time, current version (dylib build number), and
compatibility version  The build time is no longer used (it cause every rebuild
of a dylib to be different).  The compatibility version is usually just 1.0
and never changes, or the dylib becomes incompatible.

This patch copies that information into the NormalizedMachO format and
propagates it to clients.

Modified:
    lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
    lld/trunk/lib/ReaderWriter/MachO/File.h
    lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
    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
    lld/trunk/test/mach-o/dylib-install-names.yaml
    lld/trunk/test/mach-o/lazy-bind-x86_64.yaml

Modified: lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h?rev=222300&r1=222299&r2=222300&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h Tue Nov 18 20:21:53 2014
@@ -254,6 +254,10 @@ public:
   /// search paths to allow indirect dylibs to be overridden.
   mach_o::MachODylibFile* findIndirectDylib(StringRef path);
 
+  uint32_t dylibCurrentVersion(StringRef installName) const;
+
+  uint32_t dylibCompatVersion(StringRef installName) const;
+
   /// Creates a copy (owned by this MachOLinkingContext) of a string.
   StringRef copy(StringRef str) { return str.copy(_allocator); }
 

Modified: lld/trunk/lib/ReaderWriter/MachO/File.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/File.h?rev=222300&r1=222299&r2=222300&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/File.h (original)
+++ lld/trunk/lib/ReaderWriter/MachO/File.h Tue Nov 18 20:21:53 2014
@@ -198,8 +198,10 @@ private:
 
 class MachODylibFile : public SharedLibraryFile {
 public:
-  MachODylibFile(StringRef path, StringRef installName)
-      : SharedLibraryFile(path), _installName(installName) {
+  MachODylibFile(StringRef path, StringRef installName, uint32_t compatVersion,
+                 uint32_t currentVersion)
+      : SharedLibraryFile(path), _installName(installName),
+        _currentVersion(currentVersion), _compatVersion(compatVersion) {
   }
 
   const SharedLibraryAtom *exports(StringRef name,
@@ -243,6 +245,10 @@ public:
 
   StringRef installName() { return _installName; }
 
+  uint32_t currentVersion() { return _currentVersion; }
+
+  uint32_t compatVersion() { return _compatVersion; }
+
   typedef std::function<MachODylibFile *(StringRef)> FindDylib;
 
   void loadReExportedDylibs(FindDylib find) {
@@ -292,7 +298,9 @@ private:
     bool                      weakDef;
   };
 
-  StringRef _installName;
+  StringRef                                  _installName;
+  uint32_t                                   _currentVersion;
+  uint32_t                                   _compatVersion;
   atom_collection_vector<DefinedAtom>        _definedAtoms;
   atom_collection_vector<UndefinedAtom>      _undefinedAtoms;
   atom_collection_vector<SharedLibraryAtom>  _sharedLibraryAtoms;

Modified: lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp?rev=222300&r1=222299&r2=222300&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp Tue Nov 18 20:21:53 2014
@@ -652,6 +652,22 @@ MachODylibFile* MachOLinkingContext::fin
   return nullptr;
 }
 
+uint32_t MachOLinkingContext::dylibCurrentVersion(StringRef installName) const {
+  auto pos = _pathToDylibMap.find(installName);
+  if (pos != _pathToDylibMap.end())
+    return pos->second->currentVersion();
+  else
+    return 0x1000; // 1.0
+}
+
+uint32_t MachOLinkingContext::dylibCompatVersion(StringRef installName) const {
+  auto pos = _pathToDylibMap.find(installName);
+  if (pos != _pathToDylibMap.end())
+    return pos->second->compatVersion();
+  else
+    return 0x1000; // 1.0
+}
+
 bool MachOLinkingContext::createImplicitFiles(
                             std::vector<std::unique_ptr<File> > &result) {
   // Add indirect dylibs by asking each linked dylib to add its indirects.

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h?rev=222300&r1=222299&r2=222300&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h Tue Nov 18 20:21:53 2014
@@ -1,4 +1,4 @@
-//===- lib/ReaderWriter/MachO/NormalizedFile.h ----------------------===//
+//===- lib/ReaderWriter/MachO/MachONormalizedFile.h -----------------------===//
 //
 //                             The LLVM Linker
 //
@@ -145,6 +145,9 @@ struct Symbol {
 /// A typedef so that YAML I/O can (de/en)code the protection bits of a segment.
 LLVM_YAML_STRONG_TYPEDEF(uint32_t, VMProtect)
 
+/// A typedef to hold verions X.Y.X packed into 32-bit xxxx.yy.zz
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, PackedVersion)
+
 /// Segments are only used in normalized final linked images (not in relocatable
 /// object files). They specify how a range of the file is loaded.
 struct Segment {
@@ -159,6 +162,8 @@ struct Segment {
 struct DependentDylib {
   StringRef       path;
   LoadCommandType kind;
+  PackedVersion   compatVersion;
+  PackedVersion   currentVersion;
 };
 
 /// A normalized rebasing entry.  Only used in normalized final linked images.
@@ -203,7 +208,6 @@ struct DataInCode {
 /// A typedef so that YAML I/O can encode/decode mach_header.flags.
 LLVM_YAML_STRONG_TYPEDEF(uint32_t, FileFlags)
 
-
 ///
 struct NormalizedFile {
   NormalizedFile() : arch(MachOLinkingContext::arch_unknown),
@@ -225,14 +229,16 @@ struct NormalizedFile {
 
   // Maps to load commands with no LINKEDIT content (final linked images only).
   std::vector<DependentDylib> dependentDylibs;
-  StringRef                   installName;
+  StringRef                   installName;      // dylibs only
+  PackedVersion               compatVersion;    // dylibs only
+  PackedVersion               currentVersion;   // dylibs only
   bool                        hasUUID;
   std::vector<StringRef>      rpaths;
   Hex64                       entryAddress;
   MachOLinkingContext::OS     os;
   Hex64                       sourceVersion;
-  Hex32                       minOSverson;
-  Hex32                       sdkVersion;
+  PackedVersion               minOSverson;
+  PackedVersion               sdkVersion;
 
   // Maps to load commands with LINKEDIT content (final linked images only).
   Hex32                       pageSize;

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp?rev=222300&r1=222299&r2=222300&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp Tue Nov 18 20:21:53 2014
@@ -455,8 +455,10 @@ readBinary(std::unique_ptr<MemoryBuffer>
       DependentDylib entry;
       entry.path = lc + read32(&dl->dylib.name, isBig);
       entry.kind = LoadCommandType(cmd);
+      entry.compatVersion = read32(&dl->dylib.compatibility_version, isBig);
+      entry.currentVersion = read32(&dl->dylib.current_version, isBig);
       f->dependentDylibs.push_back(entry);
-      }
+     }
       break;
     case LC_DYLD_INFO:
     case LC_DYLD_INFO_ONLY:

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp?rev=222300&r1=222299&r2=222300&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp Tue Nov 18 20:21:53 2014
@@ -734,9 +734,9 @@ std::error_code MachOFileLayout::writeLo
       dc->cmd                         = LC_ID_DYLIB;
       dc->cmdsize                     = size;
       dc->dylib.name                  = sizeof(dylib_command); // offset
-      dc->dylib.timestamp             = 0; // FIXME
-      dc->dylib.current_version       = 0; // FIXME
-      dc->dylib.compatibility_version = 0; // FIXME
+      dc->dylib.timestamp             = 2;
+      dc->dylib.current_version       = _file.currentVersion;
+      dc->dylib.compatibility_version = _file.compatVersion;
       if (_swap)
         swapStruct(*dc);
       memcpy(lc + sizeof(dylib_command), path.begin(), path.size());
@@ -834,9 +834,9 @@ std::error_code MachOFileLayout::writeLo
       dc->cmd                         = dep.kind;
       dc->cmdsize                     = size;
       dc->dylib.name                  = sizeof(dylib_command); // offset
-      dc->dylib.timestamp             = 0; // FIXME
-      dc->dylib.current_version       = 0; // FIXME
-      dc->dylib.compatibility_version = 0; // FIXME
+      dc->dylib.timestamp             = 2;
+      dc->dylib.current_version       = dep.currentVersion;
+      dc->dylib.compatibility_version = dep.compatVersion;
       if (_swap)
         swapStruct(*dc);
       memcpy(lc+sizeof(dylib_command), dep.path.begin(), dep.path.size());

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp?rev=222300&r1=222299&r2=222300&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp Tue Nov 18 20:21:53 2014
@@ -941,6 +941,8 @@ void Util::addDependentDylibs(const lld:
       DependentDylib depInfo;
       depInfo.path = loadPath;
       depInfo.kind = llvm::MachO::LC_LOAD_DYLIB;
+      depInfo.currentVersion = _context.dylibCurrentVersion(loadPath);
+      depInfo.compatVersion = _context.dylibCompatVersion(loadPath);
       nFile.dependentDylibs.push_back(depInfo);
     } else {
       if ( slAtom->canBeNullAtRuntime() )
@@ -1188,6 +1190,8 @@ normalizedFromAtoms(const lld::File &ato
   normFile.fileType = context.outputMachOType();
   normFile.flags = util.fileFlags();
   normFile.installName = context.installName();
+  normFile.currentVersion = context.currentVersion();
+  normFile.compatVersion = context.compatibilityVersion();
   normFile.pageSize = context.pageSize();
   util.addDependentDylibs(atomFile, normFile);
   util.copySegmentInfo(normFile);

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp?rev=222300&r1=222299&r2=222300&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp Tue Nov 18 20:21:53 2014
@@ -820,7 +820,9 @@ normalizedDylibToAtoms(const NormalizedF
                        bool copyRefs) {
   // Instantiate SharedLibraryFile object.
   std::unique_ptr<MachODylibFile> file(
-                          new MachODylibFile(path, normalizedFile.installName));
+      new MachODylibFile(path, normalizedFile.installName,
+                         normalizedFile.compatVersion,
+                         normalizedFile.currentVersion));
   // Tell MachODylibFile object about all symbols it exports.
   if (!normalizedFile.exportInfo.empty()) {
     // If exports trie exists, use it instead of traditional symbol table.

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp?rev=222300&r1=222299&r2=222300&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp Tue Nov 18 20:21:53 2014
@@ -25,6 +25,7 @@
 #include "llvm/ADT/Twine.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
 #include "llvm/Support/MachO.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/SourceMgr.h"
@@ -529,8 +530,13 @@ struct ScalarEnumerationTraits<LoadComma
 template <>
 struct MappingTraits<DependentDylib> {
   static void mapping(IO &io, DependentDylib& dylib) {
-    io.mapRequired("path",    dylib.path);
-    io.mapOptional("kind",    dylib.kind,       llvm::MachO::LC_LOAD_DYLIB);
+    io.mapRequired("path",            dylib.path);
+    io.mapOptional("kind",            dylib.kind,
+                                      llvm::MachO::LC_LOAD_DYLIB);
+    io.mapOptional("compat-version",  dylib.compatVersion,
+                                      PackedVersion(0x10000));
+    io.mapOptional("current-version", dylib.currentVersion,
+                                      PackedVersion(0x10000));
   }
 };
 
@@ -650,6 +656,24 @@ struct MappingTraits<DataInCode> {
   }
 };
 
+template <>
+struct ScalarTraits<PackedVersion> {
+  static void output(const PackedVersion &value, void*, raw_ostream &out) {
+    out << llvm::format("%d.%d", (value >> 16), (value >> 8) & 0xFF);
+    if (value & 0xFF) {
+      out << llvm::format(".%d", (value & 0xFF));
+    }
+  }
+  static StringRef input(StringRef scalar, void*, PackedVersion &result) {
+    uint32_t value;
+    if (lld::MachOLinkingContext::parsePackedVersion(scalar, value))
+      return "malformed version number";
+    result = value;
+    // Return the empty string on success,
+    return StringRef();
+  }
+  static bool mustQuote(StringRef) { return false; }
+};
 
 template <>
 struct MappingTraits<NormalizedFile> {
@@ -659,13 +683,15 @@ struct MappingTraits<NormalizedFile> {
     io.mapOptional("flags",            file.flags);
     io.mapOptional("dependents",       file.dependentDylibs);
     io.mapOptional("install-name",     file.installName,    StringRef());
+    io.mapOptional("compat-version",   file.compatVersion,  PackedVersion(0x10000));
+    io.mapOptional("current-version",  file.currentVersion, PackedVersion(0x10000));
     io.mapOptional("has-UUID",         file.hasUUID,        true);
     io.mapOptional("rpaths",           file.rpaths);
     io.mapOptional("entry-point",      file.entryAddress,   Hex64(0));
     io.mapOptional("source-version",   file.sourceVersion,  Hex64(0));
     io.mapOptional("OS",               file.os);
-    io.mapOptional("min-os-version",   file.minOSverson,    Hex32(0));
-    io.mapOptional("sdk-version",      file.sdkVersion,     Hex32(0));
+    io.mapOptional("min-os-version",   file.minOSverson,    PackedVersion(0));
+    io.mapOptional("sdk-version",      file.sdkVersion,     PackedVersion(0));
     io.mapOptional("segments",         file.segments);
     io.mapOptional("sections",         file.sections);
     io.mapOptional("local-symbols",    file.localSymbols);

Modified: lld/trunk/test/mach-o/dylib-install-names.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/dylib-install-names.yaml?rev=222300&r1=222299&r2=222300&view=diff
==============================================================================
--- lld/trunk/test/mach-o/dylib-install-names.yaml (original)
+++ lld/trunk/test/mach-o/dylib-install-names.yaml Tue Nov 18 20:21:53 2014
@@ -1,5 +1,6 @@
 # Check we accept -install_name correctly:
 # RUN: lld -flavor darwin -arch x86_64 -install_name libwibble.dylib -dylib \
+# RUN:     -compatibility_version 2.0 -current_version 5.3 \
 # RUN:     %p/Inputs/libSystem.yaml %s -o %t.dylib
 # RUN: macho-dump %t.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
 
@@ -9,12 +10,14 @@
 
 # Check we default the install-name to the output file:
 # RUN: lld -flavor darwin -arch x86_64 -dylib %s -o libwibble.dylib \
+# RUN:     -compatibility_version 2.0 -current_version 5.3 \
 # RUN:     %p/Inputs/libSystem.yaml
 # RUN: macho-dump libwibble.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
 # RUN: rm -f libwibble.dylib
 
 # Check -single_module does nothing
 # RUN: lld -flavor darwin -arch x86_64 -dylib %s -install_name libwibble.dylib \
+# RUN:     -compatibility_version 2.0 -current_version 5.3 \
 # RUN:     -single_module -o %t2.dylib %p/Inputs/libSystem.yaml
 # RUN: macho-dump %t2.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
 
@@ -51,6 +54,9 @@ global-symbols:
 # CHECK-BINARY-WRITE: (('command', 13)
 # CHECK-BINARY-WRITE-NEXT:  ('size', 40)
 # CHECK-BINARY-WRITE-NEXT:  ('install_name', 'libwibble.dylib')
+# CHECK-BINARY-WRITE-NEXT:    ('timestamp,
+# CHECK-BINARY-WRITE-NEXT:    ('cur_version, 328448)
+# CHECK-BINARY-WRITE-NEXT:    ('compat_version, 131072)
 
 # CHECK-BINARY-READ: shared-library-atoms:
 # CHECK-BINARY-READ:     - name:          _myGlobal

Modified: lld/trunk/test/mach-o/lazy-bind-x86_64.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/lazy-bind-x86_64.yaml?rev=222300&r1=222299&r2=222300&view=diff
==============================================================================
--- lld/trunk/test/mach-o/lazy-bind-x86_64.yaml (original)
+++ lld/trunk/test/mach-o/lazy-bind-x86_64.yaml Tue Nov 18 20:21:53 2014
@@ -3,6 +3,7 @@
 # RUN: llvm-objdump -lazy-bind %t | FileCheck %s
 # RUN: llvm-nm -m %t | FileCheck --check-prefix=CHECK-NM %s
 # RUN: llvm-objdump -disassemble %t | FileCheck --check-prefix=CHECK-HELPERS %s
+# RUN: llvm-objdump -private-headers %t | FileCheck --check-prefix=CHECK-DYLIBS %s
 #
 # Test that correct two-level namespace ordinals are used for lazy bindings.
 #
@@ -61,23 +62,29 @@ undefined-symbols:
     value:           0x0000000000000000
 
 --- !mach-o
-arch:            x86_64
-file-type:       MH_DYLIB
-install-name:    /usr/lib/libbar.dylib
+arch:              x86_64
+file-type:         MH_DYLIB
+install-name:      /usr/lib/libbar.dylib
+compat-version:    1.0
+current-version:   2.3
 exports:
   - name:            _bar
 
 --- !mach-o
-arch:            x86_64
-file-type:       MH_DYLIB
-install-name:    /usr/lib/libfoo.dylib
+arch:              x86_64
+file-type:         MH_DYLIB
+install-name:      /usr/lib/libfoo.dylib
+compat-version:    2.0
+current-version:   3.4
 exports:
   - name:            _foo
 
 --- !mach-o
-arch:            x86_64
-file-type:       MH_DYLIB
-install-name:    /usr/lib/libbaz.dylib
+arch:              x86_64
+file-type:         MH_DYLIB
+install-name:      /usr/lib/libbaz.dylib
+compat-version:    3.0
+current-version:   4.5
 exports:
   - name:            _baz
 
@@ -99,3 +106,18 @@ exports:
 # CHECK-HELPERS: 	68 10 00 00 00            pushq	$16
 # CHECK-HELPERS: 	68 20 00 00 00            pushq	$32
 
+
+# CHECK-DYLIBS:           cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS:          name /usr/lib/libbar.dylib (offset 24)
+# CHECK-DYLIBS:       current version 2.3.0
+# CHECK-DYLIBS: compatibility version 1.0.0
+# CHECK-DYLIBS:           cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS:          name /usr/lib/libfoo.dylib (offset 24)
+# CHECK-DYLIBS:       current version 3.4.0
+# CHECK-DYLIBS: compatibility version 2.0.0
+# CHECK-DYLIBS:           cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS:          name /usr/lib/libbaz.dylib (offset 24)
+# CHECK-DYLIBS:       current version 4.5.0
+# CHECK-DYLIBS: compatibility version 3.0.0
+
+





More information about the llvm-commits mailing list