[lld] r217066 - [mach-o] Add support for using export tries

Nick Kledzik kledzik at apple.com
Wed Sep 3 12:52:51 PDT 2014


Author: kledzik
Date: Wed Sep  3 14:52:50 2014
New Revision: 217066

URL: http://llvm.org/viewvc/llvm-project?rev=217066&view=rev
Log:
[mach-o] Add support for using export tries

On Darwin at runtime, dyld will prefer to use the export trie of a dylib instead
of the traditional symbol table (which is large and requires a binary search).

This change enables the linker to generate an export trie and to prefer it if
found in a dylib being linked against.  This also simples the yaml for dylibs
because the yaml form of the trie can be reduced to just a sequence of names.

Added:
    lld/trunk/test/mach-o/dylib-exports.yaml
Modified:
    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/hello-world-armv6.yaml
    lld/trunk/test/mach-o/hello-world-armv7.yaml
    lld/trunk/test/mach-o/hello-world-x86.yaml
    lld/trunk/test/mach-o/hello-world-x86_64.yaml

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp?rev=217066&r1=217065&r2=217066&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp Wed Sep  3 14:52:50 2014
@@ -33,6 +33,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Object/MachO.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -45,6 +46,8 @@
 #include <system_error>
 
 using namespace llvm::MachO;
+using llvm::object::ExportEntry;
+using llvm::object::MachOObjectFile;
 
 namespace lld {
 namespace mach_o {
@@ -231,6 +234,7 @@ readBinary(std::unique_ptr<MemoryBuffer>
 
   // Walk load commands looking for segments/sections and the symbol table.
   const data_in_code_entry *dataInCode = nullptr;
+  const dyld_info_command *dyldInfo = nullptr;
   uint32_t dataInCodeSize = 0;
   ec = forEachLoadCommand(lcRange, lcCount, swap, is64,
                     [&] (uint32_t cmd, uint32_t size, const char* lc) -> bool {
@@ -406,6 +410,7 @@ readBinary(std::unique_ptr<MemoryBuffer>
                                             start + read32(swap, ldc->dataoff));
       dataInCodeSize = read32(swap, ldc->datasize);
       }
+      break;
     case LC_LOAD_DYLIB:
     case LC_LOAD_WEAK_DYLIB:
     case LC_REEXPORT_DYLIB:
@@ -417,6 +422,10 @@ readBinary(std::unique_ptr<MemoryBuffer>
       f->dependentDylibs.push_back(entry);
       }
       break;
+    case LC_DYLD_INFO:
+    case LC_DYLD_INFO_ONLY:
+      dyldInfo = reinterpret_cast<const dyld_info_command*>(lc);
+      break;
     }
     return false;
   });
@@ -434,11 +443,30 @@ readBinary(std::unique_ptr<MemoryBuffer>
     }
   }
 
+  if (dyldInfo) {
+    // If any exports, extract and add to normalized exportInfo vector.
+    if (dyldInfo->export_size) {
+      const uint8_t *trieStart = reinterpret_cast<const uint8_t*>(start +
+                                                          dyldInfo->export_off);
+      ArrayRef<uint8_t> trie(trieStart, dyldInfo->export_size);
+      for (const ExportEntry &trieExport : MachOObjectFile::exports(trie)) {
+        Export normExport;
+        normExport.name = trieExport.name().copy(f->ownedAllocations);
+        normExport.offset = trieExport.address();
+        normExport.kind = ExportSymbolKind(trieExport.flags() & EXPORT_SYMBOL_FLAGS_KIND_MASK);
+        normExport.flags = trieExport.flags() & ~EXPORT_SYMBOL_FLAGS_KIND_MASK;
+        normExport.otherOffset = trieExport.other();
+        if (!trieExport.otherName().empty())
+          normExport.otherName = trieExport.otherName().copy(f->ownedAllocations);
+        f->exportInfo.push_back(normExport);
+      }
+    }
+  }
+
   return std::move(f);
 }
 
 
-
 class MachOReader : public Reader {
 public:
   MachOReader(MachOLinkingContext &ctx) : _ctx(ctx) {}

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp?rev=217066&r1=217065&r2=217066&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp Wed Sep  3 14:52:50 2014
@@ -33,6 +33,7 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Format.h"
 #include "llvm/Support/Host.h"
 #include "llvm/Support/LEB128.h"
 #include "llvm/Support/MachO.h"
@@ -77,12 +78,14 @@ private:
   void        writeRebaseInfo();
   void        writeBindingInfo();
   void        writeLazyBindingInfo();
+  void        writeExportInfo();
   void        writeDataInCodeInfo();
   void        writeLinkEditContent();
   void        buildLinkEditInfo();
   void        buildRebaseInfo();
   void        buildBindInfo();
   void        buildLazyBindInfo();
+  void        buildExportTrie();
   void        computeDataInCodeSize();
   void        computeSymbolTableSizes();
   void        buildSectionRelocations();
@@ -115,6 +118,7 @@ private:
   class ByteBuffer {
   public:
     ByteBuffer() : _ostream(_bytes) { }
+
     void append_byte(uint8_t b) {
       _ostream << b;
     }
@@ -144,6 +148,37 @@ private:
     llvm::raw_svector_ostream     _ostream;
   };
 
+  struct TrieNode; // Forward declaration.
+
+  struct TrieEdge {
+    TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {}
+    ~TrieEdge() {}
+
+    StringRef          _subString;
+    struct TrieNode   *_child;
+  };
+
+  struct TrieNode {
+    TrieNode(StringRef s)
+        : _cummulativeString(s), _address(0), _flags(0), _other(0),
+          _trieOffset(0), _hasExportInfo(false) {}
+    ~TrieNode() {}
+
+    void addSymbol(const Export &entry, BumpPtrAllocator &allocator,
+                   std::vector<TrieNode *> &allNodes);
+    bool updateOffset(uint32_t &offset);
+    void appendToByteBuffer(ByteBuffer &out);
+
+private:
+    StringRef                 _cummulativeString;
+    SmallVector<TrieEdge, 8>  _children;
+    uint64_t                  _address;
+    uint64_t                  _flags;
+    uint64_t                  _other;
+    StringRef                 _importedName;
+    uint32_t                  _trieOffset;
+    bool                      _hasExportInfo;
+  };
 
   struct SegExtraInfo {
     uint32_t                    fileOffset;
@@ -190,6 +225,8 @@ private:
   uint32_t              _endOfBindingInfo;
   uint32_t              _startOfLazyBindingInfo;
   uint32_t              _endOfLazyBindingInfo;
+  uint32_t              _startOfExportTrie;
+  uint32_t              _endOfExportTrie;
   uint32_t              _endOfLinkEdit;
   uint64_t              _addressOfLinkEdit;
   SegMap                _segInfo;
@@ -198,7 +235,7 @@ private:
   ByteBuffer            _bindingInfo;
   ByteBuffer            _lazyBindingInfo;
   ByteBuffer            _weakBindingInfo;
-  ByteBuffer            _exportInfo;
+  ByteBuffer            _exportTrie;
 };
 
 size_t headerAndLoadCommandsSize(const NormalizedFile &file) {
@@ -295,7 +332,9 @@ MachOFileLayout::MachOFileLayout(const N
     _endOfBindingInfo = _startOfBindingInfo + _bindingInfo.size();
     _startOfLazyBindingInfo = _endOfBindingInfo;
     _endOfLazyBindingInfo = _startOfLazyBindingInfo + _lazyBindingInfo.size();
-    _startOfDataInCode = _endOfLazyBindingInfo;
+    _startOfExportTrie = _endOfLazyBindingInfo;
+    _endOfExportTrie = _startOfExportTrie + _exportTrie.size();
+    _startOfDataInCode = _endOfExportTrie;
     _startOfSymbols = _startOfDataInCode + _dataInCodeSize;
     _startOfIndirectSymbols = _startOfSymbols + _symbolTableSize;
     _startOfSymbolStrings = _startOfIndirectSymbols
@@ -315,6 +354,8 @@ MachOFileLayout::MachOFileLayout(const N
       << "  endOfBindingInfo=" << _endOfBindingInfo << "\n"
       << "  startOfLazyBindingInfo=" << _startOfLazyBindingInfo << "\n"
       << "  endOfLazyBindingInfo=" << _endOfLazyBindingInfo << "\n"
+      << "  startOfExportTrie=" << _startOfExportTrie << "\n"
+      << "  endOfExportTrie=" << _endOfExportTrie << "\n"
       << "  startOfDataInCode=" << _startOfDataInCode << "\n"
       << "  startOfSymbols=" << _startOfSymbols << "\n"
       << "  startOfSymbolStrings=" << _startOfSymbolStrings << "\n"
@@ -685,8 +726,8 @@ std::error_code MachOFileLayout::writeLo
     di->weak_bind_size = 0;
     di->lazy_bind_off  = _lazyBindingInfo.size() ? _startOfLazyBindingInfo : 0;
     di->lazy_bind_size = _lazyBindingInfo.size();
-    di->export_off     = 0;
-    di->export_size    = 0;
+    di->export_off     = _exportTrie.size() ? _startOfExportTrie : 0;
+    di->export_size    = _exportTrie.size();
     if (_swap)
       swapStruct(*di);
     lc += sizeof(dyld_info_command);
@@ -897,10 +938,15 @@ void MachOFileLayout::writeLazyBindingIn
                             _lazyBindingInfo.bytes(), _lazyBindingInfo.size());
 }
 
+void MachOFileLayout::writeExportInfo() {
+  memcpy(&_buffer[_startOfExportTrie], _exportTrie.bytes(), _exportTrie.size());
+}
+
 void MachOFileLayout::buildLinkEditInfo() {
   buildRebaseInfo();
   buildBindInfo();
   buildLazyBindInfo();
+  buildExportTrie();
   computeSymbolTableSizes();
   computeDataInCodeSize();
 }
@@ -957,6 +1003,191 @@ void MachOFileLayout::buildLazyBindInfo(
   _lazyBindingInfo.align(_is64 ? 8 : 4);
 }
 
+void MachOFileLayout::TrieNode::addSymbol(const Export& entry,
+                                          BumpPtrAllocator &allocator,
+                                          std::vector<TrieNode*> &allNodes) {
+  StringRef partialStr = entry.name.drop_front(_cummulativeString.size());
+  for (TrieEdge &edge : _children) {
+    StringRef edgeStr = edge._subString;
+    if (partialStr.startswith(edgeStr)) {
+      // Already have matching edge, go down that path.
+      edge._child->addSymbol(entry, allocator, allNodes);
+      return;
+    }
+    // See if string has commmon prefix with existing edge.
+    for (int n=edgeStr.size()-1; n > 0; --n) {
+      if (partialStr.substr(0, n).equals(edgeStr.substr(0, n))) {
+        // Splice in new node:  was A -> C,  now A -> B -> C
+        StringRef bNodeStr = edge._child->_cummulativeString;
+        bNodeStr = bNodeStr.drop_back(edgeStr.size()-n).copy(allocator);
+        TrieNode* bNode = new (allocator) TrieNode(bNodeStr);
+        allNodes.push_back(bNode);
+        TrieNode* cNode = edge._child;
+        StringRef abEdgeStr = edgeStr.substr(0,n).copy(allocator);
+        StringRef bcEdgeStr = edgeStr.substr(n).copy(allocator);
+        DEBUG_WITH_TYPE("trie-builder", llvm::dbgs()
+                        << "splice in TrieNode('" << bNodeStr
+                        << "') between edge '"
+                        << abEdgeStr << "' and edge='"
+                        << bcEdgeStr<< "'\n");
+        TrieEdge& abEdge = edge;
+        abEdge._subString = abEdgeStr;
+        abEdge._child = bNode;
+        TrieEdge bcEdge(bcEdgeStr, cNode);
+        bNode->_children.push_back(bcEdge);
+        bNode->addSymbol(entry, allocator, allNodes);
+        return;
+      }
+    }
+  }
+  if (entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
+    assert(entry.otherOffset != 0);
+  }
+  if (entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) {
+    assert(entry.otherOffset != 0);
+  }
+  // No commonality with any existing child, make a new edge.
+  TrieNode* newNode = new (allocator) TrieNode(entry.name.copy(allocator));
+  TrieEdge newEdge(partialStr, newNode);
+  _children.push_back(newEdge);
+  DEBUG_WITH_TYPE("trie-builder", llvm::dbgs()
+                   << "new TrieNode('" << entry.name << "') with edge '"
+                   << partialStr << "' from node='"
+                   << _cummulativeString << "'\n");
+  newNode->_address = entry.offset;
+  newNode->_flags = entry.flags | entry.kind;
+  newNode->_other = entry.otherOffset;
+  if ((entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) && !entry.otherName.empty())
+    newNode->_importedName = entry.otherName.copy(allocator);
+  newNode->_hasExportInfo = true;
+  allNodes.push_back(newNode);
+}
+
+bool MachOFileLayout::TrieNode::updateOffset(uint32_t& offset) {
+  uint32_t nodeSize = 1; // Length when no export info
+  if (_hasExportInfo) {
+    if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
+      nodeSize = llvm::getULEB128Size(_flags);
+      nodeSize += llvm::getULEB128Size(_other); // Other contains ordinal.
+      nodeSize += _importedName.size();
+      ++nodeSize; // Trailing zero in imported name.
+    } else {
+      nodeSize = llvm::getULEB128Size(_flags) + llvm::getULEB128Size(_address);
+      if (_flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
+        nodeSize += llvm::getULEB128Size(_other);
+    }
+    // Overall node size so far is uleb128 of export info + actual export info.
+    nodeSize += llvm::getULEB128Size(nodeSize);
+  }
+  // Compute size of all child edges.
+  ++nodeSize; // Byte for number of chidren.
+  for (TrieEdge &edge : _children) {
+    nodeSize += edge._subString.size() + 1 // String length.
+              + llvm::getULEB128Size(edge._child->_trieOffset); // Offset len.
+  }
+  // On input, 'offset' is new prefered location for this node.
+  bool result = (_trieOffset != offset);
+  // Store new location in node object for use by parents.
+  _trieOffset = offset;
+  // Update offset for next iteration.
+  offset += nodeSize;
+  // Return true if _trieOffset was changed.
+  return result;
+}
+
+void MachOFileLayout::TrieNode::appendToByteBuffer(ByteBuffer &out) {
+  if (_hasExportInfo) {
+    if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
+      if (!_importedName.empty()) {
+        // nodes with re-export info: size, flags, ordinal, import-name
+        uint32_t nodeSize = llvm::getULEB128Size(_flags)
+                          + llvm::getULEB128Size(_other)
+                          + _importedName.size() + 1;
+        assert(nodeSize < 256);
+        out.append_byte(nodeSize);
+        out.append_uleb128(_flags);
+        out.append_uleb128(_other);
+        out.append_string(_importedName);
+      } else {
+        // nodes without re-export info: size, flags, ordinal, empty-string
+        uint32_t nodeSize = llvm::getULEB128Size(_flags)
+                          + llvm::getULEB128Size(_other) + 1;
+        assert(nodeSize < 256);
+        out.append_byte(nodeSize);
+        out.append_uleb128(_flags);
+        out.append_uleb128(_other);
+        out.append_byte(0);
+      }
+    } else if ( _flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
+      // Nodes with export info: size, flags, address, other
+      uint32_t nodeSize = llvm::getULEB128Size(_flags)
+                        + llvm::getULEB128Size(_address)
+                        + llvm::getULEB128Size(_other);
+      assert(nodeSize < 256);
+      out.append_byte(nodeSize);
+      out.append_uleb128(_flags);
+      out.append_uleb128(_address);
+      out.append_uleb128(_other);
+    } else {
+      // Nodes with export info: size, flags, address
+      uint32_t nodeSize = llvm::getULEB128Size(_flags)
+                        + llvm::getULEB128Size(_address);
+      assert(nodeSize < 256);
+      out.append_byte(nodeSize);
+      out.append_uleb128(_flags);
+      out.append_uleb128(_address);
+    }
+  } else {
+    // Node with no export info.
+    uint32_t nodeSize = 0;
+    out.append_byte(nodeSize);
+  }
+  // Add number of children.
+  assert(_children.size() < 256);
+  out.append_byte(_children.size());
+  // Append each child edge substring and node offset.
+  for (TrieEdge &edge : _children) {
+    out.append_string(edge._subString);
+    out.append_uleb128(edge._child->_trieOffset);
+  }
+}
+
+void MachOFileLayout::buildExportTrie() {
+  if (_file.exportInfo.empty())
+    return;
+
+  // For all temporary strings and objects used building trie.
+  BumpPtrAllocator allocator;
+
+  // Build trie of all exported symbols.
+  TrieNode* rootNode = new (allocator) TrieNode(StringRef());
+  std::vector<TrieNode*> allNodes;
+  allNodes.reserve(_file.exportInfo.size()*2);
+  allNodes.push_back(rootNode);
+  for (const Export& entry : _file.exportInfo) {
+    rootNode->addSymbol(entry, allocator, allNodes);
+  }
+
+  // Assign each node in the vector an offset in the trie stream, iterating
+  // until all uleb128 sizes have stabilized.
+  bool more;
+  do {
+    uint32_t offset = 0;
+    more = false;
+    for (TrieNode* node : allNodes) {
+      if (node->updateOffset(offset))
+        more = true;
+    }
+  } while (more);
+
+  // Serialize trie to ByteBuffer.
+  for (TrieNode* node : allNodes) {
+    node->appendToByteBuffer(_exportTrie);
+  }
+  _exportTrie.align(_is64 ? 8 : 4);
+}
+
+
 void MachOFileLayout::computeSymbolTableSizes() {
   // MachO symbol tables have three ranges: locals, globals, and undefines
   const size_t nlistSize = (_is64 ? sizeof(nlist_64) : sizeof(nlist));
@@ -998,6 +1229,7 @@ void MachOFileLayout::writeLinkEditConte
     writeBindingInfo();
     writeLazyBindingInfo();
     // TODO: add weak binding info
+    writeExportInfo();
     writeSymbolTable();
   }
 }

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp?rev=217066&r1=217065&r2=217066&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp Wed Sep  3 14:52:50 2014
@@ -109,6 +109,7 @@ public:
   std::error_code addSymbols(const lld::File &atomFile, NormalizedFile &file);
   void      addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file);
   void      addRebaseAndBindingInfo(const lld::File &, NormalizedFile &file);
+  void      addExportInfo(const lld::File &, NormalizedFile &file);
   void      addSectionRelocs(const lld::File &, NormalizedFile &file);
   void      buildDataInCodeArray(const lld::File &, NormalizedFile &file);
   void      addDependentDylibs(const lld::File &, NormalizedFile &file);
@@ -1085,6 +1086,35 @@ void Util::addRebaseAndBindingInfo(const
   }
 }
 
+
+void Util::addExportInfo(const lld::File &atomFile, NormalizedFile &nFile) {
+  if (_context.outputMachOType() == llvm::MachO::MH_OBJECT)
+    return;
+
+  for (SectionInfo *sect : _sectionInfos) {
+    for (const AtomInfo &info : sect->atomsAndOffsets) {
+      const DefinedAtom *atom = info.atom;
+      if (atom->scope() != Atom::scopeGlobal)
+        continue;
+      if (_context.exportRestrictMode()) {
+        if (!_context.exportSymbolNamed(atom->name()))
+          continue;
+      }
+      Export exprt;
+      exprt.name = atom->name();
+      exprt.offset = _atomToAddress[atom];   // FIXME: subtract base address
+      exprt.kind = EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
+      if (atom->merge() == DefinedAtom::mergeAsWeak)
+        exprt.flags = EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
+      else
+        exprt.flags = 0;
+      exprt.otherOffset = 0;
+      exprt.otherName = StringRef();
+      nFile.exportInfo.push_back(exprt);
+    }
+  }
+}
+
 uint32_t Util::fileFlags() {
   // FIXME: these need to determined at runtime.
   if (_context.outputMachOType() == MH_OBJECT) {
@@ -1128,6 +1158,7 @@ normalizedFromAtoms(const lld::File &ato
   }
   util.addIndirectSymbols(atomFile, normFile);
   util.addRebaseAndBindingInfo(atomFile, normFile);
+  util.addExportInfo(atomFile, normFile);
   util.addSectionRelocs(atomFile, normFile);
   util.buildDataInCodeArray(atomFile, normFile);
   util.copyEntryPointAddress(normFile);

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp?rev=217066&r1=217065&r2=217066&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp Wed Sep  3 14:52:50 2014
@@ -235,7 +235,7 @@ void atomFromSymbol(DefinedAtom::Content
     bool thumb = (symbolDescFlags & N_ARM_THUMB_DEF);
     if (atomType == DefinedAtom::typeUnknown) {
       // Mach-O needs a segment and section name.  Concatentate those two
-      // with a / seperator (e.g. "seg/sect") to fit into the lld model
+      // with a / separator (e.g. "seg/sect") to fit into the lld model
       // of just a section name.
       std::string segSectName = section.segmentName.str()
                                 + "/" + section.sectionName.str();
@@ -676,10 +676,19 @@ normalizedDylibToAtoms(const NormalizedF
   std::unique_ptr<MachODylibFile> file(
                           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");
-    bool weakDef = (sym.desc & N_WEAK_DEF);
-    file->addExportedSymbol(sym.name, weakDef, copyRefs);
+  if (!normalizedFile.exportInfo.empty()) {
+    // If exports trie exists, use it instead of traditional symbol table.
+    for (const Export &exp : normalizedFile.exportInfo) {
+      bool weakDef = (exp.flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
+      // StringRefs from export iterator are ephemeral, so force copy.
+      file->addExportedSymbol(exp.name, weakDef, true);
+    }
+  } else {
+    for (auto &sym : normalizedFile.globalSymbols) {
+      assert((sym.scope & N_EXT) && "only expect external symbols here");
+      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) {

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp?rev=217066&r1=217065&r2=217066&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp Wed Sep  3 14:52:50 2014
@@ -566,8 +566,10 @@ struct ScalarEnumerationTraits<ExportSym
   static void enumeration(IO &io, ExportSymbolKind &value) {
     io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_REGULAR",
                         llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
-    io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCALl",
+    io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL",
                         llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
+    io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE",
+                        llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
   }
 };
 
@@ -588,11 +590,12 @@ template <>
 struct MappingTraits<Export> {
   static void mapping(IO &io, Export &exp) {
     io.mapRequired("name",         exp.name);
-    io.mapRequired("offset",       exp.offset);
+    io.mapOptional("offset",       exp.offset);
     io.mapOptional("kind",         exp.kind,
                                 llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
-    io.mapOptional("flags",        exp.flags);
-    io.mapOptional("other-offset", exp.otherOffset, Hex32(0));
+    if (!io.outputting() || exp.flags)
+      io.mapOptional("flags",      exp.flags);
+    io.mapOptional("other",        exp.otherOffset, Hex32(0));
     io.mapOptional("other-name",   exp.otherName, StringRef());
   }
 };

Added: lld/trunk/test/mach-o/dylib-exports.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/dylib-exports.yaml?rev=217066&view=auto
==============================================================================
--- lld/trunk/test/mach-o/dylib-exports.yaml (added)
+++ lld/trunk/test/mach-o/dylib-exports.yaml Wed Sep  3 14:52:50 2014
@@ -0,0 +1,41 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN:      %s %p/Inputs/libSystem.yaml -o %t  && \
+# RUN: llvm-objdump -exports-trie %t | FileCheck %s
+#
+#
+# Tests that exports trie builds properly.
+#
+
+--- !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, 0xC3, 0xC3 ]
+global-symbols:
+  - name:            _myHidden
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _myRegular
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myWeak
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_WEAK_DEF ]
+    value:           0x0000000000000002
+...
+
+# CHECK-NOT:  _myHidden
+# CHECK:      _myRegular
+# CHECK:      _myWeak [weak_def]

Modified: lld/trunk/test/mach-o/hello-world-armv6.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/hello-world-armv6.yaml?rev=217066&r1=217065&r2=217066&view=diff
==============================================================================
--- lld/trunk/test/mach-o/hello-world-armv6.yaml (original)
+++ lld/trunk/test/mach-o/hello-world-armv6.yaml Wed Sep  3 14:52:50 2014
@@ -61,28 +61,10 @@ undefined-symbols:
 --- !mach-o
 arch:            armv6
 file-type:       MH_DYLIB
-flags:           [ ]
 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:
+exports:
   - name:            _printf
-    type:            N_SECT
-    scope:           [ N_EXT ]
-    sect:            1
-    value:           0x0000000000000001
   - name:            dyld_stub_binder
-    type:            N_SECT
-    scope:           [ N_EXT ]
-    sect:            1
-    value:           0x0000000000000001
-
 ...
 
 # CHECK:	{{[0-9a-f]+}} (__TEXT,__text) external _main

Modified: lld/trunk/test/mach-o/hello-world-armv7.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/hello-world-armv7.yaml?rev=217066&r1=217065&r2=217066&view=diff
==============================================================================
--- lld/trunk/test/mach-o/hello-world-armv7.yaml (original)
+++ lld/trunk/test/mach-o/hello-world-armv7.yaml Wed Sep  3 14:52:50 2014
@@ -74,28 +74,10 @@ undefined-symbols:
 --- !mach-o
 arch:            armv7
 file-type:       MH_DYLIB
-flags:           [ ]
 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:
+exports:
   - name:            _printf
-    type:            N_SECT
-    scope:           [ N_EXT ]
-    sect:            1
-    value:           0x0000000000000001
   - name:            dyld_stub_binder
-    type:            N_SECT
-    scope:           [ N_EXT ]
-    sect:            1
-    value:           0x0000000000000001
-
 ...
 
 # CHECK:	{{[0-9a-f]+}} (__TEXT,__text) external [Thumb] _main

Modified: lld/trunk/test/mach-o/hello-world-x86.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/hello-world-x86.yaml?rev=217066&r1=217065&r2=217066&view=diff
==============================================================================
--- lld/trunk/test/mach-o/hello-world-x86.yaml (original)
+++ lld/trunk/test/mach-o/hello-world-x86.yaml Wed Sep  3 14:52:50 2014
@@ -59,27 +59,10 @@ undefined-symbols:
 --- !mach-o
 arch:            x86
 file-type:       MH_DYLIB
-flags:           [ ]
 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:
+exports:
   - name:            _printf
-    type:            N_SECT
-    scope:           [ N_EXT ]
-    sect:            1
-    value:           0x0000000000000001
   - name:            dyld_stub_binder
-    type:            N_SECT
-    scope:           [ N_EXT ]
-    sect:            1
-    value:           0x0000000000000001
 
 ...
 

Modified: lld/trunk/test/mach-o/hello-world-x86_64.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/hello-world-x86_64.yaml?rev=217066&r1=217065&r2=217066&view=diff
==============================================================================
--- lld/trunk/test/mach-o/hello-world-x86_64.yaml (original)
+++ lld/trunk/test/mach-o/hello-world-x86_64.yaml Wed Sep  3 14:52:50 2014
@@ -112,32 +112,11 @@ undefined-symbols:
 --- !mach-o
 arch:            x86_64
 file-type:       MH_DYLIB
-flags:           [ ]
 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:
+exports:
   - name:            _fprintf
-    type:            N_SECT
-    scope:           [ N_EXT ]
-    sect:            1
-    value:           0x0000000000000000
   - name:            dyld_stub_binder
-    type:            N_SECT
-    scope:           [ N_EXT ]
-    sect:            1
-    value:           0x0000000000000000
   - name:            ___stdoutp
-    type:            N_SECT
-    scope:           [ N_EXT ]
-    sect:            1
-    value:           0x0000000000000000
 
 ...
 





More information about the llvm-commits mailing list