(no commit message)

llvm-svn: 150539
diff --git a/lld/lib/Core/NativeWriter.cpp b/lld/lib/Core/NativeWriter.cpp
index 09fdd9c..da877fd 100644
--- a/lld/lib/Core/NativeWriter.cpp
+++ b/lld/lib/Core/NativeWriter.cpp
@@ -12,6 +12,7 @@
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 
 #include "lld/Core/File.h"
 #include "lld/Core/NativeWriter.h"
@@ -25,10 +26,13 @@
 ///
 /// Class for writing native object files.
 ///
-class NativeWriter : public File::AtomHandler {
+class NativeWriter : public File::AtomHandler, 
+                     public DefinedAtom::ReferenceHandler {
 public:
   /// construct writer for an lld::File object
   NativeWriter(const lld::File& file) : _file(file) { 
+    // reserve first byte for unnamed atoms
+    _stringPool.push_back('\0');
     // visit all atoms
     _file.forEachAtom(*this);
     // construct file header based on atom information accumulated
@@ -37,36 +41,73 @@
 
   // write the lld::File in native format to the specified stream
   void write(llvm::raw_ostream& out) {
+    assert( out.tell() == 0 );
     out.write((char*)_headerBuffer, _headerBufferSize);
-    if (!_definedAtomIvars.empty())
+    
+    if (!_definedAtomIvars.empty()) {
+      assert( out.tell() == findChunk(NCS_DefinedAtomsV1).fileOffset );
       out.write((char*)&_definedAtomIvars[0],
                 _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1));
-    if (!_attributes.empty())
+    }
+    
+    if (!_attributes.empty()) {
+      assert( out.tell() == findChunk(NCS_AttributesArrayV1).fileOffset );
       out.write((char*)&_attributes[0],
                 _attributes.size()*sizeof(NativeAtomAttributesV1));
-    if ( !_undefinedAtomIvars.empty() ) 
+    }
+                
+    if ( !_undefinedAtomIvars.empty() ) {
+      assert( out.tell() == findChunk(NCS_UndefinedAtomsV1).fileOffset );
       out.write((char*)&_undefinedAtomIvars[0], 
               _undefinedAtomIvars.size()*sizeof(NativeUndefinedAtomIvarsV1));
-    if (!_stringPool.empty())
+    }
+              
+    if (!_stringPool.empty()) {
+      assert( out.tell() == findChunk(NCS_Strings).fileOffset );
       out.write(&_stringPool[0], _stringPool.size());
-    if (!_contentPool.empty())
+    }
+    
+    if ( !_references.empty() ) {
+      assert( out.tell() == findChunk(NCS_ReferencesArrayV1).fileOffset );
+      out.write((char*)&_references[0], 
+              _references.size()*sizeof(NativeReferenceIvarsV1));
+    }
+    
+    if ( !_targetsTableIndex.empty() ) {
+      assert( out.tell() == findChunk(NCS_TargetsTable).fileOffset );
+      writeTargetTable(out);
+    }
+  
+    if ( !_addendsTableIndex.empty() ) {
+      assert( out.tell() == findChunk(NCS_AddendsTable).fileOffset );
+      writeAddendTable(out);
+    }
+  
+    if (!_contentPool.empty()) {
+      assert( out.tell() == findChunk(NCS_Content).fileOffset );
       out.write((char*)&_contentPool[0], _contentPool.size());
+    }
   }
 
 private:
 
   // visitor routine called by forEachAtom() 
-  virtual void doDefinedAtom(const class DefinedAtom& atom) {
+  virtual void doDefinedAtom(const DefinedAtom& atom) {
+    _definedAtomIndex[&atom] = _definedAtomIvars.size();
     NativeDefinedAtomIvarsV1 ivar;
+    unsigned refsCount;
     ivar.nameOffset = getNameOffset(atom);
     ivar.attributesOffset = getAttributeOffset(atom);
+    ivar.referencesStartIndex = getReferencesIndex(atom, refsCount);
+    ivar.referencesCount = refsCount;
     ivar.contentOffset = getContentOffset(atom);
     ivar.contentSize = atom.size();
     _definedAtomIvars.push_back(ivar);
   }
   
   // visitor routine called by forEachAtom() 
-  virtual void doUndefinedAtom(const class UndefinedAtom& atom) {
+  virtual void doUndefinedAtom(const UndefinedAtom& atom) {
+    _undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
     NativeUndefinedAtomIvarsV1 ivar;
     ivar.nameOffset = getNameOffset(atom);
     ivar.flags = (atom.weakImport() ? 1 : 0);
@@ -74,13 +115,18 @@
   }
   
   // visitor routine called by forEachAtom() 
-  virtual void doFile(const class File &) {
+  virtual void doFile(const File &) {
   }
 
   // fill out native file header and chunk directory
   void makeHeader() {
     const bool hasUndefines = !_undefinedAtomIvars.empty();
-    const int chunkCount = hasUndefines ? 5 : 4;
+    const bool hasTargetsTable = !_targetsTableIndex.empty();
+    const bool hasAddendTable = !_addendsTableIndex.empty();
+    int chunkCount = 5;
+    if ( hasUndefines ) ++chunkCount;
+    if ( hasTargetsTable ) ++chunkCount;
+    if ( hasAddendTable ) ++chunkCount;
     _headerBufferSize = sizeof(NativeFileHeader) 
                          + chunkCount*sizeof(NativeChunk);
     _headerBuffer = reinterpret_cast<NativeFileHeader*>
@@ -124,6 +170,9 @@
     }
     
     // create chunk for symbol strings
+    // pad end of string pool to 4-bytes 
+    while ( (_stringPool.size() % 4) != 0 )
+      _stringPool.push_back('\0');
     NativeChunk& chs = chunks[nextIndex++];
     chs.signature = NCS_Strings;
     chs.fileOffset = nextFileOffset;
@@ -131,6 +180,34 @@
     chs.elementCount = _stringPool.size();
     nextFileOffset = chs.fileOffset + chs.fileSize;
     
+    // create chunk for references 
+    NativeChunk& chr = chunks[nextIndex++];
+    chr.signature = NCS_ReferencesArrayV1;
+    chr.fileOffset = nextFileOffset;
+    chr.fileSize = _references.size() * sizeof(NativeReferenceIvarsV1);
+    chr.elementCount = _references.size();
+    nextFileOffset = chr.fileOffset + chr.fileSize;
+
+    // create chunk for target table 
+    if ( hasTargetsTable ) {
+      NativeChunk& cht = chunks[nextIndex++];
+      cht.signature = NCS_TargetsTable;
+      cht.fileOffset = nextFileOffset;
+      cht.fileSize = _targetsTableIndex.size() * sizeof(uint32_t);
+      cht.elementCount = _targetsTableIndex.size();
+      nextFileOffset = cht.fileOffset + cht.fileSize;
+    }
+
+    // create chunk for addend table 
+    if ( hasAddendTable ) {
+      NativeChunk& chad = chunks[nextIndex++];
+      chad.signature = NCS_AddendsTable;
+      chad.fileOffset = nextFileOffset;
+      chad.fileSize = _addendsTableIndex.size() * sizeof(Reference::Addend);
+      chad.elementCount = _addendsTableIndex.size();
+      nextFileOffset = chad.fileOffset + chad.fileSize;
+    }
+    
     // create chunk for content 
     NativeChunk& chc = chunks[nextIndex++];
     chc.signature = NCS_Content;
@@ -142,6 +219,18 @@
     _headerBuffer->fileSize = nextFileOffset;
   }
 
+  // scan header to find particular chunk
+  NativeChunk& findChunk(uint32_t signature) {
+    const uint32_t chunkCount = _headerBuffer->chunkCount;
+    NativeChunk* chunks =
+      reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
+                                     + sizeof(NativeFileHeader));
+    for (uint32_t i=0; i < chunkCount; ++i) {
+      if ( chunks[i].signature == signature )
+        return chunks[i];
+    }
+    assert(0 && "findChunk() signature not found");
+  }
 
   // append atom name to string pool and return offset
   uint32_t getNameOffset(const Atom& atom) {
@@ -150,6 +239,8 @@
   
  // append atom name to string pool and return offset
   uint32_t getNameOffset(llvm::StringRef name) {
+    if ( name.empty() )
+      return 0;
     uint32_t result = _stringPool.size();
     _stringPool.insert(_stringPool.end(), name.size()+1, 0);
     strcpy(&_stringPool[result], name.data());
@@ -206,7 +297,6 @@
     attrs.sectionNameOffset = sectionNameOffset(atom);
     attrs.align2            = atom.alignment().powerOf2;
     attrs.alignModulus      = atom.alignment().modulus;
-    attrs.internalName      = atom.internalName(); 
     attrs.scope             = atom.scope(); 
     attrs.interposable      = atom.interposable(); 
     attrs.merge             = atom.merge(); 
@@ -214,12 +304,99 @@
     attrs.sectionChoice     = atom.sectionChoice(); 
     attrs.deadStrip         = atom.deadStrip(); 
     attrs.permissions       = atom.permissions(); 
-    attrs.thumb             = atom.isThumb(); 
+    //attrs.thumb             = atom.isThumb(); 
     attrs.alias             = atom.isAlias(); 
   }
 
+  // add references for this atom in a contiguous block in NCS_ReferencesArrayV1
+  uint32_t getReferencesIndex(const DefinedAtom& atom, unsigned& count) {
+    count = 0;
+    size_t startRefSize = _references.size();
+    uint32_t result = startRefSize;
+    atom.forEachReference(*this);
+    count = _references.size() - startRefSize;
+    if ( count == 0 )
+      return 0;
+    else
+      return result;
+  }
+  
+  void doReference(const Reference& ref) {
+    NativeReferenceIvarsV1 nref;
+    nref.offsetInAtom = ref.offsetInAtom();
+    nref.kind = ref.kind();
+    nref.targetIndex = this->getTargetIndex(ref.target());
+    nref.addendIndex = this->getAddendIndex(ref.addend());
+    _references.push_back(nref);
+  }
+  
+  uint32_t getTargetIndex(const Atom* target) {
+    TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
+    if ( pos != _targetsTableIndex.end() ) {
+      return pos->second;
+    }
+    uint32_t result = _targetsTableIndex.size();
+    _targetsTableIndex[target] = result;
+    return result;
+  }
+  
+  void writeTargetTable(llvm::raw_ostream& out) {
+    // Build table of target indexes  
+    uint32_t maxTargetIndex = _targetsTableIndex.size();
+    uint32_t targetIndexes[maxTargetIndex];
+    for (TargetToIndex::iterator it = _targetsTableIndex.begin(); 
+                                 it != _targetsTableIndex.end(); ++it) {
+      const Atom* atom = it->first;
+      uint32_t targetIndex = it->second;
+      assert(targetIndex < maxTargetIndex);
+      uint32_t atomIndex = 0;
+      TargetToIndex::iterator pos = _definedAtomIndex.find(atom);
+      if ( pos != _definedAtomIndex.end() ) {
+        atomIndex = pos->second;
+      }
+      else {
+        pos = _undefinedAtomIndex.find(atom);
+        assert(pos != _undefinedAtomIndex.end());
+        atomIndex = pos->second + _definedAtomIvars.size();
+      }
+      targetIndexes[targetIndex] = atomIndex;
+    }
+    // write table
+    out.write((char*)&targetIndexes[0], maxTargetIndex*sizeof(uint32_t));
+  }
+  
+  uint32_t getAddendIndex(Reference::Addend addend) { 
+    if ( addend == 0 )
+      return 0; // addend index zero is used to mean "no addend"
+    AddendToIndex::const_iterator pos = _addendsTableIndex.find(addend);
+    if ( pos != _addendsTableIndex.end() ) {
+      return pos->second;
+    }
+    uint32_t result = _addendsTableIndex.size() + 1; // one-based index
+    _addendsTableIndex[addend] = result;
+    return result;
+  }
+ 
+  void writeAddendTable(llvm::raw_ostream& out) {
+    // Build table of addends  
+    uint32_t maxAddendIndex = _addendsTableIndex.size();
+    Reference::Addend addends[maxAddendIndex];
+    for (AddendToIndex::iterator it = _addendsTableIndex.begin(); 
+                                 it != _addendsTableIndex.end(); ++it) {
+      Reference::Addend addend = it->first;
+      uint32_t index = it->second;
+      assert(index <= maxAddendIndex);
+      addends[index-1] = addend;
+    }
+    // write table
+    out.write((char*)&addends[0], maxAddendIndex*sizeof(Reference::Addend));
+  }
+
   typedef std::vector<std::pair<llvm::StringRef, uint32_t> > NameToOffsetVector;
 
+  typedef llvm::DenseMap<const Atom*, uint32_t> TargetToIndex;
+  typedef llvm::DenseMap<Reference::Addend, uint32_t> AddendToIndex;
+
   const lld::File&                        _file;
   NativeFileHeader*                       _headerBuffer;
   size_t                                  _headerBufferSize;
@@ -228,6 +405,11 @@
   std::vector<NativeDefinedAtomIvarsV1>   _definedAtomIvars;
   std::vector<NativeAtomAttributesV1>     _attributes;
   std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
+  std::vector<NativeReferenceIvarsV1>     _references;
+  TargetToIndex                           _targetsTableIndex;
+  TargetToIndex                           _definedAtomIndex;
+  TargetToIndex                           _undefinedAtomIndex;
+  AddendToIndex                           _addendsTableIndex;
   NameToOffsetVector                      _sectionNames;
 };