MCLinker upstream commit e764452.

Change-Id: I5c9ec467ec96a0143e1e67c59365f3b6303e7348
diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp
index 57b82df..cc15e37 100644
--- a/lib/Support/CommandLine.cpp
+++ b/lib/Support/CommandLine.cpp
@@ -6,12 +6,16 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
-#include "mcld/Support/CommandLine.h"
+#include <mcld/Support/CommandLine.h>
 #include <llvm/ADT/StringRef.h>
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ErrorHandling.h>
 
 using namespace llvm;
 using namespace llvm::cl;
 
+using namespace mcld;
+
 //--------------------------------------------------
 // parser<mcld::sys::fs::Path>
 //
@@ -82,3 +86,81 @@
   // do nothing
 }
 
+//--------------------------------------------------
+// parser<mcld::ZOption>
+//
+bool parser<mcld::ZOption>::parse(llvm::cl::Option &O,
+                                  llvm::StringRef ArgName,
+                                  llvm::StringRef Arg,
+                                  mcld::ZOption &Val)
+{
+  if (0 == Arg.compare("combreloc"))
+    Val.setKind(ZOption::CombReloc);
+  else if (0 == Arg.compare("nocombreloc"))
+    Val.setKind(ZOption::NoCombReloc);
+  else if (0 == Arg.compare("defs"))
+    Val.setKind(ZOption::Defs);
+  else if (0 == Arg.compare("execstack"))
+    Val.setKind(ZOption::ExecStack);
+  else if (0 == Arg.compare("noexecstack"))
+    Val.setKind(ZOption::NoExecStack);
+  else if (0 == Arg.compare("initfirst"))
+    Val.setKind(ZOption::InitFirst);
+  else if (0 == Arg.compare("interpose"))
+    Val.setKind(ZOption::InterPose);
+  else if (0 == Arg.compare("loadfltr"))
+    Val.setKind(ZOption::LoadFltr);
+  else if (0 == Arg.compare("muldefs"))
+    Val.setKind(ZOption::MulDefs);
+  else if (0 == Arg.compare("nocopyreloc"))
+    Val.setKind(ZOption::NoCopyReloc);
+  else if (0 == Arg.compare("nodefaultlib"))
+    Val.setKind(ZOption::NoDefaultLib);
+  else if (0 == Arg.compare("nodelete"))
+    Val.setKind(ZOption::NoDelete);
+  else if (0 == Arg.compare("nodlopen"))
+    Val.setKind(ZOption::NoDLOpen);
+  else if (0 == Arg.compare("nodump"))
+    Val.setKind(ZOption::NoDump);
+  else if (0 == Arg.compare("relro"))
+    Val.setKind(ZOption::Relro);
+  else if (0 == Arg.compare("norelro"))
+    Val.setKind(ZOption::NoRelro);
+  else if (0 == Arg.compare("lazy"))
+    Val.setKind(ZOption::Lazy);
+  else if (0 == Arg.compare("now"))
+    Val.setKind(ZOption::Now);
+  else if (0 == Arg.compare("origin"))
+    Val.setKind(ZOption::Origin);
+  else if (Arg.startswith("common-page-size=")) {
+    Val.setKind(ZOption::CommPageSize);
+    long long unsigned size = 0;
+    Arg.drop_front(17).getAsInteger(0, size);
+    Val.setPageSize(static_cast<uint64_t>(size));
+  } else if (Arg.startswith("max-page-size=")) {
+    Val.setKind(ZOption::MaxPageSize);
+    long long unsigned size = 0;
+    Arg.drop_front(14).getAsInteger(0, size);
+    Val.setPageSize(static_cast<uint64_t>(size));
+  }
+
+  if (ZOption::Unknown == Val.kind())
+    llvm::report_fatal_error(llvm::Twine("unknown -z option: `") +
+                             Arg +
+                             llvm::Twine("'\n"));
+  return false;
+}
+
+void parser<mcld::ZOption>::printOptionDiff(const llvm::cl::Option &O,
+                                            const mcld::ZOption &V,
+                                            parser<mcld::ZOption>::OptVal Default,
+                                            size_t GlobalWidth) const
+{
+  // TODO
+}
+
+void parser<mcld::ZOption>::anchor()
+{
+  // do nothing
+}
+
diff --git a/lib/Support/Directory.cpp b/lib/Support/Directory.cpp
index 211b42a..78bb761 100644
--- a/lib/Support/Directory.cpp
+++ b/lib/Support/Directory.cpp
@@ -32,7 +32,7 @@
   : m_Path(),
     m_FileStatus(),
     m_SymLinkStatus(),
-    m_Handler(NULL),
+    m_Handler(0),
     m_Cache(),
     m_CacheFull(false) {
 }
@@ -43,7 +43,7 @@
   : m_Path(pPath),
     m_FileStatus(st),
     m_SymLinkStatus(symlink_st),
-    m_Handler(NULL),
+    m_Handler(0),
     m_Cache(),
     m_CacheFull(false) {
   if (m_Path.native() == ".")
@@ -56,7 +56,7 @@
   : m_Path(pCopy.m_Path),
     m_FileStatus(pCopy.m_FileStatus),
     m_SymLinkStatus(pCopy.m_SymLinkStatus),
-    m_Handler(NULL),
+    m_Handler(0),
     m_Cache(),
     m_CacheFull(false) {
   mcld::sys::fs::detail::open_dir(*this);
diff --git a/lib/Support/FileHandle.cpp b/lib/Support/FileHandle.cpp
new file mode 100644
index 0000000..f6b898c
--- /dev/null
+++ b/lib/Support/FileHandle.cpp
@@ -0,0 +1,332 @@
+//===- FileHandle.cpp -----------------------------------------------------===//
+//
+//                     The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/FileHandle.h>
+#include <mcld/Support/FileSystem.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// FileHandle
+FileHandle::FileHandle()
+  : m_Path(),
+    m_Handler(-1),
+    m_Size(0),
+    m_State(GoodBit),
+    m_OpenMode(NotOpen) {
+}
+
+FileHandle::~FileHandle()
+{
+  if (isOpened())
+    close();
+}
+
+inline static int oflag(FileHandle::OpenMode pMode)
+{
+  int result = 0x0;
+  if (FileHandle::Unknown == pMode)
+    return result;
+
+  if (FileHandle::ReadWrite == (pMode & FileHandle::ReadWrite))
+    result |= O_RDWR;
+  else if (pMode & FileHandle::ReadOnly)
+    result |= O_RDONLY;
+  else if (pMode & FileHandle::WriteOnly)
+    result |= O_WRONLY;
+
+  if (pMode & FileHandle::Append)
+    result |= O_APPEND;
+
+  if (pMode & FileHandle::Create)
+    result |= O_CREAT;
+
+  if (pMode & FileHandle::Truncate)
+    result |= O_TRUNC;
+
+  return result;
+}
+
+inline static bool get_size(int pHandler, unsigned int &pSize)
+{
+  struct ::stat file_stat;
+  if (-1 == ::fstat(pHandler, &file_stat)) {
+    pSize = 0;
+    return false;
+  }
+  pSize = file_stat.st_size;
+  return true;
+}
+
+bool FileHandle::open(const sys::fs::Path& pPath,
+                      FileHandle::OpenMode pMode)
+{
+  if (isOpened() || Unknown == pMode) {
+    setState(BadBit);
+    return false;
+  }
+
+  m_OpenMode = pMode;
+  m_Handler = ::open(pPath.native().c_str(), oflag(pMode));
+  m_Path = pPath;
+  if (-1 == m_Handler) {
+    m_OpenMode = NotOpen;
+    setState(FailBit);
+    return false;
+  }
+
+  if (!get_size(m_Handler, m_Size)) {
+    setState(FailBit);
+    return false;
+  }
+
+  return true;
+}
+
+bool FileHandle::open(const sys::fs::Path& pPath,
+                      FileHandle::OpenMode pMode,
+                      FileHandle::Permission pPerm)
+{
+  if (isOpened() || Unknown == pMode) {
+    setState(BadBit);
+    return false;
+  }
+
+  m_OpenMode = pMode;
+  m_Handler = sys::fs::detail::open(pPath, oflag(pMode), (int)pPerm);
+  m_Path = pPath;
+  if (-1 == m_Handler) {
+    m_OpenMode = NotOpen;
+    setState(FailBit);
+    return false;
+  }
+
+  if (!get_size(m_Handler, m_Size)) {
+    setState(FailBit);
+    return false;
+  }
+
+  return true;
+}
+
+bool FileHandle::delegate(int pFD, FileHandle::OpenMode pMode)
+{
+  if (isOpened()) {
+    setState(BadBit);
+    return false;
+  }
+
+  m_Handler = pFD;
+  m_OpenMode = pMode;
+  m_State = GoodBit;
+
+  if (!get_size(m_Handler, m_Size)) {
+    setState(FailBit);
+    return false;
+  }
+
+  return true;
+}
+
+bool FileHandle::close()
+{
+  if (!isOpened()) {
+    setState(BadBit);
+    return false;
+  }
+
+  if (-1 == ::close(m_Handler)) {
+    setState(FailBit);
+    return false;
+  }
+
+  m_Path.native().clear();
+  m_Size = 0;
+  m_OpenMode = NotOpen;
+  cleanState();
+  return true;
+}
+
+bool FileHandle::truncate(size_t pSize)
+{
+  if (!isOpened() || !isWritable()) {
+    setState(BadBit);
+    return false;
+  }
+
+  if (-1 == sys::fs::detail::ftruncate(m_Handler, pSize)) {
+    setState(FailBit);
+    return false;
+  }
+
+  m_Size = pSize;
+  return true;
+}
+
+bool FileHandle::read(void* pMemBuffer, size_t pStartOffset, size_t pLength)
+{
+  if (!isOpened() || !isReadable()) {
+    setState(BadBit);
+    return false;
+  }
+
+  if (0 == pLength)
+    return true;
+
+  ssize_t read_bytes = sys::fs::detail::pread(m_Handler,
+                                              pMemBuffer,
+                                              pLength,
+                                              pStartOffset);
+
+  if (-1 == read_bytes) {
+    setState(FailBit);
+    return false;
+  }
+
+  return true;
+}
+
+bool FileHandle::write(const void* pMemBuffer, size_t pStartOffset, size_t pLength)
+{
+  if (!isOpened() || !isWritable()) {
+    setState(BadBit);
+    return false;
+  }
+
+  if (0 == pLength)
+    return true;
+
+
+  ssize_t write_bytes = sys::fs::detail::pwrite(m_Handler,
+                                                pMemBuffer,
+                                                pLength,
+                                                pStartOffset);
+
+  if (-1 == write_bytes) {
+    setState(FailBit);
+    return false;
+  }
+
+  return true;
+}
+
+#include <iostream>
+using namespace std;
+
+bool FileHandle::mmap(void*& pMemBuffer, size_t pStartOffset, size_t pLength)
+{
+  if (!isOpened()) {
+    setState(BadBit);
+    return false;
+  }
+
+  if (0 == pLength)
+    return true;
+
+  int prot, flag;
+  if (isReadable() && !isWritable()) {
+    // read-only
+    prot = PROT_READ;
+    flag = MAP_FILE | MAP_PRIVATE;
+  }
+  else if (!isReadable() && isWritable()) {
+    // write-only
+    prot = PROT_WRITE;
+    flag = MAP_FILE | MAP_SHARED;
+  }
+  else if (isReadWrite()) {
+    // read and write
+    prot = PROT_READ | PROT_WRITE;
+    flag = MAP_FILE | MAP_SHARED;
+  }
+  else {
+    // can not read/write
+    setState(BadBit);
+    return false;
+  }
+
+  pMemBuffer = ::mmap(NULL, pLength, prot, flag, m_Handler, pStartOffset);
+
+  if (MAP_FAILED == pMemBuffer) {
+    setState(FailBit);
+    return false;
+  }
+
+  return true;
+}
+
+bool FileHandle::munmap(void* pMemBuffer, size_t pLength)
+{
+  if (!isOpened()) {
+    setState(BadBit);
+    return false;
+  }
+
+  if (-1 == ::munmap(pMemBuffer, pLength)) {
+    setState(FailBit);
+    return false;
+  }
+
+  return true;
+}
+
+void FileHandle::setState(FileHandle::IOState pState)
+{
+  m_State |= pState;
+}
+
+void FileHandle::cleanState(FileHandle::IOState pState)
+{
+  m_State = pState;
+}
+
+bool FileHandle::isOpened() const
+{
+  if (-1 != m_Handler && m_OpenMode != NotOpen && isGood())
+    return true;
+
+  return false;
+}
+
+// Assume Unknown OpenMode is readable
+bool FileHandle::isReadable() const
+{
+  return (m_OpenMode & ReadOnly);
+}
+
+// Assume Unknown OpenMode is writable
+bool FileHandle::isWritable() const
+{
+  return (m_OpenMode & WriteOnly);
+}
+
+// Assume Unknown OpenMode is both readable and writable
+bool FileHandle::isReadWrite() const
+{
+  return (FileHandle::ReadWrite == (m_OpenMode & FileHandle::ReadWrite));
+}
+
+bool FileHandle::isGood() const
+{
+  return !(m_State & (BadBit | FailBit));
+}
+
+bool FileHandle::isBad() const
+{
+  return (m_State & BadBit);
+}
+
+bool FileHandle::isFailed() const
+{
+  return (m_State & (BadBit | FailBit));
+}
+
diff --git a/lib/Support/FileSystem.cpp b/lib/Support/FileSystem.cpp
index d3366c0..fb2633d 100644
--- a/lib/Support/FileSystem.cpp
+++ b/lib/Support/FileSystem.cpp
@@ -9,10 +9,6 @@
 #include "mcld/Support/FileSystem.h"
 #include "mcld/Support/Path.h"
 
-#if defined(ANDROID)
-#include <llvm/Config/config.h>
-#endif
-
 using namespace mcld::sys::fs;
 
 
@@ -22,12 +18,12 @@
 //===--------------------------------------------------------------------===//
 // non-member functions
 
-// Include the truly platform-specific parts.
-#if defined(LLVM_ON_UNIX)
+// Include the truly platform-specific parts. 
+#if defined(MCLD_ON_UNIX)
 #include "Unix/FileSystem.inc"
-#include "Unix/PathV3.inc"
-#endif
-#if defined(LLVM_ON_WIN32)
+#include "Unix/PathV3.inc" 
+#endif 
+#if defined(MCLD_ON_WIN32)
 #include "Windows/FileSystem.inc"
-#include "Windows/PathV3.inc"
-#endif
+#include "Windows/PathV3.inc" 
+#endif 
diff --git a/lib/Support/HandleToArea.cpp b/lib/Support/HandleToArea.cpp
new file mode 100644
index 0000000..f580e64
--- /dev/null
+++ b/lib/Support/HandleToArea.cpp
@@ -0,0 +1,94 @@
+//===- HandleToArea.cpp ----------------------------------------------------===//
+//
+//                     The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/HandleToArea.h>
+#include <mcld/Support/MemoryArea.h>
+#include <llvm/ADT/StringRef.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// HandleToArea
+bool HandleToArea::push_back(FileHandle* pHandle, MemoryArea* pArea)
+{
+  if (NULL == pHandle || NULL == pArea)
+    return false;
+
+  Bucket bucket;
+  bucket.hash_value = HashFunction()(
+                              llvm::StringRef(pHandle->path().native().c_str(),
+                                              pHandle->path().native().size()));
+
+  bucket.handle = pHandle;
+  bucket.area = pArea;
+  m_AreaMap.push_back(bucket);
+  return true;
+}
+
+bool HandleToArea::erase(MemoryArea* pArea)
+{
+  if (NULL == pArea || NULL == pArea->handler())
+    return false;
+
+  return erase(pArea->handler()->path());
+}
+
+bool HandleToArea::erase(const sys::fs::Path& pPath)
+{
+  unsigned int hash_value = HashFunction()(
+                                  llvm::StringRef(pPath.native().c_str(),
+                                                  pPath.native().size()));
+
+  HandleToAreaMap::iterator bucket, bEnd = m_AreaMap.end();
+  for (bucket = m_AreaMap.begin(); bucket != bEnd; ++bucket) {
+    if (bucket->hash_value == hash_value && bucket->handle->path() == pPath) {
+      // found
+      m_AreaMap.erase(bucket);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+HandleToArea::Result HandleToArea::findFirst(const sys::fs::Path& pPath)
+{
+  unsigned int hash_value = HashFunction()(llvm::StringRef(pPath.native().c_str(),
+                                                         pPath.native().size()));
+
+  HandleToAreaMap::iterator bucket, bEnd = m_AreaMap.end();
+
+  for (bucket = m_AreaMap.begin(); bucket != bEnd; ++bucket) {
+    if (bucket->hash_value == hash_value) {
+      if (bucket->handle->path() == pPath) {
+        return Result(bucket->handle, bucket->area);
+      }
+    }
+  }
+
+  return Result(NULL, NULL);
+}
+
+HandleToArea::ConstResult HandleToArea::findFirst(const sys::fs::Path& pPath) const
+{
+  unsigned int hash_value = HashFunction()(llvm::StringRef(pPath.native().c_str(),
+                                                         pPath.native().size()));
+
+  HandleToAreaMap::const_iterator bucket, bEnd = m_AreaMap.end();
+
+  for (bucket = m_AreaMap.begin(); bucket != bEnd; ++bucket) {
+    if (bucket->hash_value == hash_value) {
+      if (bucket->handle->path() == pPath) {
+        return ConstResult(bucket->handle, bucket->area);
+      }
+    }
+  }
+
+  return ConstResult(NULL, NULL);
+}
+
diff --git a/lib/Support/MemoryArea.cpp b/lib/Support/MemoryArea.cpp
index f388e94..78a9d36 100644
--- a/lib/Support/MemoryArea.cpp
+++ b/lib/Support/MemoryArea.cpp
@@ -6,164 +6,31 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
-#include <llvm/Support/ErrorHandling.h>
-#include <llvm/ADT/Twine.h>
-
 #include <mcld/Support/RegionFactory.h>
 #include <mcld/Support/MemoryArea.h>
 #include <mcld/Support/MemoryRegion.h>
-#include <mcld/Support/FileSystem.h>
-
-#include <cerrno>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
+#include <mcld/Support/FileHandle.h>
+#include <mcld/Support/MsgHandling.h>
 
 using namespace mcld;
 
 //===--------------------------------------------------------------------===//
 // MemoryArea
-MemoryArea::MemoryArea(RegionFactory& pRegionFactory)
-  : m_RegionFactory(pRegionFactory),
-    m_FileDescriptor(-1),
-    m_FileSize(0),
-    m_AccessFlags(ReadOnly),
-    m_State(BadBit) {
+
+// MemoryArea - special constructor
+// This constructor is used for *SPECIAL* situation. I'm sorry I can not
+// reveal what is the special situation.
+MemoryArea::MemoryArea(RegionFactory& pRegionFactory, Space& pUniverse)
+  : m_RegionFactory(pRegionFactory), m_pFileHandle(NULL) {
+  m_SpaceList.push_back(&pUniverse);
+}
+
+MemoryArea::MemoryArea(RegionFactory& pRegionFactory, FileHandle& pFileHandle)
+  : m_RegionFactory(pRegionFactory), m_pFileHandle(&pFileHandle) {
 }
 
 MemoryArea::~MemoryArea()
 {
-  // truncate the file to real size
-  if (isWritable())
-    truncate(m_FileSize);
-
-  unmap();
-}
-
-void MemoryArea::truncate(size_t pLength)
-{
-  if (!isWritable())
-    return;
-
-  if (-1 == ::ftruncate(m_FileDescriptor, static_cast<off_t>(pLength))) {
-    llvm::report_fatal_error(llvm::Twine("Cannot truncate `") +
-                             m_FilePath.native() +
-                             llvm::Twine("' to size: ") +
-                             llvm::Twine(pLength) +
-                             llvm::Twine(".\n"));
-  }
-}
-
-void MemoryArea::map(const sys::fs::Path& pPath, int pFlags)
-{
-  m_AccessFlags = pFlags;
-  m_FilePath = pPath;
-  m_FileDescriptor = ::open(m_FilePath.c_str(), m_AccessFlags);
-
-  if (-1 == m_FileDescriptor) {
-    m_State |= FailBit;
-  }
-  else {
-    struct stat st;
-    int stat_result = ::stat(m_FilePath.native().c_str(), &st);
-    if (0x0 == stat_result) {
-      m_FileSize = static_cast<size_t>(st.st_size);
-      m_State = GoodBit;
-    }
-    else {
-      m_FileSize = 0x0;
-      m_State |= FailBit;
-      m_State |= BadBit;
-    }
-  }
-}
-
-void MemoryArea::map(const sys::fs::Path& pPath, int pFlags, int pMode)
-{
-  m_AccessFlags = pFlags;
-  m_FilePath = pPath;
-  m_FileDescriptor = ::open(m_FilePath.c_str(), m_AccessFlags, pMode);
-
-  if (-1 == m_FileDescriptor) {
-    m_State |= FailBit;
-  }
-  else {
-    struct stat st;
-    int stat_result = ::stat(m_FilePath.native().c_str(), &st);
-    if (0x0 == stat_result) {
-      m_FileSize = static_cast<size_t>(st.st_size);
-      m_State = GoodBit;
-    }
-    else {
-      m_FileSize = 0x0;
-      m_State |= FailBit;
-      m_State |= BadBit;
-    }
-  }
-}
-
-void MemoryArea::unmap()
-{
-  if (isMapped()) {
-    if (-1 == ::close(m_FileDescriptor))
-      m_State |= FailBit;
-    else {
-      m_FileDescriptor = -1;
-      m_AccessFlags = ReadOnly;
-    }
-  }
-}
-
-bool MemoryArea::isMapped() const
-{
-  return (-1 != m_FileDescriptor);
-}
-
-bool MemoryArea::isGood() const
-{
-  return 0x0 == (m_State & (BadBit | FailBit));
-}
-
-bool MemoryArea::isBad() const
-{
-  return 0x0 != (m_State & BadBit);
-}
-
-bool MemoryArea::isFailed() const
-{
-  return 0x0 != (m_State & FailBit);
-}
-
-bool MemoryArea::isEOF() const
-{
-  return 0x0 != (m_State & EOFBit);
-}
-
-bool MemoryArea::isReadable() const
-{
-  return (((m_AccessFlags & AccessMask) == ReadOnly) ||
-         ((m_AccessFlags & AccessMask) == ReadWrite));
-}
-
-bool MemoryArea::isWritable() const
-{
-  return (((m_AccessFlags & AccessMask) == WriteOnly) ||
-         ((m_AccessFlags & AccessMask) == ReadWrite));
-}
-
-int MemoryArea::rdstate() const
-{
-  return m_State;
-}
-
-void MemoryArea::setState(MemoryArea::IOState pState)
-{
-  m_State |= pState;
-}
-
-void MemoryArea::clear(MemoryArea::IOState pState)
-{
-  m_State = pState;
 }
 
 // The layout of MemorySpace in the virtual memory space
@@ -185,242 +52,100 @@
 //
 MemoryRegion* MemoryArea::request(size_t pOffset, size_t pLength)
 {
-  if (!isMapped() || !isGood())
-    return NULL;
-
-  if (0x0 == pLength)
-    return NULL;
-
-  if (!isWritable() && (pOffset + pLength) > m_FileSize)
-    return NULL;
-
-  if (isWritable() && (pOffset + pLength) > m_FileSize) {
-    // If the memory area is writable, user can expand the size of file by
-    // request a region larger than the file.
-    // MemoryArea should enlarge the file if the requested region is larger
-    // than the file.
-    m_FileSize = page_boundary(pOffset + pLength + 1);
-    truncate(m_FileSize);
-  }
-
   Space* space = find(pOffset, pLength);
-  MemoryArea::Address r_start = 0;
   if (NULL == space) {
-    // the space does not exist, create a new space.
-    space = new Space(this, pOffset, pLength);
+
+    // not found
+    if (NULL == m_pFileHandle) {
+      // if m_pFileHandle is NULL, clients delegate us an universal Space and
+      // we never remove it. In that way, space can not be NULL.
+      unreachable(diag::err_out_of_range_region);
+    }
+
+    space = Space::createSpace(*m_pFileHandle, pOffset, pLength);
     m_SpaceList.push_back(space);
-    switch(space->type = policy(pOffset, pLength)) {
-      case Space::MMAPED: {
-        int mm_prot, mm_flag;
-        if (isWritable()) {
-          mm_prot = PROT_READ | PROT_WRITE;
-          mm_flag = MAP_FILE | MAP_SHARED;
-        }
-        else {
-          mm_prot = PROT_READ;
-          mm_flag = MAP_FILE | MAP_PRIVATE;
-        }
-
-        space->file_offset = page_offset(pOffset);
-
-        // The space's size may be larger than filesize.
-        space->size = page_boundary(pLength + pOffset + 1 - space->file_offset);
-        space->data = (Address) ::mmap(NULL,
-                                       space->size,
-                                       mm_prot, mm_flag,
-                                       m_FileDescriptor,
-                                       space->file_offset);
-
-        if (space->data == MAP_FAILED) {
-          llvm::report_fatal_error(llvm::Twine("cannot open memory map file :") +
-                                   m_FilePath.native() +
-                                   llvm::Twine(" (") +
-                                   sys::fs::detail::strerror(errno) +
-                                   llvm::Twine(").\n"));
-        }
-
-        r_start = space->data + (pOffset - space->file_offset);
-        break;
-      }
-      case Space::ALLOCATED_ARRAY: {
-        // space->offset and space->size are set in constructor. We only need
-        // to set up data.
-        space->data = new unsigned char[pLength];
-        r_start = space->data;
-        if ((m_AccessFlags & AccessMask) != WriteOnly) {
-          // Read data from the backend file.
-          if (!read(*space)) {
-            llvm::report_fatal_error(llvm::Twine("Failed to read data from ") +
-                                     m_FilePath.native() +
-                                     llvm::Twine(" (") +
-                                     sys::fs::detail::strerror(errno) +
-                                     llvm::Twine(") at offset ") +
-                                     llvm::Twine(pOffset) +
-                                     llvm::Twine(" lenght ") +
-                                     llvm::Twine(pLength) + llvm::Twine(".\n"));
-          }
-        }
-        break;
-      } // case
-      default: {
-        llvm::report_fatal_error("unhandled space type\n");
-      }
-    } // switch
   }
-  else { // found
-    off_t distance = pOffset - space->file_offset;
-    r_start = space->data + distance;
-  }
+
+  // adjust r_start
+  off_t distance = pOffset - space->start();
+  void* r_start = space->memory() + distance;
 
   // now, we have a legal space to hold the new MemoryRegion
-  return m_RegionFactory.produce(space, r_start, pLength);
+  return m_RegionFactory.produce(*space, r_start, pLength);
 }
 
 // release - release a MemoryRegion
 void MemoryArea::release(MemoryRegion* pRegion)
 {
-  if (!isMapped() || !isGood())
+  if (NULL == pRegion)
     return;
 
   Space *space = pRegion->parent();
   m_RegionFactory.destruct(pRegion);
 
-  if (0 == space->region_num) {
-    write(*space);
-    m_SpaceList.remove(*space);
-    release(space);
+  if (0 == space->numOfRegions()) {
+
+    if (NULL != m_pFileHandle) {
+      // if m_pFileHandle is NULL, clients delegate us an universal Space and
+      // we never remove it. Otherwise, we have to synchronize and release
+      // Space.
+      if (m_pFileHandle->isWritable()) {
+        // synchronize writable space before we release it.
+        Space::syncSpace(space, *m_pFileHandle);
+      }
+      Space::releaseSpace(space, *m_pFileHandle);
+    }
+    m_SpaceList.erase(space);
   }
 }
 
-void MemoryArea::clean()
+// clear - release all MemoryRegions
+void MemoryArea::clear()
 {
-  m_RegionFactory.clear();
+  if (NULL == m_pFileHandle)
+    return;
 
-  SpaceList::iterator sIter, sEnd = m_SpaceList.end();
-  for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
-    write(*sIter);
-    release(sIter);
+  if (m_pFileHandle->isWritable()) {
+    SpaceList::iterator space, sEnd = m_SpaceList.end();
+    for (space = m_SpaceList.begin(); space != sEnd; ++space) {
+      Space::syncSpace(space, *m_pFileHandle);
+      Space::releaseSpace(space, *m_pFileHandle);
+    }
   }
+  else {
+    SpaceList::iterator space, sEnd = m_SpaceList.end();
+    for (space = m_SpaceList.begin(); space != sEnd; ++space)
+      Space::releaseSpace(space, *m_pFileHandle);
+  }
+
   m_SpaceList.clear();
 }
 
-void MemoryArea::sync()
+//===--------------------------------------------------------------------===//
+// SpaceList methods
+Space* MemoryArea::find(size_t pOffset, size_t pLength)
 {
   SpaceList::iterator sIter, sEnd = m_SpaceList.end();
   for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
-    write(*sIter);
-  }
-}
-
-MemoryArea::Space* MemoryArea::find(size_t pOffset, size_t pLength)
-{
-  SpaceList::iterator sIter, sEnd = m_SpaceList.end();
-  for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
-    if (sIter->file_offset <= pOffset &&
-       (pOffset+pLength) <= (sIter->file_offset+sIter->size) ) { // within
+    if (sIter->start() <= pOffset &&
+       (pOffset+pLength) <= (sIter->start()+sIter->size()) ) {
+      // within
       return sIter;
     }
   }
   return NULL;
 }
 
-void MemoryArea::release(MemoryArea::Space* pSpace)
+const Space* MemoryArea::find(size_t pOffset, size_t pLength) const
 {
-  switch (pSpace->type) {
-    case Space::ALLOCATED_ARRAY: {
-      delete [] pSpace->data;
-      break;
-    }
-    case Space::MMAPED: {
-      ::munmap(pSpace->data, pSpace->size);
-      break;
-    }
-    default:
-      break;
-  }
-}
-
-MemoryArea::Space::Type MemoryArea::policy(off_t pOffset, size_t pLength)
-{
-  const size_t threshold = (PageSize*3)/4; // 3/4 page size in Linux
-  if (pLength < threshold)
-    return Space::ALLOCATED_ARRAY;
-  else
-    return Space::MMAPED;
-}
-
-ssize_t MemoryArea::readToBuffer(sys::fs::detail::Address pBuf,
-                                 size_t pSize, size_t pOffset) {
-  assert(((m_AccessFlags & AccessMask) != WriteOnly) &&
-         "Write-only file cannot be read!");
-
-  ssize_t read_bytes = sys::fs::detail::pread(m_FileDescriptor, pBuf,
-                                              pSize, pOffset);
-  if (static_cast<size_t>(read_bytes) != pSize) {
-    // Some error occurred during pread().
-    if (read_bytes < 0) {
-      m_State |= FailBit;
-    }
-    else if (static_cast<size_t>(read_bytes) < pSize) {
-      m_State |= EOFBit;
-      if ((m_AccessFlags & AccessMask) != ReadWrite) {
-        // Files which is not read-write are not allowed read beyonds the EOF
-        // marker.
-        m_State |= BadBit;
-      }
-    }
-    else {
-      m_State |= BadBit;
+  SpaceList::const_iterator sIter, sEnd = m_SpaceList.end();
+  for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
+    if (sIter->start() <= pOffset &&
+       (pOffset+pLength) <= (sIter->start()+sIter->size()) ) {
+      // within
+      return sIter;
     }
   }
-  return read_bytes;
-}
-
-bool MemoryArea::read(Space& pSpace) {
-  if (!isGood() || !isReadable())
-    return false;
-
-  if (pSpace.type == Space::ALLOCATED_ARRAY) {
-    readToBuffer(pSpace.data, pSpace.size, pSpace.file_offset);
-    return isGood();
-  }
-  else {
-    // Data associated with mmap()'ed space is already at the position the
-    // pSpace points to.
-    assert((pSpace.type == Space::MMAPED) && "Unknown type of Space!");
-    return true;
-  }
-}
-
-
-void MemoryArea::write(const Space& pSpace)
-{
-  if (!isMapped() || !isGood() || !isWritable())
-    return;
-
-  switch(pSpace.type) {
-    case Space::MMAPED: {
-      if(-1 == ::msync(pSpace.data, pSpace.size, MS_SYNC))
-        m_State |= FailBit;
-      return;
-    }
-    case Space::ALLOCATED_ARRAY: {
-      ssize_t write_bytes = sys::fs::detail::pwrite(m_FileDescriptor,
-                                                    pSpace.data,
-                                                    pSpace.size,
-                                                    pSpace.file_offset);
-      if (0 > write_bytes) {
-        m_State |= FailBit;
-        return;
-      }
-      if (0 == write_bytes && 0 != pSpace.size)
-        m_State |= BadBit;
-      if ( pSpace.size > static_cast<size_t>(write_bytes) )
-        m_State |= EOFBit;
-      return;
-    }
-    default:
-      return;
-  }
+  return NULL;
 }
 
diff --git a/lib/Support/MemoryAreaFactory.cpp b/lib/Support/MemoryAreaFactory.cpp
index 1f7e523..3da07d5 100644
--- a/lib/Support/MemoryAreaFactory.cpp
+++ b/lib/Support/MemoryAreaFactory.cpp
@@ -6,15 +6,18 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
-#include "mcld/Support/MemoryAreaFactory.h"
-#include "mcld/Support/RegionFactory.h"
+#include <mcld/Support/MemoryAreaFactory.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/RegionFactory.h>
+#include <mcld/Support/SystemUtils.h>
+#include <mcld/Support/Space.h>
 
 using namespace mcld;
 
-//==========================
+//===----------------------------------------------------------------------===//
 // MemoryAreaFactory
 MemoryAreaFactory::MemoryAreaFactory(size_t pNum)
-  : UniqueGCFactoryBase<sys::fs::Path, MemoryArea, 0>(pNum) {
+  : GCFactory<MemoryArea, 0>(pNum) {
   // For each loaded file, MCLinker must load ELF header, section header,
   // symbol table, and string table. So, we set the size of chunk quadruple
   // larger than the number of input files.
@@ -23,30 +26,91 @@
 
 MemoryAreaFactory::~MemoryAreaFactory()
 {
+  HandleToArea::iterator rec, rEnd = m_HandleToArea.end();
+  for (rec = m_HandleToArea.begin(); rec != rEnd; ++rec) {
+    if (rec->handle->isOpened()) {
+      rec->handle->close();
+    }
+    delete rec->handle;
+  }
+
   delete m_pRegionFactory;
 }
 
-MemoryArea* MemoryAreaFactory::produce(const sys::fs::Path& pPath, int pFlags)
+MemoryArea*
+MemoryAreaFactory::produce(const sys::fs::Path& pPath,
+                           FileHandle::OpenMode pMode)
 {
-  MemoryArea* result = find(pPath);
-  if (0 == result) {
-    result = allocate();
-    new (result) MemoryArea(*m_pRegionFactory);
-    result->map(pPath, pFlags);
-    f_KeyMap.insert(std::make_pair(pPath, result));
+  HandleToArea::Result map_result = m_HandleToArea.findFirst(pPath);
+  if (NULL == map_result.area) {
+    // can not found
+    FileHandle* handler = new FileHandle();
+    if (!handler->open(pPath, pMode)) {
+      error(diag::err_cannot_open_file) << pPath
+                                        << sys::strerror(handler->error());
+    }
+
+    MemoryArea* result = allocate();
+    new (result) MemoryArea(*m_pRegionFactory, *handler);
+
+    m_HandleToArea.push_back(handler, result);
+    return result;
   }
+
+  return map_result.area;
+}
+
+MemoryArea*
+MemoryAreaFactory::produce(const sys::fs::Path& pPath,
+                           FileHandle::OpenMode pMode,
+                           FileHandle::Permission pPerm)
+{
+  HandleToArea::Result map_result = m_HandleToArea.findFirst(pPath);
+  if (NULL == map_result.area) {
+    // can not found
+    FileHandle* handler = new FileHandle();
+    if (!handler->open(pPath, pMode, pPerm)) {
+      error(diag::err_cannot_open_file) << pPath
+                                        << sys::strerror(handler->error());
+    }
+
+    MemoryArea* result = allocate();
+    new (result) MemoryArea(*m_pRegionFactory, *handler);
+
+    m_HandleToArea.push_back(handler, result);
+    return result;
+  }
+
+  return map_result.area;
+}
+
+void MemoryAreaFactory::destruct(MemoryArea* pArea)
+{
+  m_HandleToArea.erase(pArea);
+  pArea->clear();
+  pArea->handler()->close();
+  destroy(pArea);
+  deallocate(pArea);
+}
+
+MemoryArea*
+MemoryAreaFactory::create(void* pMemBuffer, size_t pSize)
+{
+  Space* space = new Space(Space::EXTERNAL, pMemBuffer, pSize);
+  MemoryArea* result = allocate();
+  new (result) MemoryArea(*m_pRegionFactory, *space);
   return result;
 }
 
-MemoryArea* MemoryAreaFactory::produce(const sys::fs::Path& pPath, int pFlags, mode_t pMode)
+MemoryArea*
+MemoryAreaFactory::create(int pFD, FileHandle::OpenMode pMode)
 {
-  MemoryArea* result = find(pPath);
-  if (0 == result) {
-    result = allocate();
-    new (result) MemoryArea(*m_pRegionFactory);
-    result->map(pPath, pFlags, pMode);
-    f_KeyMap.insert(std::make_pair(pPath, result));
-  }
+  FileHandle* handler = new FileHandle();
+  handler->delegate(pFD, pMode);
+  
+  MemoryArea* result = allocate();
+  new (result) MemoryArea(*m_pRegionFactory, *handler);
+
   return result;
 }
 
diff --git a/lib/Support/MemoryRegion.cpp b/lib/Support/MemoryRegion.cpp
index 3a35f4e..32e790b 100644
--- a/lib/Support/MemoryRegion.cpp
+++ b/lib/Support/MemoryRegion.cpp
@@ -12,23 +12,13 @@
 
 //==========================
 // MemoryRegion
-MemoryRegion::MemoryRegion(MemoryArea::Space *pParentSpace,
-                           const MemoryRegion::Address pVMAStart,
+MemoryRegion::MemoryRegion(Space& pParent,
+                           MemoryRegion::Address pVMAStart,
                            size_t pSize)
-  : m_pParentSpace(pParentSpace), m_VMAStart(pVMAStart), m_Length(pSize) {
-  m_pParentSpace->region_num++;
+  : m_Parent(pParent), m_VMAStart(pVMAStart), m_Length(pSize) {
 }
 
 MemoryRegion::~MemoryRegion()
 {
-  drift();
-}
-
-void MemoryRegion::drift()
-{
-  if (NULL == m_pParentSpace)
-    return;
-  m_pParentSpace->region_num--;
-  m_pParentSpace = NULL;
 }
 
diff --git a/lib/Support/MsgHandling.cpp b/lib/Support/MsgHandling.cpp
new file mode 100644
index 0000000..5b45289
--- /dev/null
+++ b/lib/Support/MsgHandling.cpp
@@ -0,0 +1,74 @@
+//===- MsgHandling.cpp ----------------------------------------------------===//
+//
+//                     The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/DiagnosticEngine.h>
+#include <mcld/LD/DiagnosticLineInfo.h>
+#include <mcld/LD/DiagnosticPrinter.h>
+#include <mcld/LD/MsgHandler.h>
+#include <mcld/Support/MsgHandling.h>
+#include <llvm/Support/ManagedStatic.h>
+#include <llvm/Support/raw_ostream.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// DiagnosticInitializer
+class DiagnosticInitializer : public llvm::ManagedStaticBase
+{
+public:
+  DiagnosticEngine* initialize(const MCLDInfo& pLDInfo,
+                               DiagnosticLineInfo* pLineInfo,
+                               DiagnosticPrinter* pPrinter)
+  {
+    RegisterManagedStatic(NULL, llvm::object_deleter<DiagnosticEngine>::call);
+    if (llvm::llvm_is_multithreaded()) {
+      llvm::llvm_acquire_global_lock();
+      void* tmp = NULL;
+      if (NULL != pPrinter)
+        tmp = new DiagnosticEngine(pLDInfo, pLineInfo, pPrinter, false);
+      else
+        tmp = new DiagnosticEngine(pLDInfo, pLineInfo, NULL, false);
+
+      TsanHappensBefore(this);
+      llvm::sys::MemoryFence();
+      TsanIgnoreWritesBegin();
+      Ptr = tmp;
+      TsanIgnoreWritesEnd();
+      llvm::llvm_release_global_lock();
+    }
+    else {
+      if (NULL != pPrinter)
+        Ptr = new DiagnosticEngine(pLDInfo, pLineInfo, pPrinter, false);
+      else
+        Ptr = new DiagnosticEngine(pLDInfo, pLineInfo, NULL, false);
+    }
+    return static_cast<DiagnosticEngine*>(Ptr);
+  }
+};
+
+static DiagnosticInitializer g_DiagInitializer;
+static DiagnosticEngine* g_pDiagnosticEngine = NULL;
+
+void mcld::InitializeDiagnosticEngine(const mcld::MCLDInfo& pLDInfo,
+                                DiagnosticLineInfo* pLineInfo,
+                                DiagnosticPrinter* pPrinter)
+{
+  if (NULL == g_pDiagnosticEngine) {
+    g_pDiagnosticEngine = g_DiagInitializer.initialize(pLDInfo,
+                                                       pLineInfo,
+                                                       pPrinter);
+  }
+}
+
+DiagnosticEngine& mcld::getDiagnosticEngine()
+{
+  assert(NULL != g_pDiagnosticEngine &&
+         "mcld::InitializeDiagnostics() is not called");
+  return *g_pDiagnosticEngine;
+}
+
diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp
index ffb449f..8cc384d 100644
--- a/lib/Support/Path.cpp
+++ b/lib/Support/Path.cpp
@@ -11,11 +11,8 @@
 #include <llvm/ADT/StringRef.h>
 
 #include <locale>
-#include <stdio.h>
 #include <string.h>
 
-#include <iostream>
-
 using namespace mcld;
 using namespace mcld::sys::fs;
 
@@ -119,7 +116,7 @@
 Path::StringType::size_type Path::m_append_separator_if_needed()
 {
   if (!m_PathName.empty() &&
-#ifdef LLVM_ON_WIN32
+#if defined(MCLD_ON_WIN32)
       *(m_PathName.end()-1) != colon &&
 #endif
       !is_separator(*(m_PathName.end()-1))) {
@@ -171,7 +168,7 @@
 bool mcld::sys::fs::is_separator(char value)
 {
   return (value == separator
-#ifdef LLVM_ON_WIN32
+#if defined(MCLD_ON_WIN32)
           || value == preferred_separator
 #endif
           );
diff --git a/lib/Support/RegionFactory.cpp b/lib/Support/RegionFactory.cpp
index e87d389..ddce433 100644
--- a/lib/Support/RegionFactory.cpp
+++ b/lib/Support/RegionFactory.cpp
@@ -6,8 +6,9 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
-#include "mcld/Support/RegionFactory.h"
-#include "mcld/Support/MemoryArea.h"
+#include <mcld/Support/RegionFactory.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/Space.h>
 
 using namespace mcld;
 
@@ -21,18 +22,19 @@
 {
 }
 
-MemoryRegion* RegionFactory::produce(MemoryArea::Space* pSpace,
-                                     const sys::fs::detail::Address pVMAStart,
-                                     size_t pSize)
+MemoryRegion* RegionFactory::produce(Space& pSpace, void* pVMAStart, size_t pSize)
 {
   MemoryRegion* result = Alloc::allocate();
-  new (result) MemoryRegion(pSpace, pVMAStart, pSize);
+  new (result) MemoryRegion(pSpace,
+                            static_cast<const MemoryRegion::Address>(pVMAStart),
+                            pSize);
+  pSpace.addRegion(*result);
   return result;
 }
 
 void RegionFactory::destruct(MemoryRegion* pRegion)
 {
-  pRegion->drift();
+  pRegion->parent()->removeRegion(*pRegion);
   destroy(pRegion);
   deallocate(pRegion);
 }
diff --git a/lib/Support/Space.cpp b/lib/Support/Space.cpp
new file mode 100644
index 0000000..4024da1
--- /dev/null
+++ b/lib/Support/Space.cpp
@@ -0,0 +1,179 @@
+//===- Space.cpp ----------------------------------------------------------===//
+//
+//                     The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/Space.h>
+#include <mcld/Support/FileHandle.h>
+#include <mcld/Support/MsgHandling.h>
+#include <cstdlib>
+#include <unistd.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// constant data
+static const off_t PageSize = getpagesize();
+
+//===----------------------------------------------------------------------===//
+// Non-member functions
+//
+// low address      A page             high address
+// |--------------------|------------------|
+// ^ page_offset        ^ pFileOffset      ^ page_boundary
+
+// Given a file offset, return the page offset.
+// return the first page boundary \b before pFileOffset
+inline static off_t page_offset(off_t pFileOffset)
+{ return pFileOffset & ~ (PageSize - 1); }
+
+// page_boundary - Given a file size, return the size to read integral pages.
+// return the first page boundary \b after pFileOffset
+inline static off_t page_boundary(off_t pFileOffset)
+{ return (pFileOffset + (PageSize - 1)) & ~ (PageSize - 1); }
+
+inline static Space::Type policy(off_t pOffset, size_t pLength)
+{
+  const size_t threshold = (PageSize*3)/4; // 3/4 page size in Linux
+  if (pLength < threshold)
+    return Space::ALLOCATED_ARRAY;
+  else
+    return Space::MMAPED;
+}
+
+//===----------------------------------------------------------------------===//
+// Space
+Space::Space()
+  : m_Data(NULL), m_StartOffset(0), m_Size(0),
+    m_RegionCount(0), m_Type(UNALLOCATED) {
+}
+
+Space::Space(Space::Type pType, void* pMemBuffer, size_t pSize)
+  : m_Data(static_cast<Address>(pMemBuffer)), m_StartOffset(0), m_Size(pSize),
+    m_RegionCount(0), m_Type(pType)
+{
+}
+
+Space::~Space()
+{
+  // do nothing. m_Data is deleted by @ref releaseSpace
+}
+
+Space* Space::createSpace(FileHandle& pHandler,
+                          size_t pStart, size_t pSize)
+{
+  Type type;
+  void* memory;
+  Space* result = NULL;
+  size_t start, size = 0, total_offset;
+  switch(type = policy(pStart, pSize)) {
+    case ALLOCATED_ARRAY: {
+      // adjust total_offset, start and size
+      total_offset = pStart + pSize;
+      start = pStart;
+      if (total_offset > pHandler.size()) {
+        if (pHandler.isWritable()) {
+          size = pSize;
+          pHandler.truncate(total_offset);
+        }
+        else if (pHandler.size() > start)
+          size = pHandler.size() - start;
+        else {
+          // create a space out of a read-only file.
+          fatal(diag::err_cannot_read_small_file) << pHandler.path()
+                                                  << pHandler.size()
+                                                  << start << size;
+        }
+      }
+      else
+        size = pSize;
+
+      // malloc
+      memory = (void*)malloc(size);
+      if (!pHandler.read(memory, start, size))
+        error(diag::err_cannot_read_file) << pHandler.path() << start << size;
+
+      break;
+    }
+    case MMAPED: {
+      // adjust total_offset, start and size
+      total_offset = page_boundary(pStart + pSize);
+      start = page_offset(pStart);
+      if (total_offset > pHandler.size()) {
+        if (pHandler.isWritable()) {
+          size = page_boundary((pStart - start) + pSize);
+          pHandler.truncate(total_offset);
+        }
+        else if (pHandler.size() > start)
+          size = pHandler.size() - start;
+        else {
+          // create a space out of a read-only file.
+          fatal(diag::err_cannot_read_small_file) << pHandler.path()
+                                                  << pHandler.size()
+                                                  << start << size;
+        }
+      }
+      else
+        size = page_boundary((pStart - start) + pSize);
+
+      // mmap
+      if (!pHandler.mmap(memory, start, size))
+        error(diag::err_cannot_mmap_file) << pHandler.path() << start << size;
+
+      break;
+    }
+    default:
+      break;
+  } // end of switch
+
+  result = new Space(type, memory, size);
+  result->setStart(start);
+  return result;
+}
+
+void Space::releaseSpace(Space* pSpace, FileHandle& pHandler)
+{
+  if (NULL == pSpace)
+    return;
+
+  switch(pSpace->type()) {
+    case ALLOCATED_ARRAY:
+      free(pSpace->memory());
+      break;
+    case MMAPED:
+      if (!pHandler.munmap(pSpace->memory(), pSpace->size()))
+        error(diag::err_cannot_munmap_file) << pHandler.path();
+      break;
+    default: // external and unallocated memory buffers
+      break;
+  } // end of switch
+}
+
+void Space::syncSpace(Space* pSpace, FileHandle& pHandler)
+{
+  if (NULL == pSpace || !pHandler.isWritable())
+    return;
+
+  switch(pSpace->type()) {
+    case Space::ALLOCATED_ARRAY: {
+      if (!pHandler.write(pSpace->memory(),
+                          pSpace->start(),
+                          pSpace->size())) {
+        error(diag::err_cannot_write_file) << pHandler.path()
+                                           << pSpace->start()
+                                           << pSpace->size();
+      }
+      return;
+    }
+    case Space::MMAPED:
+    default: {
+      // system will eventually write bakc the memory after
+      // calling ::munmap
+      return;
+    }
+  } // end of switch
+}
+
diff --git a/lib/Support/SystemUtils.cpp b/lib/Support/SystemUtils.cpp
new file mode 100644
index 0000000..5dfea36
--- /dev/null
+++ b/lib/Support/SystemUtils.cpp
@@ -0,0 +1,20 @@
+//===- SystemUtils.cpp ----------------------------------------------------===//
+//
+//                     The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/SystemUtils.h>
+
+using namespace mcld::sys;
+
+//===----------------------------------------------------------------------===//
+// Non-member functions
+#if defined(MCLD_ON_UNIX)
+#include "Unix/System.inc"
+#endif
+#if defined(MCLD_ON_WIN32)
+#include "Windows/System.inc"
+#endif 
diff --git a/lib/Support/TargetRegistry.cpp b/lib/Support/TargetRegistry.cpp
index 246cbe8..8bfa235 100644
--- a/lib/Support/TargetRegistry.cpp
+++ b/lib/Support/TargetRegistry.cpp
@@ -6,13 +6,11 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
-#include "mcld/Support/TargetRegistry.h"
+#include <mcld/Support/TargetRegistry.h>
 
 
 mcld::TargetRegistry::TargetListTy mcld::TargetRegistry::s_TargetList;
 
-/* ** */
-
 void mcld::TargetRegistry::RegisterTarget(mcld::Target &T)
 {
   s_TargetList.push_back(&T);
@@ -34,7 +32,7 @@
 const mcld::Target *mcld::TargetRegistry::lookupTarget(const std::string &pTriple,
                                                        std::string &pError) 
 {
-  const llvm::Target* target = llvm::TargetRegistry::lookupTarget( pTriple, pError );
+  const llvm::Target* target = llvm::TargetRegistry::lookupTarget(pTriple, pError);
   if (!target)
     return 0;
   return lookupTarget( *target );
diff --git a/lib/Support/Unix/FileSystem.inc b/lib/Support/Unix/FileSystem.inc
index 6499d66..ce6d0df 100644
--- a/lib/Support/Unix/FileSystem.inc
+++ b/lib/Support/Unix/FileSystem.inc
@@ -9,6 +9,7 @@
 #include <string>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <unistd.h>
 #include <fcntl.h>
 
 namespace mcld{
@@ -23,19 +24,29 @@
 std::string assembly_extension = ".s";
 std::string bitcode_extension = ".bc";
 
-size_t pread(int pFD, Address pBuf, size_t pCount, off_t pOffset)
+int open(const Path& pPath, int pOFlag)
 {
-  return ::pread(pFD, (void*) pBuf, pCount, pOffset);
+  return ::open(pPath.native().c_str(), pOFlag);
 }
 
-size_t pwrite(int pFD, const Address pBuf, size_t pCount, off_t pOffset)
+int open(const Path& pPath, int pOFlag, int pPerm)
 {
-  return ::pwrite(pFD, (const void*) pBuf, pCount, pOffset);
+  return ::open(pPath.native().c_str(), pOFlag, pPerm);
 }
 
-char *strerror(int errnum)
+ssize_t pread(int pFD, void* pBuf, size_t pCount, size_t pOffset)
 {
-  return ::strerror(errnum);
+  return ::pread(pFD, pBuf, pCount, pOffset);
+}
+
+ssize_t pwrite(int pFD, const void* pBuf, size_t pCount, size_t pOffset)
+{
+  return ::pwrite(pFD, pBuf, pCount, pOffset);
+}
+
+int ftruncate(int pFD, size_t pLength)
+{
+  return ::ftruncate(pFD, pLength);
 }
 
 } // namespace of detail
diff --git a/lib/Support/Unix/PathV3.inc b/lib/Support/Unix/PathV3.inc
index 2e8e6d0..68b0c36 100644
--- a/lib/Support/Unix/PathV3.inc
+++ b/lib/Support/Unix/PathV3.inc
@@ -282,7 +282,7 @@
 {
   if (pDir.m_Handler)
     closedir(reinterpret_cast<DIR *>(pDir.m_Handler));
-  pDir.m_Handler = NULL;
+  pDir.m_Handler = 0;
 }
 
 void get_pwd(std::string& pPWD)
diff --git a/lib/Support/Unix/System.inc b/lib/Support/Unix/System.inc
new file mode 100644
index 0000000..716aaa2
--- /dev/null
+++ b/lib/Support/Unix/System.inc
@@ -0,0 +1,24 @@
+//===- System.inc ---------------------------------------------------------===//
+//
+//                     The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <string>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace mcld{
+namespace sys{
+
+char *strerror(int errnum)
+{
+  return ::strerror(errnum);
+}
+
+} // namespace of sys
+} // namespace of mcld
+
diff --git a/lib/Support/Windows/System.inc b/lib/Support/Windows/System.inc
new file mode 100644
index 0000000..bfd75ee
--- /dev/null
+++ b/lib/Support/Windows/System.inc
@@ -0,0 +1,19 @@
+//===- System.inc ---------------------------------------------------------===//
+//
+//                     The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <string>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace mcld{
+namespace sys{
+
+} // namespace of sys
+} // namespace of mcld
+
diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp
new file mode 100644
index 0000000..2453c2c
--- /dev/null
+++ b/lib/Support/raw_ostream.cpp
@@ -0,0 +1,95 @@
+//===- raw_ostream.cpp ----------------------------------------------------===//
+//
+//                     The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/raw_ostream.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// raw_ostream
+mcld::raw_fd_ostream::raw_fd_ostream(const char *pFilename,
+                               std::string &pErrorInfo,
+                               unsigned int pFlags,
+                               const MCLDInfo* pLDInfo)
+  : llvm::raw_fd_ostream(pFilename, pErrorInfo, pFlags), m_pLDInfo(pLDInfo) {
+}
+
+mcld::raw_fd_ostream::raw_fd_ostream(int pFD,
+                               bool pShouldClose,
+                               bool pUnbuffered,
+                               const MCLDInfo* pLDInfo)
+  : llvm::raw_fd_ostream(pFD, pShouldClose, pUnbuffered), m_pLDInfo(pLDInfo) {
+}
+
+mcld::raw_fd_ostream::~raw_fd_ostream()
+{
+}
+
+void mcld::raw_fd_ostream::setLDInfo(const MCLDInfo& pLDInfo)
+{
+  m_pLDInfo = &pLDInfo;
+}
+
+llvm::raw_ostream &
+mcld::raw_fd_ostream::changeColor(enum llvm::raw_ostream::Colors pColor,
+                                  bool pBold,
+                                  bool pBackground)
+{
+  if (!is_displayed())
+    return *this;
+  return llvm::raw_fd_ostream::changeColor(pColor, pBold, pBackground);
+}
+
+llvm::raw_ostream& mcld::raw_fd_ostream::resetColor()
+{
+  if (!is_displayed())
+    return *this;
+  return llvm::raw_fd_ostream::resetColor();
+}
+
+// FIXME: migrate to newer LLVM
+/**
+llvm::raw_ostream& mcld::raw_fd_ostream::reverseColor()
+{
+  if (!is_displayed())
+    return *this;
+  return llvm::raw_ostream::reverseColor();
+}
+**/
+
+bool mcld::raw_fd_ostream::is_displayed() const
+{
+  if (NULL == m_pLDInfo)
+    return llvm::raw_fd_ostream::is_displayed();
+
+  return m_pLDInfo->options().color();
+}
+
+//===----------------------------------------------------------------------===//
+//  outs(), errs(), nulls()
+//===----------------------------------------------------------------------===//
+mcld::raw_fd_ostream& mcld::outs() {
+  // Set buffer settings to model stdout behavior.
+  // Delete the file descriptor when the program exists, forcing error
+  // detection. If you don't want this behavior, don't use outs().
+  static mcld::raw_fd_ostream S(STDOUT_FILENO, true, NULL);
+  return S;
+}
+
+mcld::raw_fd_ostream& mcld::errs() {
+  // Set standard error to be unbuffered by default.
+  static mcld::raw_fd_ostream S(STDERR_FILENO, false, true, NULL);
+  return S;
+}
+
+void mcld::InitializeOStreams(const MCLDInfo& pLDInfo)
+{
+  outs().setLDInfo(pLDInfo);
+  errs().setLDInfo(pLDInfo);
+}
+