[lld] r219949 - [mach-o] Add support for upward linking

Nick Kledzik kledzik at apple.com
Thu Oct 16 12:31:28 PDT 2014


Author: kledzik
Date: Thu Oct 16 14:31:28 2014
New Revision: 219949

URL: http://llvm.org/viewvc/llvm-project?rev=219949&view=rev
Log:
[mach-o] Add support for upward linking

To deal with cycles in shared library dependencies, the darwin linker supports
marking specific link dependencies as "upward".  An upward link is when a
lower level library links against a higher level library.

Added:
    lld/trunk/test/mach-o/Inputs/bar.yaml
    lld/trunk/test/mach-o/upward-dylib-load-command.yaml
    lld/trunk/test/mach-o/upward-dylib-paths.yaml
Modified:
    lld/trunk/include/lld/Driver/DarwinInputGraph.h
    lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
    lld/trunk/lib/Driver/DarwinInputGraph.cpp
    lld/trunk/lib/Driver/DarwinLdDriver.cpp
    lld/trunk/lib/Driver/DarwinLdOptions.td
    lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
    lld/trunk/test/mach-o/libresolve-bizarre-root-override.yaml

Modified: lld/trunk/include/lld/Driver/DarwinInputGraph.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Driver/DarwinInputGraph.h?rev=219949&r1=219948&r2=219949&view=diff
==============================================================================
--- lld/trunk/include/lld/Driver/DarwinInputGraph.h (original)
+++ lld/trunk/include/lld/Driver/DarwinInputGraph.h Thu Oct 16 14:31:28 2014
@@ -25,8 +25,9 @@ namespace lld {
 /// \brief Represents a MachO File
 class MachOFileNode : public FileNode {
 public:
-  MachOFileNode(StringRef path, bool isWholeArchive, MachOLinkingContext &ctx)
-      : FileNode(path), _context(ctx), _isWholeArchive(isWholeArchive) {}
+  MachOFileNode(StringRef path, MachOLinkingContext &ctx)
+      : FileNode(path), _context(ctx), _isWholeArchive(false),
+        _upwardDylib(false) {}
 
   /// \brief Parse the input file to lld::File.
   std::error_code parse(const LinkingContext &ctx,
@@ -42,11 +43,20 @@ public:
     return *_files[_nextFileIndex++];
   }
 
+  void setLoadWholeArchive(bool value=true) {
+    _isWholeArchive = value;
+  }
+
+  void setUpwardDylib(bool value=true) {
+    _upwardDylib = value;
+  }
+
 private:
  void narrowFatBuffer(StringRef filePath);
 
   MachOLinkingContext &_context;
   bool _isWholeArchive;
+  bool _upwardDylib;
 };
 
 } // namespace lld

Modified: lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h?rev=219949&r1=219948&r2=219949&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h Thu Oct 16 14:31:28 2014
@@ -237,7 +237,7 @@ public:
   StringRef binderSymbolName() const;
 
   /// Used to keep track of direct and indirect dylibs.
-  void registerDylib(mach_o::MachODylibFile *dylib) const;
+  void registerDylib(mach_o::MachODylibFile *dylib, bool upward) const;
 
   /// Used to find indirect dylibs. Instantiates a MachODylibFile if one
   /// has not already been made for the requested dylib.  Uses -L and -F
@@ -252,6 +252,9 @@ public:
   bool sliceFromFatFile(const MemoryBuffer &mb, uint32_t &offset,
                         uint32_t &size);
 
+  /// Returns if a command line option specified dylib is an upward link.
+  bool isUpwardDylib(StringRef installName) const;
+
   static bool isThinObjectFile(StringRef path, Arch &arch);
   static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype);
   static Arch archFromName(StringRef archName);
@@ -317,6 +320,7 @@ private:
   std::vector<SectionAlign> _sectAligns;
   mutable llvm::StringMap<mach_o::MachODylibFile*> _pathToDylibMap;
   mutable std::set<mach_o::MachODylibFile*> _allDylibs;
+  mutable std::set<mach_o::MachODylibFile*> _upwardDylibs;
   mutable std::vector<std::unique_ptr<class MachOFileNode>> _indirectDylibs;
   ExportMode _exportMode;
   llvm::StringSet<> _exportedSymbols;

Modified: lld/trunk/lib/Driver/DarwinInputGraph.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinInputGraph.cpp?rev=219949&r1=219948&r2=219949&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinInputGraph.cpp (original)
+++ lld/trunk/lib/Driver/DarwinInputGraph.cpp Thu Oct 16 14:31:28 2014
@@ -57,7 +57,8 @@ std::error_code MachOFileNode::parse(con
   for (std::unique_ptr<File> &pf : parsedFiles) {
     // If a dylib was parsed, inform LinkingContext about it.
     if (SharedLibraryFile *shl = dyn_cast<SharedLibraryFile>(pf.get())) {
-      _context.registerDylib(reinterpret_cast<mach_o::MachODylibFile*>(shl));
+      _context.registerDylib(reinterpret_cast<mach_o::MachODylibFile*>(shl),
+                             _upwardDylib);
     }
     _files.push_back(std::move(pf));
   }

Modified: lld/trunk/lib/Driver/DarwinLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdDriver.cpp?rev=219949&r1=219948&r2=219949&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/DarwinLdDriver.cpp Thu Oct 16 14:31:28 2014
@@ -85,9 +85,14 @@ static std::string canonicalizePath(Stri
 }
 
 static void addFile(StringRef path, std::unique_ptr<InputGraph> &inputGraph,
-                    bool forceLoad, MachOLinkingContext &ctx) {
-   inputGraph->addInputElement(std::unique_ptr<InputElement>(
-                                      new MachOFileNode(path, forceLoad, ctx)));
+                    MachOLinkingContext &ctx, bool loadWholeArchive,
+                    bool upwardDylib) {
+  auto node = llvm::make_unique<MachOFileNode>(path, ctx);
+  if (loadWholeArchive)
+    node->setLoadWholeArchive();
+  if (upwardDylib)
+    node->setUpwardDylib();
+  inputGraph->addInputElement(std::move(node));
 }
 
 // Export lists are one symbol per line.  Blank lines are ignored.
@@ -165,7 +170,7 @@ static std::error_code parseFileList(Str
     if (ctx.testingFileUsage()) {
       diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n';
     }
-    addFile(path, inputGraph, forceLoad, ctx);
+    addFile(path, inputGraph, ctx, forceLoad, false);
     buffer = lineAndRest.second;
   }
   return std::error_code();
@@ -638,34 +643,44 @@ bool DarwinLdDriver::parse(int argc, con
 
   // Handle input files
   for (auto &arg : *parsedArgs) {
+    bool upward;
     ErrorOr<StringRef> resolvedPath = StringRef();
     switch (arg->getOption().getID()) {
     default:
       continue;
     case OPT_INPUT:
-      addFile(arg->getValue(), inputGraph, globalWholeArchive, ctx);
+      addFile(arg->getValue(), inputGraph, ctx, globalWholeArchive, false);
+      break;
+    case OPT_upward_library:
+      addFile(arg->getValue(), inputGraph, ctx, false, true);
       break;
     case OPT_l:
+    case OPT_upward_l:
+      upward = (arg->getOption().getID() == OPT_upward_l);
       resolvedPath = ctx.searchLibrary(arg->getValue());
       if (!resolvedPath) {
-        diagnostics << "Unable to find library -l" << arg->getValue() << "\n";
+        diagnostics << "Unable to find library for " << arg->getSpelling()
+                    << arg->getValue() << "\n";
         return false;
       } else if (ctx.testingFileUsage()) {
-       diagnostics << "Found library "
+        diagnostics << "Found " << (upward ? "upward " : " ") << "library "
                    << canonicalizePath(resolvedPath.get()) << '\n';
       }
-      addFile(resolvedPath.get(), inputGraph, globalWholeArchive, ctx);
+      addFile(resolvedPath.get(), inputGraph, ctx, globalWholeArchive, upward);
       break;
     case OPT_framework:
+    case OPT_upward_framework:
+      upward = (arg->getOption().getID() == OPT_upward_framework);
       resolvedPath = ctx.findPathForFramework(arg->getValue());
       if (!resolvedPath) {
-        diagnostics << "Unable to find -framework " << arg->getValue() << "\n";
+        diagnostics << "Unable to find framework for "
+                    << arg->getSpelling() << " " << arg->getValue() << "\n";
         return false;
       } else if (ctx.testingFileUsage()) {
-        diagnostics << "Found framework "
+        diagnostics << "Found " << (upward ? "upward " : " ") << "framework "
                     << canonicalizePath(resolvedPath.get()) << '\n';
       }
-      addFile(resolvedPath.get(), inputGraph, globalWholeArchive, ctx);
+      addFile(resolvedPath.get(), inputGraph, ctx, globalWholeArchive, upward);
       break;
     case OPT_filelist:
       if (std::error_code ec = parseFileList(arg->getValue(), inputGraph,

Modified: lld/trunk/lib/Driver/DarwinLdOptions.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdOptions.td?rev=219949&r1=219948&r2=219949&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdOptions.td (original)
+++ lld/trunk/lib/Driver/DarwinLdOptions.td Thu Oct 16 14:31:28 2014
@@ -115,9 +115,18 @@ def syslibroot : Separate<["-"], "syslib
 def l : Joined<["-"], "l">,
      MetaVarName<"<libname>">,
      HelpText<"Base name of library searched for in -L directories">;
+def upward_l : Joined<["-"], "upward-l">,
+     MetaVarName<"<libname>">,
+     HelpText<"Base name of upward library searched for in -L directories">;
 def framework : Separate<["-"], "framework">,
      MetaVarName<"<name>">,
      HelpText<"Base name of framework searched for in -F directories">;
+def upward_framework : Separate<["-"], "upward_framework">,
+     MetaVarName<"<name>">,
+     HelpText<"Base name of upward framework searched for in -F directories">;
+def upward_library : Separate<["-"], "upward_library">,
+     MetaVarName<"<path>">,
+     HelpText<"path to upward dylib to link with">;
 def filelist : Separate<["-"], "filelist">,
      MetaVarName<"<path>">,
      HelpText<"file containing paths to input files">;

Modified: lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp?rev=219949&r1=219948&r2=219949&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp Thu Oct 16 14:31:28 2014
@@ -598,7 +598,7 @@ Writer &MachOLinkingContext::writer() co
 }
 
 MachODylibFile* MachOLinkingContext::loadIndirectDylib(StringRef path) {
-  std::unique_ptr<MachOFileNode> node(new MachOFileNode(path, false, *this));
+  std::unique_ptr<MachOFileNode> node(new MachOFileNode(path, *this));
   std::error_code ec = node->parse(*this, llvm::errs());
   if (ec)
     return nullptr;
@@ -668,15 +668,26 @@ bool MachOLinkingContext::createImplicit
 }
 
 
-void MachOLinkingContext::registerDylib(MachODylibFile *dylib) const {
+void MachOLinkingContext::registerDylib(MachODylibFile *dylib,
+                                        bool upward) const {
   _allDylibs.insert(dylib);
   _pathToDylibMap[dylib->installName()] = dylib;
   // If path is different than install name, register path too.
   if (!dylib->path().equals(dylib->installName()))
     _pathToDylibMap[dylib->path()] = dylib;
+  if (upward)
+    _upwardDylibs.insert(dylib);
 }
 
 
+bool MachOLinkingContext::isUpwardDylib(StringRef installName) const {
+  for (MachODylibFile *dylib : _upwardDylibs) {
+    if (dylib->installName().equals(installName))
+      return true;
+  }
+  return false;
+}
+
 ArchHandler &MachOLinkingContext::archHandler() const {
   if (!_archHandler)
     _archHandler = ArchHandler::create(_arch);

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp?rev=219949&r1=219948&r2=219949&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp Thu Oct 16 14:31:28 2014
@@ -808,7 +808,7 @@ std::error_code MachOFileLayout::writeLo
     for (const DependentDylib &dep : _file.dependentDylibs) {
       dylib_command* dc = reinterpret_cast<dylib_command*>(lc);
       uint32_t size = sizeof(dylib_command) + pointerAlign(dep.path.size()+1);
-      dc->cmd                         = LC_LOAD_DYLIB;
+      dc->cmd                         = dep.kind;
       dc->cmdsize                     = size;
       dc->dylib.name                  = sizeof(dylib_command); // offset
       dc->dylib.timestamp             = 0; // FIXME

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp?rev=219949&r1=219948&r2=219949&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp Thu Oct 16 14:31:28 2014
@@ -935,6 +935,8 @@ void Util::addDependentDylibs(const lld:
     DylibInfo &info = _dylibInfo[dep.path];
     if (info.hasWeak && !info.hasNonWeak)
       dep.kind = llvm::MachO::LC_LOAD_WEAK_DYLIB;
+    else if (_context.isUpwardDylib(dep.path))
+      dep.kind = llvm::MachO::LC_LOAD_UPWARD_DYLIB;
   }
 }
 

Added: lld/trunk/test/mach-o/Inputs/bar.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/Inputs/bar.yaml?rev=219949&view=auto
==============================================================================
--- lld/trunk/test/mach-o/Inputs/bar.yaml (added)
+++ lld/trunk/test/mach-o/Inputs/bar.yaml Thu Oct 16 14:31:28 2014
@@ -0,0 +1,18 @@
+
+--- !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:         [ 0xC3 ]
+global-symbols:
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000

Modified: lld/trunk/test/mach-o/libresolve-bizarre-root-override.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/libresolve-bizarre-root-override.yaml?rev=219949&r1=219948&r2=219949&view=diff
==============================================================================
--- lld/trunk/test/mach-o/libresolve-bizarre-root-override.yaml (original)
+++ lld/trunk/test/mach-o/libresolve-bizarre-root-override.yaml Thu Oct 16 14:31:28 2014
@@ -14,4 +14,4 @@
 # CHECK: Library search paths:
 # CHECK:     /usr/lib
 # CHECK-NOT:     /usr/local/lib
-# CHECK: Unable to find library -lSystem
+# CHECK: Unable to find library for -lSystem

Added: lld/trunk/test/mach-o/upward-dylib-load-command.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/upward-dylib-load-command.yaml?rev=219949&view=auto
==============================================================================
--- lld/trunk/test/mach-o/upward-dylib-load-command.yaml (added)
+++ lld/trunk/test/mach-o/upward-dylib-load-command.yaml Thu Oct 16 14:31:28 2014
@@ -0,0 +1,48 @@
+# RUN: lld -flavor darwin -arch x86_64 -dylib %p/Inputs/bar.yaml \
+# RUN:     -install_name /usr/lib/libbar.dylib %p/Inputs/libSystem.yaml -o %t1.dylib
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -upward_library  %t1.dylib \
+# RUN:      -install_name /usr/lib/libfoo.dylib %p/Inputs/libSystem.yaml -o %t 
+# RUN: llvm-objdump -private-headers %t | FileCheck %s
+#
+#
+# Test upward linking: 1) build libbar.dylib, 2) build libfoo.dylib and upward
+# like with libbar.dylib, 3) dump load commands of libfoo and verify upward link.
+#
+
+--- !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:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xE9, 
+                       0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000008
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK:	              cmd LC_LOAD_UPWARD_DYLIB
+# CHECK-NEXT:	      cmdsize 48
+# CHECK-NEXT:	         name /usr/lib/libbar.dylib (offset 24)

Added: lld/trunk/test/mach-o/upward-dylib-paths.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/upward-dylib-paths.yaml?rev=219949&view=auto
==============================================================================
--- lld/trunk/test/mach-o/upward-dylib-paths.yaml (added)
+++ lld/trunk/test/mach-o/upward-dylib-paths.yaml Thu Oct 16 14:31:28 2014
@@ -0,0 +1,18 @@
+#
+#
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN:        -path_exists /Custom/Frameworks \
+# RUN:        -path_exists /Custom/Frameworks/Bar.framework/Bar \
+# RUN:        -path_exists /usr/lib \
+# RUN:        -path_exists /usr/lib/libfoo.dylib \
+# RUN:        -path_exists /opt/stuff/libstuff.dylib \
+# RUN:        -F/Custom/Frameworks \
+# RUN:        -upward_framework Bar \
+# RUN:        -upward-lfoo \
+# RUN:        -upward_library /opt/stuff/libstuff.dylib \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Found upward framework /Custom/Frameworks/Bar.framework/Bar
+# CHECK: Found upward library /usr/lib/libfoo.dylib
+
+





More information about the llvm-commits mailing list