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/NativeReader.cpp b/lld/lib/Core/NativeReader.cpp
index bc86d19..e85d2ff 100644
--- a/lld/lib/Core/NativeReader.cpp
+++ b/lld/lib/Core/NativeReader.cpp
@@ -77,7 +77,7 @@
       
   virtual DefinedAtom::DeadStripKind deadStrip() const {
      return (DefinedAtom::DeadStripKind)(attributes().deadStrip);
- }
+  }
     
   virtual DefinedAtom::ContentPermissions permissions() const {
      return (DefinedAtom::ContentPermissions)(attributes().permissions);
@@ -117,16 +117,64 @@
   virtual const File& file() const;
   virtual llvm::StringRef name() const;
   
-  virtual bool weakImport() const {
-    return (_ivarData->flags & 0x1);
+  virtual CanBeNull canBeNull() const {
+    return (CanBeNull)(_ivarData->flags & 0x3);
   }
   
+
 private:
   const NativeFile*                 _file;
   const NativeUndefinedAtomIvarsV1* _ivarData;
 };
 
 
+//
+// An object of this class is instantied for each NativeUndefinedAtomIvarsV1
+// struct in the NCS_SharedLibraryAtomsV1 chunk.
+//
+class NativeSharedLibraryAtomV1 : public SharedLibraryAtom {
+public:
+       NativeSharedLibraryAtomV1(const NativeFile& f, 
+                             const NativeSharedLibraryAtomIvarsV1* ivarData)
+        : _file(&f), _ivarData(ivarData) { } 
+
+  virtual const File& file() const;
+  virtual llvm::StringRef name() const;
+  virtual llvm::StringRef loadName() const;
+  
+  virtual bool canBeNullAtRuntime() const {
+    return (_ivarData->flags & 0x1);
+  }
+
+private:
+  const NativeFile*                     _file;
+  const NativeSharedLibraryAtomIvarsV1* _ivarData;
+};
+
+
+//
+// An object of this class is instantied for each NativeAbsoluteAtomIvarsV1
+// struct in the NCS_AbsoluteAtomsV1 chunk.
+//
+class NativeAbsoluteAtomV1 : public AbsoluteAtom {
+public:
+       NativeAbsoluteAtomV1(const NativeFile& f, 
+                             const NativeAbsoluteAtomIvarsV1* ivarData)
+        : _file(&f), _ivarData(ivarData) { } 
+
+  virtual const File& file() const;
+  virtual llvm::StringRef name() const;
+  
+  virtual uint64_t value() const {
+    return _ivarData->value;
+  }
+
+private:
+  const NativeFile*                 _file;
+  const NativeAbsoluteAtomIvarsV1*  _ivarData;
+};
+
+
 
 //
 // An object of this class is instantied for each NativeReferenceIvarsV1
@@ -206,6 +254,12 @@
         case NCS_UndefinedAtomsV1:
           ec = file->processUndefinedAtomsV1(base, chunk);
           break;
+        case NCS_SharedLibraryAtomsV1:
+          ec = file->processSharedLibraryAtomsV1(base, chunk);
+          break;
+        case NCS_AbsoluteAtomsV1:
+          ec = file->processAbsoluteAtomsV1(base, chunk);
+          break;
         case NCS_ReferencesArrayV1:
           ec = file->processReferencesV1(base, chunk);
           break;
@@ -247,23 +301,45 @@
     // to just delete the memory.
     delete _definedAtoms.arrayStart;
     delete _undefinedAtoms.arrayStart;
+    delete _sharedLibraryAtoms.arrayStart;
+    delete _absoluteAtoms.arrayStart;
     delete _references.arrayStart;
     delete _targetsTable;
   }
   
   // visits each atom in the file
   virtual bool forEachAtom(AtomHandler& handler) const {
+    bool didSomething = false;
     for(const uint8_t* p=_definedAtoms.arrayStart; p != _definedAtoms.arrayEnd; 
           p += _definedAtoms.elementSize) {
       const DefinedAtom* atom = reinterpret_cast<const DefinedAtom*>(p);
       handler.doDefinedAtom(*atom);
+      didSomething = true;
     }
-    for(const uint8_t* p=_undefinedAtoms.arrayStart; p != _undefinedAtoms.arrayEnd; 
-          p += _undefinedAtoms.elementSize) {
+    for(const uint8_t* p=_undefinedAtoms.arrayStart; 
+                      p != _undefinedAtoms.arrayEnd; 
+                      p += _undefinedAtoms.elementSize) {
       const UndefinedAtom* atom = reinterpret_cast<const UndefinedAtom*>(p);
       handler.doUndefinedAtom(*atom);
+      didSomething = true;
     }
-    return (_definedAtoms.arrayStart != _definedAtoms.arrayEnd);
+    for(const uint8_t* p=_sharedLibraryAtoms.arrayStart; 
+                  p != _sharedLibraryAtoms.arrayEnd; 
+                  p += _sharedLibraryAtoms.elementSize) {
+      const SharedLibraryAtom* atom 
+                          = reinterpret_cast<const SharedLibraryAtom*>(p);
+      handler.doSharedLibraryAtom(*atom);
+      didSomething = true;
+    }
+    for(const uint8_t* p=_absoluteAtoms.arrayStart; 
+                  p != _absoluteAtoms.arrayEnd; 
+                  p += _absoluteAtoms.elementSize) {
+      const AbsoluteAtom* atom 
+                          = reinterpret_cast<const AbsoluteAtom*>(p);
+      handler.doAbsoluteAtom(*atom);
+      didSomething = true;
+    }
+    return didSomething;
   }
   
   // not used
@@ -275,6 +351,8 @@
 private:
   friend class NativeDefinedAtomV1;
   friend class NativeUndefinedAtomV1;
+  friend class NativeSharedLibraryAtomV1;
+  friend class NativeAbsoluteAtomV1;
   friend class NativeReferenceV1;
   
   // instantiate array of DefinedAtoms from v1 ivar data in file
@@ -308,12 +386,14 @@
   }
   
   // set up pointers to attributes array
-  llvm::error_code processAttributesV1(const uint8_t* base, const NativeChunk* chunk) {
+  llvm::error_code processAttributesV1(const uint8_t* base, 
+                                       const NativeChunk* chunk) {
     this->_attributes = base + chunk->fileOffset;
     this->_attributesMaxOffset = chunk->fileSize;
     return make_error_code(native_reader_error::success);
   }
   
+  // instantiate array of UndefinedAtoms from v1 ivar data in file
   llvm::error_code processUndefinedAtomsV1(const uint8_t* base, 
                                                 const NativeChunk* chunk) {
     const size_t atomSize = sizeof(NativeUndefinedAtomV1);
@@ -344,6 +424,70 @@
   }
   
   
+  // instantiate array of ShareLibraryAtoms from v1 ivar data in file
+  llvm::error_code processSharedLibraryAtomsV1(const uint8_t* base, 
+                                                const NativeChunk* chunk) {
+    const size_t atomSize = sizeof(NativeSharedLibraryAtomV1);
+    size_t atomsArraySize = chunk->elementCount * atomSize;
+    uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+                                (operator new(atomsArraySize, std::nothrow));
+    if (atomsStart == NULL )
+      return make_error_code(native_reader_error::memory_error);
+    const size_t ivarElementSize = chunk->fileSize 
+                                          / chunk->elementCount;
+    if ( ivarElementSize != sizeof(NativeSharedLibraryAtomIvarsV1) )
+      return make_error_code(native_reader_error::file_malformed);
+    uint8_t* atomsEnd = atomsStart + atomsArraySize;
+    const NativeSharedLibraryAtomIvarsV1* ivarData = 
+                      reinterpret_cast<const NativeSharedLibraryAtomIvarsV1*>
+                                                  (base + chunk->fileOffset);
+    for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+      NativeSharedLibraryAtomV1* atomAllocSpace = 
+                  reinterpret_cast<NativeSharedLibraryAtomV1*>(s);
+      new (atomAllocSpace) NativeSharedLibraryAtomV1(*this, ivarData);
+      ++ivarData;
+    }
+    this->_sharedLibraryAtoms.arrayStart = atomsStart;
+    this->_sharedLibraryAtoms.arrayEnd = atomsEnd;
+    this->_sharedLibraryAtoms.elementSize = atomSize;
+    this->_sharedLibraryAtoms.elementCount = chunk->elementCount;
+    return make_error_code(native_reader_error::success);
+  }
+  
+ 
+   // instantiate array of AbsoluteAtoms from v1 ivar data in file
+  llvm::error_code processAbsoluteAtomsV1(const uint8_t* base, 
+                                                const NativeChunk* chunk) {
+    const size_t atomSize = sizeof(NativeAbsoluteAtomV1);
+    size_t atomsArraySize = chunk->elementCount * atomSize;
+    uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+                                (operator new(atomsArraySize, std::nothrow));
+    if (atomsStart == NULL )
+      return make_error_code(native_reader_error::memory_error);
+    const size_t ivarElementSize = chunk->fileSize 
+                                          / chunk->elementCount;
+    if ( ivarElementSize != sizeof(NativeAbsoluteAtomIvarsV1) )
+      return make_error_code(native_reader_error::file_malformed);
+    uint8_t* atomsEnd = atomsStart + atomsArraySize;
+    const NativeAbsoluteAtomIvarsV1* ivarData = 
+                      reinterpret_cast<const NativeAbsoluteAtomIvarsV1*>
+                                                  (base + chunk->fileOffset);
+    for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+      NativeAbsoluteAtomV1* atomAllocSpace = 
+                  reinterpret_cast<NativeAbsoluteAtomV1*>(s);
+      new (atomAllocSpace) NativeAbsoluteAtomV1(*this, ivarData);
+      ++ivarData;
+    }
+    this->_absoluteAtoms.arrayStart = atomsStart;
+    this->_absoluteAtoms.arrayEnd = atomsEnd;
+    this->_absoluteAtoms.elementSize = atomSize;
+    this->_absoluteAtoms.elementCount = chunk->elementCount;
+    return make_error_code(native_reader_error::success);
+  }
+  
+ 
+ 
+  
   // instantiate array of Referemces from v1 ivar data in file
   llvm::error_code processReferencesV1(const uint8_t* base, 
                                                 const NativeChunk* chunk) {
@@ -398,7 +542,24 @@
         this->_targetsTable[i] = reinterpret_cast<const UndefinedAtom*>(p);
         continue;
       }
-      return make_error_code(native_reader_error::file_malformed);
+      const uint32_t slIndex = index - _definedAtoms.elementCount 
+                                     - _undefinedAtoms.elementCount;
+      if ( slIndex < _sharedLibraryAtoms.elementCount ) {
+        const uint8_t* p = _sharedLibraryAtoms.arrayStart 
+                                  + slIndex * _sharedLibraryAtoms.elementSize;
+        this->_targetsTable[i] = reinterpret_cast<const SharedLibraryAtom*>(p);
+        continue;
+      }
+      const uint32_t abIndex = index - _definedAtoms.elementCount 
+                                     - _undefinedAtoms.elementCount
+                                     - _sharedLibraryAtoms.elementCount;
+      if ( abIndex < _absoluteAtoms.elementCount ) {
+        const uint8_t* p = _absoluteAtoms.arrayStart 
+                                  + slIndex * _absoluteAtoms.elementSize;
+        this->_targetsTable[i] = reinterpret_cast<const AbsoluteAtom*>(p);
+        continue;
+      }
+     return make_error_code(native_reader_error::file_malformed);
     }
     return make_error_code(native_reader_error::success);
   }
@@ -491,7 +652,8 @@
     _contentStart(NULL), 
     _contentEnd(NULL)
   {
-    _header = reinterpret_cast<const NativeFileHeader*>(_buffer->getBufferStart());
+    _header = reinterpret_cast<const NativeFileHeader*>
+                                                  (_buffer->getBufferStart());
   }
 
   struct IvarArray {
@@ -507,6 +669,8 @@
   const NativeFileHeader*         _header;
   IvarArray                       _definedAtoms;
   IvarArray                       _undefinedAtoms;
+  IvarArray                       _sharedLibraryAtoms;
+  IvarArray                       _absoluteAtoms;
   const uint8_t*                  _attributes;
   uint32_t                        _attributesMaxOffset;
   IvarArray                       _references;
@@ -567,6 +731,31 @@
 }
 
 
+
+
+inline const class File& NativeSharedLibraryAtomV1::file() const {
+  return *_file;
+}
+
+inline llvm::StringRef NativeSharedLibraryAtomV1::name() const {
+  return _file->string(_ivarData->nameOffset);
+}
+
+inline llvm::StringRef NativeSharedLibraryAtomV1::loadName() const {
+  return _file->string(_ivarData->loadNameOffset);
+}
+
+
+
+inline const class File& NativeAbsoluteAtomV1::file() const {
+  return *_file;
+}
+
+inline llvm::StringRef NativeAbsoluteAtomV1::name() const {
+  return _file->string(_ivarData->nameOffset);
+}
+
+
 inline const Atom* NativeReferenceV1::target() const {
   return _file->target(_ivarData->targetIndex);
 }