[lld] r215605 - [mach-o] Support re-exported dylibs

Nick Kledzik kledzik at apple.com
Wed Aug 13 16:55:41 PDT 2014


Author: kledzik
Date: Wed Aug 13 18:55:41 2014
New Revision: 215605

URL: http://llvm.org/viewvc/llvm-project?rev=215605&view=rev
Log:
[mach-o] Support re-exported dylibs

In general two-level namespace means each program records exactly which dylib
each undefined (imported) symbol comes from.  But, sometimes the implementor
wants to hide the implementation dylib.  For instance libSytem.dylib is the base
dylib all Darwin programs must link with.  A few years ago it was split up
into two dozen dylibs by all are hidden behind libSystem.dylib which re-exports
each sub-dylib.  All clients still think libSystem.dylib is the implementor.

To support this, the linker must load "indirect" dylibs and not just the
"direct" dylibs specified on the command line.  This is done in the
createImplicitFiles() method after all command line specified files are
loaded.  Since an indirect dylib may have already been loaded as a direct dylib
(or indirectly via a previous direct dylib), the MachOLinkingContext keeps
a list of all loaded dylibs.

With this change hello world can now be linked against the real OS or SDK.

Added:
    lld/trunk/test/mach-o/re-exported-dylib-ordinal.yaml
Modified:
    lld/trunk/include/lld/Driver/DarwinInputGraph.h
    lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
    lld/trunk/include/lld/ReaderWriter/Reader.h
    lld/trunk/lib/Driver/DarwinLdDriver.cpp
    lld/trunk/lib/Driver/DarwinLdOptions.td
    lld/trunk/lib/ReaderWriter/MachO/Atoms.h
    lld/trunk/lib/ReaderWriter/MachO/File.h
    lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp

Modified: lld/trunk/include/lld/Driver/DarwinInputGraph.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Driver/DarwinInputGraph.h?rev=215605&r1=215604&r2=215605&view=diff
==============================================================================
--- lld/trunk/include/lld/Driver/DarwinInputGraph.h (original)
+++ lld/trunk/include/lld/Driver/DarwinInputGraph.h Wed Aug 13 18:55:41 2014
@@ -19,6 +19,7 @@
 
 #include "lld/Core/InputGraph.h"
 #include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/SharedLibraryFile.h"
 #include "lld/ReaderWriter/MachOLinkingContext.h"
 
 #include <map>
@@ -28,7 +29,7 @@ namespace lld {
 /// \brief Represents a MachO File
 class MachOFileNode : public FileNode {
 public:
-  MachOFileNode(MachOLinkingContext &, StringRef path, bool isWholeArchive)
+  MachOFileNode(StringRef path, bool isWholeArchive)
       : FileNode(path), _isWholeArchive(isWholeArchive) {}
 
   /// \brief Parse the input file to lld::File.
@@ -44,8 +45,8 @@ public:
     if (ctx.logInputFiles())
       diagnostics << *filePath << "\n";
 
+    std::vector<std::unique_ptr<File>> parsedFiles;
     if (_isWholeArchive) {
-      std::vector<std::unique_ptr<File>> parsedFiles;
       std::error_code ec = ctx.registry().parseFile(_buffer, parsedFiles);
       if (ec)
         return ec;
@@ -62,7 +63,17 @@ public:
         return std::error_code();
       }
     }
-    return ctx.registry().parseFile(_buffer, _files);
+    if (std::error_code ec = ctx.registry().parseFile(_buffer, parsedFiles))
+      return ec;
+    for (std::unique_ptr<File> &pf : parsedFiles) {
+      // If a dylib was parsed, inform LinkingContext about it.
+      if (SharedLibraryFile *shl = dyn_cast<SharedLibraryFile>(pf.get())) {
+        MachOLinkingContext *mctx = (MachOLinkingContext*)(&ctx);
+        mctx->registerDylib(reinterpret_cast<mach_o::MachODylibFile*>(shl));
+      }
+      _files.push_back(std::move(pf));
+    }
+    return std::error_code();
   }
 
   /// \brief Return the file that has to be processed by the resolver

Modified: lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h?rev=215605&r1=215604&r2=215605&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h Wed Aug 13 18:55:41 2014
@@ -14,6 +14,7 @@
 #include "lld/ReaderWriter/Reader.h"
 #include "lld/ReaderWriter/Writer.h"
 
+#include "llvm/ADT/StringMap.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MachO.h"
 
@@ -25,6 +26,7 @@ namespace lld {
 
 namespace mach_o {
 class ArchHandler; 
+class MachODylibFile;
 }
 
 class MachOLinkingContext : public LinkingContext {
@@ -56,6 +58,7 @@ public:
 
   void addPasses(PassManager &pm) override;
   bool validateImpl(raw_ostream &diagnostics) override;
+  bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) const override;
 
   uint32_t getCPUType() const;
   uint32_t getCPUSubType() const;
@@ -82,6 +85,8 @@ public:
   bool printAtoms() const { return _printAtoms; }
   bool testingLibResolution() const { return _testingLibResolution; }
   const StringRefVector &searchDirs() const { return _searchDirs; }
+  void addSysLibRoot(StringRef sysPath) { _syslibRoots.push_back(sysPath); }
+  const StringRefVector &sysLibRoots() const { return _syslibRoots; }
 
   /// \brief Checks whether a given path on the filesystem exists.
   ///
@@ -96,9 +101,7 @@ public:
   /// The set of paths added consists of approximately all syslibroot-prepended
   /// versions of libPath that exist, or the original libPath if there are none
   /// for whatever reason. With various edge-cases for compatibility.
-  void addModifiedSearchDir(StringRef libPath,
-                            const StringRefVector &syslibRoots,
-                            bool isSystemPath = false);
+  void addModifiedSearchDir(StringRef libPath, bool isSystemPath = false);
 
   /// \brief Determine whether -lFoo can be resolve within the given path, and
   /// return the filename if so.
@@ -177,12 +180,20 @@ public:
   /// Stub creation Pass should be run.
   bool needsStubsPass() const;
 
-  // GOT createion Pass should be run.
+  // GOT creation Pass should be run.
   bool needsGOTPass() const;
 
   /// Magic symbol name stubs will need to help lazy bind.
   StringRef binderSymbolName() const;
 
+  /// Used to keep track of direct and indirect dylibs.
+  void registerDylib(mach_o::MachODylibFile *dylib);
+
+  /// Used to find indirect dylibs. Instantiates a MachODylibFile if one
+  /// has not already been made for the requested dylib.  Uses -L and -F
+  /// search paths to allow indirect dylibs to be overridden.
+  mach_o::MachODylibFile* findIndirectDylib(StringRef path) const;
+
   static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype);
   static Arch archFromName(StringRef archName);
   static StringRef nameFromArch(Arch arch);
@@ -198,6 +209,8 @@ public:
 
 private:
   Writer &writer() const override;
+  mach_o::MachODylibFile* loadIndirectDylib(StringRef path) const;
+
 
   struct ArchInfo {
     StringRef                 archName;
@@ -217,6 +230,7 @@ private:
 
   std::set<StringRef> _existingPaths; // For testing only.
   StringRefVector _searchDirs;
+  StringRefVector _syslibRoots;
   HeaderFileType _outputMachOType;   // e.g MH_EXECUTE
   bool _outputMachOTypeStatic; // Disambiguate static vs dynamic prog
   bool _doNothing;            // for -help and -v which just print info
@@ -235,6 +249,9 @@ private:
   mutable std::unique_ptr<mach_o::ArchHandler> _archHandler;
   mutable std::unique_ptr<Writer> _writer;
   std::vector<SectionAlign> _sectAligns;
+  llvm::StringMap<mach_o::MachODylibFile*> _pathToDylibMap;
+  std::set<mach_o::MachODylibFile*> _allDylibs;
+  mutable std::vector<std::unique_ptr<class MachOFileNode>> _indirectDylibs;
 };
 
 } // end namespace lld

Modified: lld/trunk/include/lld/ReaderWriter/Reader.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/Reader.h?rev=215605&r1=215604&r2=215605&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/Reader.h (original)
+++ lld/trunk/include/lld/ReaderWriter/Reader.h Wed Aug 13 18:55:41 2014
@@ -123,7 +123,7 @@ public:
   void addSupportNativeObjects();
   void addSupportCOFFObjects(PECOFFLinkingContext &);
   void addSupportCOFFImportLibraries();
-  void addSupportMachOObjects(const MachOLinkingContext &);
+  void addSupportMachOObjects(MachOLinkingContext &);
   void addSupportELFObjects(bool atomizeStrings, TargetHandlerBase *handler);
   void addSupportELFDynamicSharedObjects(bool useShlibUndefines,
                                          TargetHandlerBase *handler);

Modified: lld/trunk/lib/Driver/DarwinLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdDriver.cpp?rev=215605&r1=215604&r2=215605&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/DarwinLdDriver.cpp Wed Aug 13 18:55:41 2014
@@ -321,26 +321,25 @@ bool DarwinLdDriver::parse(int argc, con
   //      skipped.
   //   3. If the last -syslibroot is "/", all of them are ignored entirely.
   //   4. If { syslibroots } x path ==  {}, the original path is kept.
-  std::vector<StringRef> syslibRoots;
   for (auto syslibRoot : parsedArgs->filtered(OPT_syslibroot)) {
-    syslibRoots.push_back(syslibRoot->getValue());
+    ctx.addSysLibRoot(syslibRoot->getValue());
   }
 
   // Paths specified with -L come first, and are not considered system paths for
   // the case where there is precisely 1 -syslibroot.
   for (auto libPath : parsedArgs->filtered(OPT_L)) {
-    ctx.addModifiedSearchDir(libPath->getValue(), syslibRoots, false);
+    ctx.addModifiedSearchDir(libPath->getValue());
   }
 
   // -Z suppresses the standard search paths.
   if (!parsedArgs->hasArg(OPT_Z)) {
-    ctx.addModifiedSearchDir("/usr/lib", syslibRoots, true);
-    ctx.addModifiedSearchDir("/usr/local/lib", syslibRoots, true);
+    ctx.addModifiedSearchDir("/usr/lib", true);
+    ctx.addModifiedSearchDir("/usr/local/lib", true);
   }
 
   // Now that we've constructed the final set of search paths, print out what
   // we'll be using for testing purposes.
-  if (ctx.testingLibResolution()) {
+  if (ctx.testingLibResolution() || parsedArgs->getLastArg(OPT_v)) {
     diagnostics << "Library search paths:\n";
     for (auto path : ctx.searchDirs()) {
       diagnostics << "    " << path << '\n';
@@ -373,7 +372,7 @@ bool DarwinLdDriver::parse(int argc, con
     }
     }
     inputGraph->addInputElement(std::unique_ptr<InputElement>(
-        new MachOFileNode(ctx, inputPath, globalWholeArchive)));
+        new MachOFileNode(inputPath, globalWholeArchive)));
   }
 
   if (!inputGraph->size()) {

Modified: lld/trunk/lib/Driver/DarwinLdOptions.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdOptions.td?rev=215605&r1=215604&r2=215605&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdOptions.td (original)
+++ lld/trunk/lib/Driver/DarwinLdOptions.td Wed Aug 13 18:55:41 2014
@@ -96,6 +96,8 @@ def sectalign : MultiArg<["-"], "sectali
                 HelpText<"alignment for segment/section">;
 def t : Flag<["-"], "t">,
      HelpText<"Print the names of the input files as ld processes them">;
+def v : Flag<["-"], "v">,
+     HelpText<"Print linker information">;
 
 
 // extras

Modified: lld/trunk/lib/ReaderWriter/MachO/Atoms.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/Atoms.h?rev=215605&r1=215604&r2=215605&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/Atoms.h (original)
+++ lld/trunk/lib/ReaderWriter/MachO/Atoms.h Wed Aug 13 18:55:41 2014
@@ -123,7 +123,7 @@ private:
 class MachOSharedLibraryAtom : public SharedLibraryAtom {
 public:
   MachOSharedLibraryAtom(const File &file, StringRef name,
-                         StringRef dylibInstallName)
+                         StringRef dylibInstallName, bool weakDef)
       : SharedLibraryAtom(), _file(file), _name(name),
         _dylibInstallName(dylibInstallName) {}
   virtual ~MachOSharedLibraryAtom() {}

Modified: lld/trunk/lib/ReaderWriter/MachO/File.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/File.h?rev=215605&r1=215604&r2=215605&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/File.h (original)
+++ lld/trunk/lib/ReaderWriter/MachO/File.h Wed Aug 13 18:55:41 2014
@@ -175,22 +175,16 @@ private:
 
 class MachODylibFile : public SharedLibraryFile {
 public:
-  MachODylibFile(StringRef path) : SharedLibraryFile(path), _dylib_name(path) {}
-
-  virtual const SharedLibraryAtom *exports(StringRef name,
-                                           bool dataSymbolOnly) const {
-    // FIXME: we obviously need to record code/data if we're going to make
-    // proper use of dataSymbolOnly.
-    auto sym = _nameToAtom.find(name);
-
-    if (sym == _nameToAtom.end())
-      return nullptr;
-
-    if (!sym->second)
-      sym->second =
-          new (_allocator) MachOSharedLibraryAtom(*this, name, _dylib_name);
+  MachODylibFile(StringRef path, StringRef installName)
+      : SharedLibraryFile(path), _installName(installName) {
+  }
 
-    return sym->second;
+  virtual const SharedLibraryAtom *exports(StringRef name, bool isData) const {
+    // Pass down _installName and _allocator so that if this requested symbol
+    // is re-exported through this dylib, the SharedLibraryAtom's loadName()
+    // is this dylib installName and not the implementation dylib's.
+    // NOTE: isData is not needed for dylibs (it matters for static libs).
+    return exports(name, _installName, _allocator);
   }
 
   const atom_collection<DefinedAtom> &defined() const override {
@@ -209,22 +203,78 @@ public:
     return _absoluteAtoms;
   }
 
-  void addSharedLibraryAtom(StringRef name, bool copyRefs) {
+  /// Adds symbol name that this dylib exports. The corresponding
+  /// SharedLibraryAtom is created lazily (since most symbols are not used).
+  void addExportedSymbol(StringRef name, bool weakDef, bool copyRefs) {
     if (copyRefs) {
       name = name.copy(_allocator);
     }
+    AtomAndFlags info(weakDef);
+    _nameToAtom[name] = info;
+  }
 
-    _nameToAtom[name] = nullptr;
+  void addReExportedDylib(StringRef dylibPath) {
+    _reExportedDylibs.emplace_back(dylibPath);
+  }
+
+  StringRef installName() { return _installName; }
+
+  typedef std::function<MachODylibFile *(StringRef)> FindDylib;
+
+  void loadReExportedDylibs(FindDylib find) {
+    for (ReExportedDylib &entry : _reExportedDylibs) {
+      entry.file = find(entry.path);
+    }
   }
 
 private:
-  StringRef _dylib_name;
+  const SharedLibraryAtom *exports(StringRef name, StringRef installName,
+                                   llvm::BumpPtrAllocator &allocator) const {
+    // First, check if requested symbol is directly implemented by this dylib.
+    auto entry = _nameToAtom.find(name);
+    if (entry != _nameToAtom.end()) {
+      if (!entry->second.atom) {
+        // Lazily create SharedLibraryAtom.
+        entry->second.atom =
+          new (allocator) MachOSharedLibraryAtom(*this, name, installName,
+                                                 entry->second.weakDef);
+      }
+      return entry->second.atom;
+    }
+
+    // Next, check if symbol is implemented in some re-exported dylib.
+    for (const ReExportedDylib &dylib : _reExportedDylibs) {
+      assert(dylib.file);
+      auto atom = dylib.file->exports(name, installName, allocator);
+      if (atom)
+        return atom;
+    }
+
+    // Symbol not exported or re-exported by this dylib.
+    return nullptr;
+  }
+
+
+  struct ReExportedDylib {
+    ReExportedDylib(StringRef p) : path(p), file(nullptr) { }
+    StringRef       path;
+    MachODylibFile *file;
+  };
+
+  struct AtomAndFlags {
+    AtomAndFlags() : atom(nullptr), weakDef(false) { }
+    AtomAndFlags(bool weak) : atom(nullptr), weakDef(weak) { }
+    const SharedLibraryAtom  *atom;
+    bool                      weakDef;
+  };
+
+  StringRef _installName;
   atom_collection_vector<DefinedAtom>        _definedAtoms;
   atom_collection_vector<UndefinedAtom>      _undefinedAtoms;
   atom_collection_vector<SharedLibraryAtom>  _sharedLibraryAtoms;
   atom_collection_vector<AbsoluteAtom>       _absoluteAtoms;
-
-  mutable std::unordered_map<StringRef, SharedLibraryAtom *> _nameToAtom;
+  std::vector<ReExportedDylib>               _reExportedDylibs;
+  mutable std::unordered_map<StringRef, AtomAndFlags> _nameToAtom;
   mutable llvm::BumpPtrAllocator _allocator;
 };
 

Modified: lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp?rev=215605&r1=215604&r2=215605&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp Wed Aug 13 18:55:41 2014
@@ -10,9 +10,11 @@
 #include "lld/ReaderWriter/MachOLinkingContext.h"
 
 #include "ArchHandler.h"
+#include "File.h"
 #include "MachOPasses.h"
 
 #include "lld/Core/PassManager.h"
+#include "lld/Driver/DarwinInputGraph.h"
 #include "lld/ReaderWriter/Reader.h"
 #include "lld/ReaderWriter/Writer.h"
 #include "lld/Passes/LayoutPass.h"
@@ -28,6 +30,7 @@
 #include <algorithm>
 
 using lld::mach_o::ArchHandler;
+using lld::mach_o::MachODylibFile;
 using namespace llvm::MachO;
 
 namespace lld {
@@ -304,16 +307,16 @@ bool MachOLinkingContext::pathExists(Str
   return _existingPaths.find(key) != _existingPaths.end();
 }
 
-void MachOLinkingContext::addModifiedSearchDir(
-    StringRef libPath, const StringRefVector &syslibRoots, bool isSystemPath) {
+void MachOLinkingContext::addModifiedSearchDir(StringRef libPath,
+                                               bool isSystemPath) {
   bool addedModifiedPath = false;
 
   // Two cases to consider here:
   //   + If the last -syslibroot is "/", all of them are ignored (don't ask).
   //   + -syslibroot only applies to absolute paths.
-  if (!syslibRoots.empty() && syslibRoots.back() != "/" &&
+  if (!_syslibRoots.empty() && _syslibRoots.back() != "/" &&
       libPath.startswith("/")) {
-    for (auto syslibRoot : syslibRoots) {
+    for (auto syslibRoot : _syslibRoots) {
       SmallString<256> path(syslibRoot);
       llvm::sys::path::append(path, libPath);
       if (pathExists(path)) {
@@ -328,7 +331,7 @@ void MachOLinkingContext::addModifiedSea
 
   // Finally, if only one -syslibroot is given, system paths which aren't in it
   // get suppressed.
-  if (syslibRoots.size() != 1 || !isSystemPath) {
+  if (_syslibRoots.size() != 1 || !isSystemPath) {
     if (pathExists(libPath)) {
       _searchDirs.push_back(libPath);
     }
@@ -419,6 +422,86 @@ Writer &MachOLinkingContext::writer() co
   return *_writer;
 }
 
+MachODylibFile* MachOLinkingContext::loadIndirectDylib(StringRef path) const {
+  std::unique_ptr<MachOFileNode> node(new MachOFileNode(path, false));
+  std::error_code ec = node->parse(*this, llvm::errs());
+  if (ec)
+    return nullptr;
+
+  assert(node->files().size() == 1 && "expected one file in dylib");
+  // lld::File object is owned by MachOFileNode object. This method returns
+  // an unowned pointer to the lld::File object.
+  MachODylibFile* result = reinterpret_cast<MachODylibFile*>(
+                                                   node->files().front().get());
+
+  // Node object now owned by _indirectDylibs vector.
+  _indirectDylibs.push_back(std::move(node));
+
+  return result;
+}
+
+
+MachODylibFile* MachOLinkingContext::findIndirectDylib(StringRef path) const {
+  // See if already loaded.
+  auto pos = _pathToDylibMap.find(path);
+  if (pos != _pathToDylibMap.end())
+    return pos->second;
+
+  // Search -L paths if of the form "libXXX.dylib"
+  std::pair<StringRef, StringRef> split = path.rsplit('/');
+  StringRef leafName = split.second;
+  if (leafName.startswith("lib") && leafName.endswith(".dylib")) {
+    // FIXME: Need to enhance searchLibrary() to only look for .dylib
+    auto libPath = searchLibrary(leafName);
+    if (!libPath.getError()) {
+      return loadIndirectDylib(libPath.get());
+    }
+  }
+
+  // Try full path with sysroot.
+  for (StringRef sysPath : _syslibRoots) {
+    SmallString<256> fullPath;
+    fullPath.assign(sysPath);
+    llvm::sys::path::append(fullPath, path);
+    if (pathExists(fullPath))
+      return loadIndirectDylib(fullPath);
+  }
+
+  // Try full path.
+  if (pathExists(path)) {
+    return loadIndirectDylib(path);
+  }
+
+  return nullptr;
+}
+
+bool MachOLinkingContext::createImplicitFiles(
+                            std::vector<std::unique_ptr<File> > &result) const {
+  // Add indirect dylibs by asking each linked dylib to add its indirects.
+  // Iterate until no more dylibs get loaded.
+  size_t dylibCount = 0;
+  while (dylibCount != _allDylibs.size()) {
+    dylibCount = _allDylibs.size();
+    for (MachODylibFile *dylib : _allDylibs) {
+      dylib->loadReExportedDylibs([this] (StringRef path) -> MachODylibFile* {
+                                  return findIndirectDylib(path); });
+    }
+  }
+
+  // Let writer add output type specific extras.
+  return writer().createImplicitFiles(result);
+}
+
+
+void MachOLinkingContext::registerDylib(MachODylibFile *dylib) {
+  _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;
+}
+
+
 ArchHandler &MachOLinkingContext::archHandler() const {
   if (!_archHandler)
     _archHandler = ArchHandler::create(_arch);

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp?rev=215605&r1=215604&r2=215605&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp Wed Aug 13 18:55:41 2014
@@ -28,6 +28,7 @@
 
 #include "lld/Core/Error.h"
 #include "lld/Core/LLVM.h"
+#include "lld/Core/SharedLibraryFile.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSwitch.h"
@@ -233,8 +234,9 @@ readBinary(std::unique_ptr<MemoryBuffer>
   uint32_t dataInCodeSize = 0;
   ec = forEachLoadCommand(lcRange, lcCount, swap, is64,
                     [&] (uint32_t cmd, uint32_t size, const char* lc) -> bool {
-    if (is64) {
-      if (cmd == LC_SEGMENT_64) {
+    switch(cmd) {
+    case LC_SEGMENT_64:
+      if (is64) {
         const segment_command_64 *seg =
                               reinterpret_cast<const segment_command_64*>(lc);
         const unsigned sectionCount = (swap
@@ -276,8 +278,9 @@ readBinary(std::unique_ptr<MemoryBuffer>
           f->sections.push_back(section);
         }
       }
-    } else {
-      if (cmd == LC_SEGMENT) {
+      break;
+    case LC_SEGMENT:
+      if (!is64) {
         const segment_command *seg =
                               reinterpret_cast<const segment_command*>(lc);
         const unsigned sectionCount = (swap
@@ -319,8 +322,8 @@ readBinary(std::unique_ptr<MemoryBuffer>
           f->sections.push_back(section);
         }
       }
-    }
-    if (cmd == LC_SYMTAB) {
+      break;
+    case LC_SYMTAB: {
       const symtab_command *st = reinterpret_cast<const symtab_command*>(lc);
       const char *strings = start + read32(swap, st->stroff);
       const uint32_t strSize = read32(swap, st->strsize);
@@ -389,15 +392,31 @@ readBinary(std::unique_ptr<MemoryBuffer>
             f->localSymbols.push_back(sout);
         }
       }
-    } else if (cmd == LC_ID_DYLIB) {
+      }
+      break;
+    case LC_ID_DYLIB: {
       const dylib_command *dl = reinterpret_cast<const dylib_command*>(lc);
       f->installName = lc + read32(swap, dl->dylib.name);
-    } else if (cmd == LC_DATA_IN_CODE) {
+      }
+      break;
+    case LC_DATA_IN_CODE: {
       const linkedit_data_command *ldc =
                             reinterpret_cast<const linkedit_data_command*>(lc);
       dataInCode = reinterpret_cast<const data_in_code_entry*>(
                                             start + read32(swap, ldc->dataoff));
       dataInCodeSize = read32(swap, ldc->datasize);
+      }
+    case LC_LOAD_DYLIB:
+    case LC_LOAD_WEAK_DYLIB:
+    case LC_REEXPORT_DYLIB:
+    case LC_LOAD_UPWARD_DYLIB: {
+      const dylib_command *dl = reinterpret_cast<const dylib_command*>(lc);
+      DependentDylib entry;
+      entry.path = lc + read32(swap, dl->dylib.name);
+      entry.kind = LoadCommandType(cmd);
+      f->dependentDylibs.push_back(entry);
+      }
+      break;
     }
     return false;
   });
@@ -422,7 +441,7 @@ readBinary(std::unique_ptr<MemoryBuffer>
 
 class MachOReader : public Reader {
 public:
-  MachOReader(MachOLinkingContext::Arch arch) : _arch(arch) {}
+  MachOReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
 
   bool canParse(file_magic magic, StringRef ext,
                 const MemoryBuffer &mb) const override {
@@ -437,7 +456,7 @@ public:
   parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry &registry,
             std::vector<std::unique_ptr<File>> &result) const override {
     // Convert binary file to normalized mach-o.
-    auto normFile = readBinary(mb, _arch);
+    auto normFile = readBinary(mb, _ctx.arch());
     if (std::error_code ec = normFile.getError())
       return ec;
     // Convert normalized mach-o to atoms.
@@ -450,16 +469,16 @@ public:
     return std::error_code();
   }
 private:
-  MachOLinkingContext::Arch _arch;
+  MachOLinkingContext &_ctx;
 };
 
 
 } // namespace normalized
 } // namespace mach_o
 
-void Registry::addSupportMachOObjects(const MachOLinkingContext &ctx) {
+void Registry::addSupportMachOObjects(MachOLinkingContext &ctx) {
   MachOLinkingContext::Arch arch = ctx.arch();
-  add(std::unique_ptr<Reader>(new mach_o::normalized::MachOReader(arch)));
+  add(std::unique_ptr<Reader>(new mach_o::normalized::MachOReader(ctx)));
   addKindTable(Reference::KindNamespace::mach_o, ctx.archHandler().kindArch(), 
                ctx.archHandler().kindStrings());
   add(std::unique_ptr<YamlIOTaggedDocumentHandler>(

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp?rev=215605&r1=215604&r2=215605&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp Wed Aug 13 18:55:41 2014
@@ -671,12 +671,19 @@ normalizedObjectToAtoms(const Normalized
 ErrorOr<std::unique_ptr<lld::File>>
 normalizedDylibToAtoms(const NormalizedFile &normalizedFile, StringRef path,
                        bool copyRefs) {
+  // Instantiate SharedLibraryFile object.
   std::unique_ptr<MachODylibFile> file(
-      new MachODylibFile(normalizedFile.installName));
-
+                          new MachODylibFile(path, normalizedFile.installName));
+  // Tell MachODylibFile object about all symbols it exports.
   for (auto &sym : normalizedFile.globalSymbols) {
     assert((sym.scope & N_EXT) && "only expect external symbols here");
-    file->addSharedLibraryAtom(sym.name, copyRefs);
+    bool weakDef = (sym.desc & N_WEAK_DEF);
+    file->addExportedSymbol(sym.name, weakDef, copyRefs);
+  }
+  // Tell MachODylibFile object about all dylibs it re-exports.
+  for (const DependentDylib &dep : normalizedFile.dependentDylibs) {
+    if (dep.kind == llvm::MachO::LC_REEXPORT_DYLIB)
+      file->addReExportedDylib(dep.path);
   }
 
   return std::unique_ptr<File>(std::move(file));
@@ -715,6 +722,7 @@ normalizedToAtoms(const NormalizedFile &
                   bool copyRefs) {
   switch (normalizedFile.fileType) {
   case MH_DYLIB:
+  case MH_DYLIB_STUB:
     return normalizedDylibToAtoms(normalizedFile, path, copyRefs);
   case MH_OBJECT:
     return normalizedObjectToAtoms(normalizedFile, path, copyRefs);

Added: lld/trunk/test/mach-o/re-exported-dylib-ordinal.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/re-exported-dylib-ordinal.yaml?rev=215605&view=auto
==============================================================================
--- lld/trunk/test/mach-o/re-exported-dylib-ordinal.yaml (added)
+++ lld/trunk/test/mach-o/re-exported-dylib-ordinal.yaml Wed Aug 13 18:55:41 2014
@@ -0,0 +1,105 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -dylib -o %t \
+# RUN:  && llvm-nm -m %t | FileCheck %s
+#
+# Test that when one dylib A re-exports dylib B that using a symbol from B
+# gets recorded as coming from A.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+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:            _test
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ MH_TWOLEVEL ]
+install-name:    /junk/libfoo.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000F9A
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3 ]
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000F9A
+dependents:
+  - path:            /junk/libbar.dylib
+    kind:            LC_REEXPORT_DYLIB
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ MH_TWOLEVEL ]
+install-name:    /junk/libbar.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000F9A
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3 ]
+global-symbols:
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000F9A
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ MH_TWOLEVEL ]
+install-name:    /usr/lib/libSystem.B.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55 ]
+
+global-symbols:
+  - name:            dyld_stub_binder
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+...
+
+# CHECK:	(undefined) external _bar (from libfoo)
+# CHECK:	(undefined) external dyld_stub_binder (from libSystem)





More information about the llvm-commits mailing list