Add support for SharedLibraryAtoms (proxy atoms for exported symbols from a 
shared library) and AbsoluteAtoms (proxy atoms for absolute address (e.g. ROM)).
Redesign weak importing as can-be-null-at-runtime and can-be-null-at-build-time.
Add lots of test cases for all the above.

llvm-svn: 151204
diff --git a/lld/lib/Core/NativeWriter.cpp b/lld/lib/Core/NativeWriter.cpp
index da877fd..a95a514 100644
--- a/lld/lib/Core/NativeWriter.cpp
+++ b/lld/lib/Core/NativeWriter.cpp
@@ -61,7 +61,21 @@
       out.write((char*)&_undefinedAtomIvars[0], 
               _undefinedAtomIvars.size()*sizeof(NativeUndefinedAtomIvarsV1));
     }
-              
+    
+     if ( !_sharedLibraryAtomIvars.empty() ) {
+      assert( out.tell() == findChunk(NCS_SharedLibraryAtomsV1).fileOffset );
+      out.write((char*)&_sharedLibraryAtomIvars[0], 
+              _sharedLibraryAtomIvars.size() 
+              * sizeof(NativeSharedLibraryAtomIvarsV1));
+    }
+     
+    if ( !_absoluteAtomIvars.empty() ) {
+      assert( out.tell() == findChunk(NCS_AbsoluteAtomsV1).fileOffset );
+      out.write((char*)&_absoluteAtomIvars[0], 
+              _absoluteAtomIvars.size() 
+              * sizeof(NativeAbsoluteAtomIvarsV1));
+    }
+                       
     if (!_stringPool.empty()) {
       assert( out.tell() == findChunk(NCS_Strings).fileOffset );
       out.write(&_stringPool[0], _stringPool.size());
@@ -110,23 +124,55 @@
     _undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
     NativeUndefinedAtomIvarsV1 ivar;
     ivar.nameOffset = getNameOffset(atom);
-    ivar.flags = (atom.weakImport() ? 1 : 0);
+    ivar.flags = (atom.canBeNull() & 0x03);
     _undefinedAtomIvars.push_back(ivar);
   }
   
   // visitor routine called by forEachAtom() 
+  virtual void doSharedLibraryAtom(const SharedLibraryAtom& atom) {
+    _sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size();
+    NativeSharedLibraryAtomIvarsV1 ivar;
+    ivar.nameOffset = getNameOffset(atom);
+    ivar.loadNameOffset = getSharedLibraryNameOffset(atom.loadName());
+    ivar.flags = atom.canBeNullAtRuntime();
+    _sharedLibraryAtomIvars.push_back(ivar);
+  }
+   
+  // visitor routine called by forEachAtom() 
+  virtual void doAbsoluteAtom(const AbsoluteAtom& atom) {
+    _absoluteAtomIndex[&atom] = _absoluteAtomIvars.size();
+    NativeAbsoluteAtomIvarsV1 ivar;
+    ivar.nameOffset = getNameOffset(atom);
+    ivar.reserved = 0;
+    ivar.value = atom.value();
+    _absoluteAtomIvars.push_back(ivar);
+  }
+
+  // visitor routine called by forEachAtom() 
   virtual void doFile(const File &) {
   }
 
   // fill out native file header and chunk directory
   void makeHeader() {
+    const bool hasDefines = !_definedAtomIvars.empty();
     const bool hasUndefines = !_undefinedAtomIvars.empty();
+    const bool hasSharedLibraries = !_sharedLibraryAtomIvars.empty();
+    const bool hasAbsolutes = !_absoluteAtomIvars.empty();
+    const bool hasReferences = !_references.empty();
     const bool hasTargetsTable = !_targetsTableIndex.empty();
     const bool hasAddendTable = !_addendsTableIndex.empty();
-    int chunkCount = 5;
+    const bool hasContent = !_contentPool.empty();
+
+    int chunkCount = 1; // always have string pool chunk
+    if ( hasDefines ) chunkCount += 2;
     if ( hasUndefines ) ++chunkCount;
+    if ( hasSharedLibraries ) ++chunkCount;
+    if ( hasAbsolutes ) ++chunkCount;
+    if ( hasReferences ) ++chunkCount;
     if ( hasTargetsTable ) ++chunkCount;
     if ( hasAddendTable ) ++chunkCount;
+    if ( hasContent ) ++chunkCount;
+
     _headerBufferSize = sizeof(NativeFileHeader) 
                          + chunkCount*sizeof(NativeChunk);
     _headerBuffer = reinterpret_cast<NativeFileHeader*>
@@ -140,23 +186,25 @@
     _headerBuffer->fileSize = 0;
     _headerBuffer->chunkCount = chunkCount;
     
-    
-    // create chunk for atom ivar array
+    // create chunk for defined atom ivar array
     int nextIndex = 0;
-    NativeChunk& chd = chunks[nextIndex++];
-    chd.signature = NCS_DefinedAtomsV1;
-    chd.fileOffset = _headerBufferSize;
-    chd.fileSize = _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1);
-    chd.elementCount = _definedAtomIvars.size();
-    uint32_t nextFileOffset = chd.fileOffset + chd.fileSize;
+    uint32_t nextFileOffset = _headerBufferSize;
+    if ( hasDefines ) {
+      NativeChunk& chd = chunks[nextIndex++];
+      chd.signature = NCS_DefinedAtomsV1;
+      chd.fileOffset = nextFileOffset;
+      chd.fileSize = _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1);
+      chd.elementCount = _definedAtomIvars.size();
+      nextFileOffset = chd.fileOffset + chd.fileSize;
 
-    // create chunk for attributes 
-    NativeChunk& cha = chunks[nextIndex++];
-    cha.signature = NCS_AttributesArrayV1;
-    cha.fileOffset = nextFileOffset;
-    cha.fileSize = _attributes.size()*sizeof(NativeAtomAttributesV1);
-    cha.elementCount = _attributes.size();
-    nextFileOffset = cha.fileOffset + cha.fileSize;
+      // create chunk for attributes 
+      NativeChunk& cha = chunks[nextIndex++];
+      cha.signature = NCS_AttributesArrayV1;
+      cha.fileOffset = nextFileOffset;
+      cha.fileSize = _attributes.size()*sizeof(NativeAtomAttributesV1);
+      cha.elementCount = _attributes.size();
+      nextFileOffset = cha.fileOffset + cha.fileSize;
+    }
     
     // create chunk for undefined atom array
     if ( hasUndefines ) {
@@ -169,6 +217,28 @@
       nextFileOffset = chu.fileOffset + chu.fileSize;
     }
     
+    // create chunk for shared library atom array
+    if ( hasSharedLibraries ) {
+      NativeChunk& chsl = chunks[nextIndex++];
+      chsl.signature = NCS_SharedLibraryAtomsV1;
+      chsl.fileOffset = nextFileOffset;
+      chsl.fileSize = _sharedLibraryAtomIvars.size() * 
+                                        sizeof(NativeSharedLibraryAtomIvarsV1);
+      chsl.elementCount = _sharedLibraryAtomIvars.size();
+      nextFileOffset = chsl.fileOffset + chsl.fileSize;
+    }
+   
+     // create chunk for shared library atom array
+    if ( hasAbsolutes ) {
+      NativeChunk& chsl = chunks[nextIndex++];
+      chsl.signature = NCS_AbsoluteAtomsV1;
+      chsl.fileOffset = nextFileOffset;
+      chsl.fileSize = _absoluteAtomIvars.size() * 
+                                        sizeof(NativeAbsoluteAtomIvarsV1);
+      chsl.elementCount = _absoluteAtomIvars.size();
+      nextFileOffset = chsl.fileOffset + chsl.fileSize;
+    }
+   
     // create chunk for symbol strings
     // pad end of string pool to 4-bytes 
     while ( (_stringPool.size() % 4) != 0 )
@@ -181,13 +251,15 @@
     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;
-
+    if ( hasReferences ) {
+      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++];
@@ -209,13 +281,15 @@
     }
     
     // create chunk for content 
-    NativeChunk& chc = chunks[nextIndex++];
-    chc.signature = NCS_Content;
-    chc.fileOffset = nextFileOffset;
-    chc.fileSize = _contentPool.size();
-    chc.elementCount = _contentPool.size();
-    nextFileOffset = chc.fileOffset + chc.fileSize;
-
+    if ( hasContent ) {
+      NativeChunk& chc = chunks[nextIndex++];
+      chc.signature = NCS_Content;
+      chc.fileOffset = nextFileOffset;
+      chc.fileSize = _contentPool.size();
+      chc.elementCount = _contentPool.size();
+      nextFileOffset = chc.fileOffset + chc.fileSize;
+    }
+    
     _headerBuffer->fileSize = nextFileOffset;
   }
 
@@ -237,7 +311,23 @@
     return this->getNameOffset(atom.name());
   }
   
- // append atom name to string pool and return offset
+  // check if name is already in pool or append and return offset
+  uint32_t getSharedLibraryNameOffset(llvm::StringRef name) {
+    assert( ! name.empty() );
+    // look to see if this library name was used by another atom
+    for(NameToOffsetVector::iterator it = _sharedLibraryNames.begin(); 
+                                    it != _sharedLibraryNames.end(); ++it) {
+      if ( name.equals(it->first) )
+        return it->second;
+    }
+    // first use of this library name
+    uint32_t result = this->getNameOffset(name);
+    _sharedLibraryNames.push_back(
+                    std::make_pair<llvm::StringRef, uint32_t>(name, result));
+    return result;
+  }
+  
+  // append atom name to string pool and return offset
   uint32_t getNameOffset(llvm::StringRef name) {
     if ( name.empty() )
       return 0;
@@ -356,8 +446,26 @@
       }
       else {
         pos = _undefinedAtomIndex.find(atom);
-        assert(pos != _undefinedAtomIndex.end());
-        atomIndex = pos->second + _definedAtomIvars.size();
+        if ( pos != _undefinedAtomIndex.end() ) {
+          atomIndex = pos->second + _definedAtomIvars.size();
+        }
+        else {
+          pos = _sharedLibraryAtomIndex.find(atom);
+          if ( pos != _sharedLibraryAtomIndex.end() ) {
+            assert(pos != _sharedLibraryAtomIndex.end());
+            atomIndex = pos->second 
+                      + _definedAtomIvars.size() 
+                      + _undefinedAtomIndex.size();
+          }
+          else {
+            pos = _absoluteAtomIndex.find(atom);
+            assert(pos != _absoluteAtomIndex.end());
+            atomIndex = pos->second 
+                      + _definedAtomIvars.size() 
+                      + _undefinedAtomIndex.size()
+                      + _sharedLibraryAtomIndex.size();
+         }
+        }
       }
       targetIndexes[targetIndex] = atomIndex;
     }
@@ -405,12 +513,17 @@
   std::vector<NativeDefinedAtomIvarsV1>   _definedAtomIvars;
   std::vector<NativeAtomAttributesV1>     _attributes;
   std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
+  std::vector<NativeSharedLibraryAtomIvarsV1> _sharedLibraryAtomIvars;
+  std::vector<NativeAbsoluteAtomIvarsV1>  _absoluteAtomIvars;
   std::vector<NativeReferenceIvarsV1>     _references;
   TargetToIndex                           _targetsTableIndex;
   TargetToIndex                           _definedAtomIndex;
   TargetToIndex                           _undefinedAtomIndex;
+  TargetToIndex                           _sharedLibraryAtomIndex;
+  TargetToIndex                           _absoluteAtomIndex;
   AddendToIndex                           _addendsTableIndex;
   NameToOffsetVector                      _sectionNames;
+  NameToOffsetVector                      _sharedLibraryNames;
 };