Update mclinker for LLVM rebase.

commit 6824c791204cf5daabdfe008ee8808799f348815
Author: Pete Chou <[email protected]>
Date:   Tue Jul 15 10:15:12 2014 +0800

    Fix typo in README.

Change-Id: Id7a525732ba33b5ac81a0da4c8d8f02d1f8c3a16
diff --git a/include/mcld/Config/Config.h b/include/mcld/Config/Config.h
index 9e52d54..2973426 100644
--- a/include/mcld/Config/Config.h
+++ b/include/mcld/Config/Config.h
@@ -27,11 +27,14 @@
 #define MCLD_DEFAULT_TARGET_TRIPLE "x86_64-unknown-linux-gnu"
 
 /* MCLINKER version */
-#define MCLD_VERSION "2.3.0.RC-WhiteStone"
+#define MCLD_VERSION "2.9.0.dev-"
+
+/* Name of package */
+#define PACKAGE "mclinker"
 
 
 /* Version number of package */
-#define VERSION "WhiteStone"
+#define VERSION "dev"
 
 
 #define MCLD_REGION_CHUNK_SIZE 32
diff --git a/include/mcld/Config/Config.h.in b/include/mcld/Config/Config.h.in
index 39df682..4a38cbf 100644
--- a/include/mcld/Config/Config.h.in
+++ b/include/mcld/Config/Config.h.in
@@ -108,6 +108,7 @@
 #define MCLD_SECTIONS_PER_INPUT 16
 #define MCLD_SYMBOLS_PER_INPUT 128
 #define MCLD_RELOCATIONS_PER_INPUT 1024
+#define MCLD_SEGMENTS_PER_OUTPUT 8
 
 #endif
 
diff --git a/include/mcld/GeneralOptions.h b/include/mcld/GeneralOptions.h
index 226e5d1..1d6c9a3 100644
--- a/include/mcld/GeneralOptions.h
+++ b/include/mcld/GeneralOptions.h
@@ -8,10 +8,11 @@
 //===----------------------------------------------------------------------===//
 #ifndef MCLD_GENERALOPTIONS_H
 #define MCLD_GENERALOPTIONS_H
-#include <string>
-#include <vector>
 #include <mcld/Support/RealPath.h>
 #include <mcld/Support/FileSystem.h>
+#include <string>
+#include <vector>
+#include <set>
 
 namespace mcld {
 
@@ -39,6 +40,12 @@
     Both    = 0x3
   };
 
+  enum ICF {
+    ICF_None,
+    ICF_All,
+    ICF_Safe
+  };
+
   typedef std::vector<std::string> RpathList;
   typedef RpathList::iterator rpath_iterator;
   typedef RpathList::const_iterator const_rpath_iterator;
@@ -51,6 +58,12 @@
   typedef AuxiliaryList::iterator aux_iterator;
   typedef AuxiliaryList::const_iterator const_aux_iterator;
 
+  typedef std::vector<std::string> UndefSymList;
+  typedef UndefSymList::iterator undef_sym_iterator;
+  typedef UndefSymList::const_iterator const_undef_sym_iterator;
+
+  typedef std::set<std::string> ExcludeLIBS;
+
 public:
   GeneralOptions();
   ~GeneralOptions();
@@ -284,6 +297,13 @@
   bool GCSections() const
   { return m_bGCSections; }
 
+  // --print-gc-sections
+  void setPrintGCSections(bool pEnable = true)
+  { m_bPrintGCSections = pEnable; }
+
+  bool getPrintGCSections() const
+  { return m_bPrintGCSections; }
+
   // --ld-generated-unwind-info
   void setGenUnwindInfo(bool pEnable = true)
   { m_bGenUnwindInfo = pEnable; }
@@ -303,6 +323,21 @@
   void setHashStyle(unsigned int pStyle)
   { m_HashStyle = pStyle; }
 
+  ICF getICFMode() const { return m_ICF; }
+
+  void setICFMode(ICF pMode)
+  { m_ICF = pMode; }
+
+  size_t getICFIterations() const { return m_ICFIterations; }
+
+  void setICFIterations(size_t pNum)
+  { m_ICFIterations = pNum; }
+
+  bool printICFSections() const { return m_bPrintICFSections; }
+
+  void setPrintICFSections(bool pPrintICFSections)
+  { m_bPrintICFSections = pPrintICFSections; }
+
   // -----  link-in rpath  ----- //
   const RpathList& getRpathList() const { return m_RpathList; }
   RpathList&       getRpathList()       { return m_RpathList; }
@@ -321,6 +356,20 @@
   const_script_iterator script_end  () const { return m_ScriptList.end();   }
   script_iterator       script_end  ()       { return m_ScriptList.end();   }
 
+  // -----  -u/--undefined, undefined symbols ----- //
+  const UndefSymList& getUndefSymList() const { return m_UndefSymList; }
+  UndefSymList&       getUndefSymList()       { return m_UndefSymList; }
+
+  const_undef_sym_iterator undef_sym_begin() const
+  { return m_UndefSymList.begin(); }
+  undef_sym_iterator undef_sym_begin()
+  { return m_UndefSymList.begin(); }
+
+  const_undef_sym_iterator undef_sym_end() const
+  { return m_UndefSymList.end(); }
+  undef_sym_iterator undef_sym_end()
+  { return m_UndefSymList.end(); }
+
   // -----  filter and auxiliary filter  ----- //
   void setFilter(const std::string& pFilter)
   { m_Filter = pFilter; }
@@ -339,6 +388,13 @@
   const_aux_iterator aux_end  () const { return m_AuxiliaryList.end();   }
   aux_iterator       aux_end  ()       { return m_AuxiliaryList.end();   }
 
+  // -----  exclude libs  ----- //
+  ExcludeLIBS& excludeLIBS()
+  { return m_ExcludeLIBS; }
+
+  bool isInExcludeLIBS(const Input& pInput) const;
+
+
 private:
   enum status {
     YES,
@@ -389,14 +445,20 @@
   bool m_bPrintMap: 1; // --print-map
   bool m_bWarnMismatch: 1; // --no-warn-mismatch
   bool m_bGCSections: 1; // --gc-sections
+  bool m_bPrintGCSections:1; // --print-gc-sections
   bool m_bGenUnwindInfo: 1; // --ld-generated-unwind-info
+  bool m_bPrintICFSections: 1; // --print-icf-sections
+  ICF m_ICF;
+  size_t m_ICFIterations;
   uint32_t m_GPSize; // -G, --gpsize
   StripSymbolMode m_StripSymbols;
   RpathList m_RpathList;
   ScriptList m_ScriptList;
+  UndefSymList m_UndefSymList; // -u [symbol], --undefined [symbol]
   unsigned int m_HashStyle;
   std::string m_Filter;
   AuxiliaryList m_AuxiliaryList;
+  ExcludeLIBS m_ExcludeLIBS;
 };
 
 } // namespace of mcld
diff --git a/include/mcld/LD/BinaryReader.h b/include/mcld/LD/BinaryReader.h
index b713b06..26dab6f 100644
--- a/include/mcld/LD/BinaryReader.h
+++ b/include/mcld/LD/BinaryReader.h
@@ -9,7 +9,6 @@
 #ifndef MCLD_LD_BINARYREADER_H
 #define MCLD_LD_BINARYREADER_H
 #include "mcld/LD/LDReader.h"
-#include <llvm/Support/system_error.h>
 
 namespace mcld {
 
diff --git a/include/mcld/LD/BranchIsland.h b/include/mcld/LD/BranchIsland.h
index 09ac9dc..8733ddb 100644
--- a/include/mcld/LD/BranchIsland.h
+++ b/include/mcld/LD/BranchIsland.h
@@ -9,14 +9,15 @@
 #ifndef MCLD_LD_BRANCHISLAND_H
 #define MCLD_LD_BRANCHISLAND_H
 
-#include <llvm/Support/DataTypes.h>
-#include <llvm/ADT/StringRef.h>
 #include <mcld/ADT/HashEntry.h>
 #include <mcld/ADT/HashTable.h>
 #include <mcld/ADT/StringHash.h>
 #include <mcld/LD/SectionData.h>
 #include <mcld/LD/LDSymbol.h>
+#include <mcld/Fragment/FragmentRef.h>
 #include <mcld/Fragment/Stub.h>
+#include <llvm/Support/DataTypes.h>
+#include <llvm/ADT/StringRef.h>
 #include <string>
 
 namespace mcld {
@@ -133,9 +134,25 @@
     {
       bool operator() (const Key& KEY1, const Key& KEY2) const
       {
-        return (KEY1.prototype() == KEY2.prototype()) &&
-               (KEY1.symbol() == KEY2.symbol()) &&
-               (KEY1.addend() == KEY2.addend());
+        bool res = false;
+        if ((KEY1.prototype() == KEY2.prototype()) &&
+            (KEY1.addend() == KEY2.addend())) {
+
+          if (KEY1.symbol() == KEY2.symbol()) {
+            res = true;
+          } else {
+            // Folded symbols may use the existing stub.
+            if (KEY1.symbol()->hasFragRef() && KEY2.symbol()->hasFragRef()) {
+              const FragmentRef* ref1 = KEY1.symbol()->fragRef();
+              const FragmentRef* ref2 = KEY2.symbol()->fragRef();
+              if ((ref1->offset() == ref2->offset()) &&
+                  (ref1->frag()->getOffset() == ref2->frag()->getOffset())) {
+                res = true;
+              }
+            }
+          }
+        }
+        return res;
       }
     };
 
diff --git a/include/mcld/LD/BranchIslandFactory.h b/include/mcld/LD/BranchIslandFactory.h
index ef263b0..61a13ad 100644
--- a/include/mcld/LD/BranchIslandFactory.h
+++ b/include/mcld/LD/BranchIslandFactory.h
@@ -27,11 +27,13 @@
 {
 public:
   /// ctor
-  /// @param pMaxBranchRange - the max branch range of the target backend
+  /// @param pMaxFwdBranchRange - the max forward branch range of the target
+  /// @param pMaxBwdBranchRange - the max backward branch range of the target
   /// @param pMaxIslandSize - a predifned value (64KB here) to decide the max
   ///                         size of the island
-  BranchIslandFactory(uint64_t pMaxBranchRange,
-                      uint64_t pMaxIslandSize = 65536U);
+  BranchIslandFactory(int64_t pMaxFwdBranchRange,
+                      int64_t pMaxBwdBranchRange,
+                      size_t pMaxIslandSize = 65536U);
 
   ~BranchIslandFactory();
 
@@ -43,13 +45,15 @@
   /// @param pFragment - the fragment needs a branch island
   BranchIsland* produce(Fragment& pFragment);
 
-  /// find - find a island for the given fragment
-  /// @param pFragment - the fragment needs a branch isladn
-  BranchIsland* find(const Fragment& pFragment);
+  /// getIsland - find fwd and bwd islands for the fragment
+  /// @param pFragment - the fragment needs a branch island
+  /// @return - return the pair of <fwd island, bwd island>
+  std::pair<BranchIsland*, BranchIsland*> getIslands(const Fragment& pFragment);
 
 private:
-  uint64_t m_MaxBranchRange;
-  uint64_t m_MaxIslandSize;
+  int64_t m_MaxFwdBranchRange;
+  int64_t m_MaxBwdBranchRange;
+  size_t m_MaxIslandSize;
 };
 
 } // namespace of mcld
diff --git a/include/mcld/LD/DiagCommonKinds.inc b/include/mcld/LD/DiagCommonKinds.inc
index 539eafb..6bb1461 100644
--- a/include/mcld/LD/DiagCommonKinds.inc
+++ b/include/mcld/LD/DiagCommonKinds.inc
@@ -51,3 +51,4 @@
 DIAG(err_cannot_find_scriptfile, DiagnosticEngine::Fatal, "cannot open %0 file %1", "cannot open %0 file %1")
 DIAG(err_unsupported_archive, DiagnosticEngine::Error, "Unsupported archive type.", "Unsupported archive type.")
 DIAG(unexpected_frag_type, DiagnosticEngine::Unreachable, "Unexpected fragment type `%0' when constructing FG", "Unexpected fragment type `%0' when constructing FG")
+DIAG(debug_print_gc_sections, DiagnosticEngine::Debug, "removing unused section from '%0' in file '%1'", "removing unused section from '%0' in file '%1'")
diff --git a/include/mcld/LD/DiagLayouts.inc b/include/mcld/LD/DiagLayouts.inc
index fac7a32..513ee33 100644
--- a/include/mcld/LD/DiagLayouts.inc
+++ b/include/mcld/LD/DiagLayouts.inc
@@ -4,3 +4,5 @@
 DIAG(warn_duplicate_std_sectmap, DiagnosticEngine::Warning, "Duplicated definition of section map \"from %0 to %0\".", "Duplicated definition of section map \"from %0 to %0\".")
 DIAG(warn_rules_check_failed, DiagnosticEngine::Warning, "Illegal section mapping rule: %0 -> %1. (conflict with %2 -> %3)", "Illegal section mapping rule: %0 -> %1. (conflict with %2 -> %3)")
 DIAG(err_cannot_merge_section, DiagnosticEngine::Error, "Cannot merge section %0 of %1", "Cannot merge section %0 of %1")
+DIAG(debug_icf_iterations, DiagnosticEngine::Debug, "ICF converged after `%0' iteration(s).", "ICF converged after `%0' iteration(s).")
+DIAG(debug_icf_folded_section, DiagnosticEngine::Debug, "ICF folding section `%0' of `%1' into `%2' of `%3'", "ICF folding section `%0' of `%1' into `%2' of `%3'")
diff --git a/include/mcld/LD/DynObjReader.h b/include/mcld/LD/DynObjReader.h
index 56cf5e9..1817c4a 100644
--- a/include/mcld/LD/DynObjReader.h
+++ b/include/mcld/LD/DynObjReader.h
@@ -9,7 +9,6 @@
 #ifndef MCLD_LD_DYNOBJREADER_H
 #define MCLD_LD_DYNOBJREADER_H
 #include "mcld/LD/LDReader.h"
-#include <llvm/Support/system_error.h>
 
 namespace mcld {
 
diff --git a/include/mcld/LD/ELFDynObjReader.h b/include/mcld/LD/ELFDynObjReader.h
index b534fc1..0beeecd 100644
--- a/include/mcld/LD/ELFDynObjReader.h
+++ b/include/mcld/LD/ELFDynObjReader.h
@@ -9,7 +9,6 @@
 #ifndef MCLD_LD_ELFDYNOBJREADER_H
 #define MCLD_LD_ELFDYNOBJREADER_H
 #include <mcld/LD/DynObjReader.h>
-#include <llvm/Support/system_error.h>
 
 namespace mcld {
 
diff --git a/include/mcld/LD/ELFObjectWriter.h b/include/mcld/LD/ELFObjectWriter.h
index 7ab73fd..b83fb01 100644
--- a/include/mcld/LD/ELFObjectWriter.h
+++ b/include/mcld/LD/ELFObjectWriter.h
@@ -12,7 +12,6 @@
 #include <cassert>
 
 #include <mcld/Support/FileOutputBuffer.h>
-#include <llvm/Support/system_error.h>
 
 namespace mcld {
 
@@ -39,7 +38,7 @@
 
   ~ELFObjectWriter();
 
-  llvm::error_code writeObject(Module& pModule, FileOutputBuffer& pOutput);
+  std::error_code writeObject(Module& pModule, FileOutputBuffer& pOutput);
 
   size_t getOutputSize(const Module& pModule) const;
 
diff --git a/include/mcld/LD/IdenticalCodeFolding.h b/include/mcld/LD/IdenticalCodeFolding.h
new file mode 100644
index 0000000..e26315e
--- /dev/null
+++ b/include/mcld/LD/IdenticalCodeFolding.h
@@ -0,0 +1,79 @@
+//===- IdenticalCodeFolding.h ---------------------------------------------===//
+//
+//                     The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_LD_IDENTICALCODEFOLDING_H
+#define MCLD_LD_IDENTICALCODEFOLDING_H
+
+#include <llvm/ADT/MapVector.h>
+#include <string>
+#include <vector>
+
+namespace mcld {
+class Input;
+class LDSection;
+class LinkerConfig;
+class Module;
+class Relocation;
+class TargetLDBackend;
+
+/** \class IdenticalCodeFolding
+ *  \brief Implementation of identical code folding for --icf=[none|all|safe]
+ *  @ref Safe ICF: Pointer Safe and Unwinding Aware Identical Code Folding in
+ *       Gold, http://research.google.com/pubs/pub36912.html
+ */
+class IdenticalCodeFolding {
+public:
+  typedef std::pair<Input*, size_t> ObjectAndId;
+  typedef llvm::MapVector<LDSection*, ObjectAndId> KeptSections;
+
+private:
+  class FoldingCandidate {
+  public:
+    FoldingCandidate()
+        : sect(NULL), reloc_sect(NULL), obj(NULL)
+    { }
+    FoldingCandidate(LDSection* pCode, LDSection* pReloc, Input* pInput)
+        : sect(pCode), reloc_sect(pReloc), obj(pInput)
+    { }
+
+    void initConstantContent(const TargetLDBackend& pBackend,
+        const IdenticalCodeFolding::KeptSections& pKeptSections);
+    std::string getContentWithVariables(const TargetLDBackend& pBackend,
+        const IdenticalCodeFolding::KeptSections& pKeptSections);
+
+    LDSection* sect;
+    LDSection* reloc_sect;
+    Input* obj;
+    std::string content;
+    std::vector<Relocation*> variable_relocs;
+  };
+
+  typedef std::vector<FoldingCandidate> FoldingCandidates;
+
+public:
+  IdenticalCodeFolding(const LinkerConfig& pConfig,
+                       const TargetLDBackend& pBackend,
+                       Module& pModule);
+
+  void foldIdenticalCode();
+
+private:
+  void findCandidates(FoldingCandidates& pCandidateList);
+
+  bool matchCandidates(FoldingCandidates& pCandidateList);
+
+private:
+  const LinkerConfig& m_Config;
+  const TargetLDBackend& m_Backend;
+  Module& m_Module;
+  KeptSections m_KeptSections;
+};
+
+} // namespace of mcld
+
+#endif
diff --git a/include/mcld/LD/LDFileFormat.h b/include/mcld/LD/LDFileFormat.h
index 41ee0d8..44d3bfc 100644
--- a/include/mcld/LD/LDFileFormat.h
+++ b/include/mcld/LD/LDFileFormat.h
@@ -25,7 +25,8 @@
 public:
   enum Kind {
     Null,
-    Regular,
+    TEXT, // Executable regular sections
+    DATA, // Non-executable regular sections
     BSS,
     NamePool,
     Relocation,
@@ -41,7 +42,8 @@
     LinkOnce,
     StackNote,
     Ignore,
-    Exclude
+    Exclude,
+    Folded
   };
 
 protected:
diff --git a/include/mcld/LD/LDSymbol.h b/include/mcld/LD/LDSymbol.h
index 5cfb2ef..45c10a8 100644
--- a/include/mcld/LD/LDSymbol.h
+++ b/include/mcld/LD/LDSymbol.h
@@ -105,6 +105,9 @@
   const FragmentRef* fragRef() const
   { return m_pFragRef; }
 
+  FragmentRef* fragRef()
+  { return m_pFragRef; }
+
   SizeType size() const
   { return m_pResolveInfo->size(); }
 
diff --git a/include/mcld/LD/ObjectReader.h b/include/mcld/LD/ObjectReader.h
index 7ecbd9d..32a8c0a 100644
--- a/include/mcld/LD/ObjectReader.h
+++ b/include/mcld/LD/ObjectReader.h
@@ -9,7 +9,6 @@
 #ifndef MCLD_LD_OBJECTREADER_H
 #define MCLD_LD_OBJECTREADER_H
 #include "mcld/LD/LDReader.h"
-#include <llvm/Support/system_error.h>
 #include <mcld/ADT/HashTable.h>
 #include <mcld/ADT/StringHash.h>
 #include <mcld/LD/ResolveInfo.h>
diff --git a/include/mcld/LD/ObjectWriter.h b/include/mcld/LD/ObjectWriter.h
index d5d124b..b58661a 100644
--- a/include/mcld/LD/ObjectWriter.h
+++ b/include/mcld/LD/ObjectWriter.h
@@ -8,7 +8,7 @@
 //===----------------------------------------------------------------------===//
 #ifndef MCLD_LD_OBJECTWRITER_H
 #define MCLD_LD_OBJECTWRITER_H
-#include <llvm/Support/system_error.h>
+#include <system_error>
 
 namespace mcld {
 
@@ -26,8 +26,8 @@
 public:
   virtual ~ObjectWriter();
 
-  virtual llvm::error_code writeObject(Module& pModule,
-                                       FileOutputBuffer& pOutput) = 0;
+  virtual std::error_code writeObject(Module& pModule,
+                                      FileOutputBuffer& pOutput) = 0;
 
   virtual size_t getOutputSize(const Module& pModule) const = 0;
 };
diff --git a/include/mcld/LD/Relocator.h b/include/mcld/LD/Relocator.h
index 8c9dfb6..82bdf8a 100644
--- a/include/mcld/LD/Relocator.h
+++ b/include/mcld/LD/Relocator.h
@@ -115,6 +115,13 @@
   /// getSize - get the size of a relocation in bit
   virtual Size getSize(Type pType) const = 0;
 
+  /// mayHaveFunctionPointerAccess - check if the given reloc would possibly
+  /// access a function pointer.
+  /// Note: Each target relocator should override this function, or be
+  /// conservative and return true to avoid getting folded.
+  virtual bool mayHaveFunctionPointerAccess(const Relocation& pReloc) const
+  { return true; }
+
 protected:
   const LinkerConfig& config() const { return m_Config; }
 
diff --git a/include/mcld/MC/Input.h b/include/mcld/MC/Input.h
index 1c8ccba..da3a647 100644
--- a/include/mcld/MC/Input.h
+++ b/include/mcld/MC/Input.h
@@ -94,6 +94,12 @@
   void setNeeded()
   { m_bNeeded = true; }
 
+  bool noExport() const
+  { return m_bNoExport; }
+
+  void setNoExport()
+  { m_bNoExport = true; }
+
   off_t fileOffset() const
   { return m_fileOffset; }
 
@@ -126,6 +132,7 @@
   sys::fs::Path m_Path;
   Attribute *m_pAttr;
   bool m_bNeeded;
+  bool m_bNoExport;
   off_t m_fileOffset;
   MemoryArea* m_pMemArea;
   LDContext* m_pContext;
diff --git a/include/mcld/Object/ObjectLinker.h b/include/mcld/Object/ObjectLinker.h
index 0462414..9d54d2e 100644
--- a/include/mcld/Object/ObjectLinker.h
+++ b/include/mcld/Object/ObjectLinker.h
@@ -45,6 +45,9 @@
   /// initStdSections - initialize standard sections of the output file.
   bool initStdSections();
 
+  /// addUndefinedSymbols - add symbols set by -u
+  void addUndefinedSymbols();
+
   /// normalize - normalize the input files
   void normalize();
 
diff --git a/include/mcld/Script/FlexLexer.h b/include/mcld/Script/FlexLexer.h
index 1e49b83..f09ab20 100644
--- a/include/mcld/Script/FlexLexer.h
+++ b/include/mcld/Script/FlexLexer.h
@@ -141,10 +141,6 @@
 protected:
 	virtual int LexerInput( char* buf, int max_size );
 	virtual void LexerOutput( const char* buf, int size );
-	/* BEGIN ANDROID WAR - Mac builds use size_t until we switch to prebuilts */
-	virtual size_t LexerInput( char* buf, size_t max_size );
-	virtual void LexerOutput( const char* buf, size_t size );
-	/* END ANDROID WAR */
 	virtual void LexerError( const char* msg );
 
 	void yyunput( int c, char* buf_ptr );
diff --git a/include/mcld/Support/CXADemangle.tcc b/include/mcld/Support/CXADemangle.tcc
new file mode 100644
index 0000000..4e66f84
--- /dev/null
+++ b/include/mcld/Support/CXADemangle.tcc
@@ -0,0 +1,4976 @@
+//===- CXADemangle.tcc ----------------------------------------------------===//
+//
+//                     The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/*
+ * Note: This file is imported from cxa_demangle.cpp in llvm libcxxabi.
+ */
+#include <vector>
+#include <algorithm>
+#include <string>
+#include <numeric>
+#include <cstdlib>
+#include <cstring>
+#include <cctype>
+
+namespace mcld
+{
+
+enum
+{
+    unknown_error = -4,
+    invalid_args = -3,
+    invalid_mangled_name,
+    memory_alloc_failure,
+    success
+};
+
+template <class C>
+    const char* parse_type(const char* first, const char* last, C& db);
+template <class C>
+    const char* parse_encoding(const char* first, const char* last, C& db);
+template <class C>
+    const char* parse_name(const char* first, const char* last, C& db,
+                           bool* ends_with_template_args = 0);
+template <class C>
+    const char* parse_expression(const char* first, const char* last, C& db);
+template <class C>
+    const char* parse_template_args(const char* first, const char* last, C& db);
+template <class C>
+    const char* parse_operator_name(const char* first, const char* last, C& db);
+template <class C>
+    const char* parse_unqualified_name(const char* first, const char* last, C& db);
+template <class C>
+    const char* parse_decltype(const char* first, const char* last, C& db);
+
+template <class C>
+void
+print_stack(const C& db)
+{
+    printf("---------\n");
+    printf("names:\n");
+    for (auto& s : db.names)
+        printf("{%s#%s}\n", s.first.c_str(), s.second.c_str());
+    int i = -1;
+    printf("subs:\n");
+    for (auto& v : db.subs)
+    {
+        if (i >= 0)
+            printf("S%i_ = {", i);
+        else
+            printf("S_  = {");
+        for (auto& s : v)
+            printf("{%s#%s}", s.first.c_str(), s.second.c_str());
+        printf("}\n");
+        ++i;
+    }
+    printf("template_param:\n");
+    for (auto& t : db.template_param)
+    {
+        printf("--\n");
+        i = -1;
+        for (auto& v : t)
+        {
+            if (i >= 0)
+                printf("T%i_ = {", i);
+            else
+                printf("T_  = {");
+            for (auto& s : v)
+                printf("{%s#%s}", s.first.c_str(), s.second.c_str());
+            printf("}\n");
+            ++i;
+        }
+    }
+    printf("---------\n\n");
+}
+
+template <class C>
+void
+print_state(const char* msg, const char* first, const char* last, const C& db)
+{
+    printf("%s: ", msg);
+    for (; first != last; ++first)
+        printf("%c", *first);
+    printf("\n");
+    print_stack(db);
+}
+
+// <number> ::= [n] <non-negative decimal integer>
+
+const char*
+parse_number(const char* first, const char* last)
+{
+    if (first != last)
+    {
+        const char* t = first;
+        if (*t == 'n')
+            ++t;
+        if (t != last)
+        {
+            if (*t == '0')
+            {
+                first = t+1;
+            }
+            else if ('1' <= *t && *t <= '9')
+            {
+                first = t+1;
+                while (first != last && std::isdigit(*first))
+                    ++first;
+            }
+        }
+    }
+    return first;
+}
+
+template <class Float>
+struct float_data;
+
+template <>
+struct float_data<float>
+{
+    static const size_t mangled_size = 8;
+    static const size_t max_demangled_size = 24;
+    static constexpr const char* spec = "%af";
+};
+
+constexpr const char* float_data<float>::spec;
+
+template <>
+struct float_data<double>
+{
+    static const size_t mangled_size = 16;
+    static const size_t max_demangled_size = 32;
+    static constexpr const char* spec = "%a";
+};
+
+constexpr const char* float_data<double>::spec;
+
+template <>
+struct float_data<long double>
+{
+#if defined(__arm__)
+    static const size_t mangled_size = 16;
+#else
+    static const size_t mangled_size = 20;  // May need to be adjusted to 16 or 24 on other platforms
+#endif
+    static const size_t max_demangled_size = 40;
+    static constexpr const char* spec = "%LaL";
+};
+
+constexpr const char* float_data<long double>::spec;
+
+template <class Float, class C>
+const char*
+parse_floating_number(const char* first, const char* last, C& db)
+{
+    const size_t N = float_data<Float>::mangled_size;
+    if (static_cast<std::size_t>(last - first) > N)
+    {
+        last = first + N;
+        union
+        {
+            Float value;
+            char buf[sizeof(Float)];
+        };
+        const char* t = first;
+        char* e = buf;
+        for (; t != last; ++t, ++e)
+        {
+            if (!isxdigit(*t))
+                return first;
+            unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
+                                        static_cast<unsigned>(*t - 'a' + 10);
+            ++t;
+            unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
+                                        static_cast<unsigned>(*t - 'a' + 10);
+            *e = static_cast<char>((d1 << 4) + d0);
+        }
+        if (*t == 'E')
+        {
+#if __LITTLE_ENDIAN__
+            std::reverse(buf, e);
+#endif
+            char num[float_data<Float>::max_demangled_size] = {0};
+            int n = snprintf(num, sizeof(num), float_data<Float>::spec, value);
+            if (static_cast<std::size_t>(n) >= sizeof(num))
+                return first;
+            db.names.push_back(typename C::String(num, static_cast<std::size_t>(n)));
+            first = t+1;
+        }
+    }
+    return first;
+}
+
+// <source-name> ::= <positive length number> <identifier>
+
+template <class C>
+const char*
+parse_source_name(const char* first, const char* last, C& db)
+{
+    if (first != last)
+    {
+        char c = *first;
+        if (isdigit(c) && first+1 != last)
+        {
+            const char* t = first+1;
+            size_t n = static_cast<size_t>(c - '0');
+            for (c = *t; isdigit(c); c = *t)
+            {
+                n = n * 10 + static_cast<size_t>(c - '0');
+                if (++t == last)
+                    return first;
+            }
+            if (static_cast<size_t>(last - t) >= n)
+            {
+                typename C::String r(t, n);
+                if (r.substr(0, 10) == "_GLOBAL__N")
+                    db.names.push_back("(anonymous namespace)");
+                else
+                    db.names.push_back(std::move(r));
+                first = t + n;
+            }
+        }
+    }
+    return first;
+}
+
+// <substitution> ::= S <seq-id> _
+//                ::= S_
+// <substitution> ::= Sa # ::std::allocator
+// <substitution> ::= Sb # ::std::basic_string
+// <substitution> ::= Ss # ::std::basic_string < char,
+//                                               ::std::char_traits<char>,
+//                                               ::std::allocator<char> >
+// <substitution> ::= Si # ::std::basic_istream<char,  std::char_traits<char> >
+// <substitution> ::= So # ::std::basic_ostream<char,  std::char_traits<char> >
+// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
+
+template <class C>
+const char*
+parse_substitution(const char* first, const char* last, C& db)
+{
+    if (last - first >= 2)
+    {
+        if (*first == 'S')
+        {
+            switch (first[1])
+            {
+            case 'a':
+                db.names.push_back("std::allocator");
+                first += 2;
+                break;
+            case 'b':
+                db.names.push_back("std::basic_string");
+                first += 2;
+                break;
+            case 's':
+                db.names.push_back("std::string");
+                first += 2;
+                break;
+            case 'i':
+                db.names.push_back("std::istream");
+                first += 2;
+                break;
+            case 'o':
+                db.names.push_back("std::ostream");
+                first += 2;
+                break;
+            case 'd':
+                db.names.push_back("std::iostream");
+                first += 2;
+                break;
+            case '_':
+                if (!db.subs.empty())
+                {
+                    for (const auto& n : db.subs.front())
+                        db.names.push_back(n);
+                    first += 2;
+                }
+                break;
+            default:
+                if (std::isdigit(first[1]) || std::isupper(first[1]))
+                {
+                    size_t sub = 0;
+                    const char* t = first+1;
+                    if (std::isdigit(*t))
+                        sub = static_cast<size_t>(*t - '0');
+                    else
+                        sub = static_cast<size_t>(*t - 'A') + 10;
+                    for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t)
+                    {
+                        sub *= 36;
+                        if (std::isdigit(*t))
+                            sub += static_cast<size_t>(*t - '0');
+                        else
+                            sub += static_cast<size_t>(*t - 'A') + 10;
+                    }
+                    if (t == last || *t != '_')
+                        return first;
+                    ++sub;
+                    if (sub < db.subs.size())
+                    {
+                        for (const auto& n : db.subs[sub])
+                            db.names.push_back(n);
+                        first = t+1;
+                    }
+                }
+                break;
+            }
+        }
+    }
+    return first;
+}
+
+// <builtin-type> ::= v    # void
+//                ::= w    # wchar_t
+//                ::= b    # bool
+//                ::= c    # char
+//                ::= a    # signed char
+//                ::= h    # unsigned char
+//                ::= s    # short
+//                ::= t    # unsigned short
+//                ::= i    # int
+//                ::= j    # unsigned int
+//                ::= l    # long
+//                ::= m    # unsigned long
+//                ::= x    # long long, __int64
+//                ::= y    # unsigned long long, __int64
+//                ::= n    # __int128
+//                ::= o    # unsigned __int128
+//                ::= f    # float
+//                ::= d    # double
+//                ::= e    # long double, __float80
+//                ::= g    # __float128
+//                ::= z    # ellipsis
+//                ::= Dd   # IEEE 754r decimal floating point (64 bits)
+//                ::= De   # IEEE 754r decimal floating point (128 bits)
+//                ::= Df   # IEEE 754r decimal floating point (32 bits)
+//                ::= Dh   # IEEE 754r half-precision floating point (16 bits)
+//                ::= Di   # char32_t
+//                ::= Ds   # char16_t
+//                ::= Da   # auto (in dependent new-expressions)
+//                ::= Dc   # decltype(auto)
+//                ::= Dn   # std::nullptr_t (i.e., decltype(nullptr))
+//                ::= u <source-name>    # vendor extended type
+
+template <class C>
+const char*
+parse_builtin_type(const char* first, const char* last, C& db)
+{
+    if (first != last)
+    {
+        switch (*first)
+        {
+        case 'v':
+            db.names.push_back("void");
+            ++first;
+            break;
+        case 'w':
+            db.names.push_back("wchar_t");
+            ++first;
+            break;
+        case 'b':
+            db.names.push_back("bool");
+            ++first;
+            break;
+        case 'c':
+            db.names.push_back("char");
+            ++first;
+            break;
+        case 'a':
+            db.names.push_back("signed char");
+            ++first;
+            break;
+        case 'h':
+            db.names.push_back("unsigned char");
+            ++first;
+            break;
+        case 's':
+            db.names.push_back("short");
+            ++first;
+            break;
+        case 't':
+            db.names.push_back("unsigned short");
+            ++first;
+            break;
+        case 'i':
+            db.names.push_back("int");
+            ++first;
+            break;
+        case 'j':
+            db.names.push_back("unsigned int");
+            ++first;
+            break;
+        case 'l':
+            db.names.push_back("long");
+            ++first;
+            break;
+        case 'm':
+            db.names.push_back("unsigned long");
+            ++first;
+            break;
+        case 'x':
+            db.names.push_back("long long");
+            ++first;
+            break;
+        case 'y':
+            db.names.push_back("unsigned long long");
+            ++first;
+            break;
+        case 'n':
+            db.names.push_back("__int128");
+            ++first;
+            break;
+        case 'o':
+            db.names.push_back("unsigned __int128");
+            ++first;
+            break;
+        case 'f':
+            db.names.push_back("float");
+            ++first;
+            break;
+        case 'd':
+            db.names.push_back("double");
+            ++first;
+            break;
+        case 'e':
+            db.names.push_back("long double");
+            ++first;
+            break;
+        case 'g':
+            db.names.push_back("__float128");
+            ++first;
+            break;
+        case 'z':
+            db.names.push_back("...");
+            ++first;
+            break;
+        case 'u':
+            {
+                const char*t = parse_source_name(first+1, last, db);
+                if (t != first+1)
+                    first = t;
+            }
+            break;
+        case 'D':
+            if (first+1 != last)
+            {
+                switch (first[1])
+                {
+                case 'd':
+                    db.names.push_back("decimal64");
+                    first += 2;
+                    break;
+                case 'e':
+                    db.names.push_back("decimal128");
+                    first += 2;
+                    break;
+                case 'f':
+                    db.names.push_back("decimal32");
+                    first += 2;
+                    break;
+                case 'h':
+                    db.names.push_back("decimal16");
+                    first += 2;
+                    break;
+                case 'i':
+                    db.names.push_back("char32_t");
+                    first += 2;
+                    break;
+                case 's':
+                    db.names.push_back("char16_t");
+                    first += 2;
+                    break;
+                case 'a':
+                    db.names.push_back("auto");
+                    first += 2;
+                    break;
+                case 'c':
+                    db.names.push_back("decltype(auto)");
+                    first += 2;
+                    break;
+                case 'n':
+                    db.names.push_back("std::nullptr_t");
+                    first += 2;
+                    break;
+                }
+            }
+            break;
+        }
+    }
+    return first;
+}
+
+// <CV-qualifiers> ::= [r] [V] [K]
+
+const char*
+parse_cv_qualifiers(const char* first, const char* last, unsigned& cv)
+{
+    cv = 0;
+    if (first != last)
+    {
+        if (*first == 'r')
+        {
+            cv |= 4;
+            ++first;
+        }
+        if (*first == 'V')
+        {
+            cv |= 2;
+            ++first;
+        }
+        if (*first == 'K')
+        {
+            cv |= 1;
+            ++first;
+        }
+    }
+    return first;
+}
+
+// <template-param> ::= T_    # first template parameter
+//                  ::= T <parameter-2 non-negative number> _
+
+template <class C>
+const char*
+parse_template_param(const char* first, const char* last, C& db)
+{
+    if (last - first >= 2)
+    {
+        if (*first == 'T')
+        {
+            if (first[1] == '_')
+            {
+                if (db.template_param.empty())
+                    return first;
+                if (!db.template_param.back().empty())
+                {
+                    for (auto& t : db.template_param.back().front())
+                        db.names.push_back(t);
+                    first += 2;
+                }
+                else
+                {
+                    db.names.push_back("T_");
+                    first += 2;
+                    db.fix_forward_references = true;
+                }
+            }
+            else if (isdigit(first[1]))
+            {
+                const char* t = first+1;
+                size_t sub = static_cast<size_t>(*t - '0');
+                for (++t; t != last && isdigit(*t); ++t)
+                {
+                    sub *= 10;
+                    sub += static_cast<size_t>(*t - '0');
+                }
+                if (t == last || *t != '_' || db.template_param.empty())
+                    return first;
+                ++sub;
+                if (sub < db.template_param.back().size())
+                {
+                    for (auto& temp : db.template_param.back()[sub])
+                        db.names.push_back(temp);
+                    first = t+1;
+                }
+                else
+                {
+                    db.names.push_back(typename C::String(first, t+1));
+                    first = t+1;
+                    db.fix_forward_references = true;
+                }
+            }
+        }
+    }
+    return first;
+}
+
+// cc <type> <expression>                               # const_cast<type> (expression)
+
+template <class C>
+const char*
+parse_const_cast_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 'c' && first[1] == 'c')
+    {
+        const char* t = parse_type(first+2, last, db);
+        if (t != first+2)
+        {
+            const char* t1 = parse_expression(t, last, db);
+            if (t1 != t)
+            {
+                if (db.names.size() < 2)
+                    return first;
+                auto expr = db.names.back().move_full();
+                db.names.pop_back();
+                db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+                first = t1;
+            }
+        }
+    }
+    return first;
+}
+
+// dc <type> <expression>                               # dynamic_cast<type> (expression)
+
+template <class C>
+const char*
+parse_dynamic_cast_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 'd' && first[1] == 'c')
+    {
+        const char* t = parse_type(first+2, last, db);
+        if (t != first+2)
+        {
+            const char* t1 = parse_expression(t, last, db);
+            if (t1 != t)
+            {
+                if (db.names.size() < 2)
+                    return first;
+                auto expr = db.names.back().move_full();
+                db.names.pop_back();
+                db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+                first = t1;
+            }
+        }
+    }
+    return first;
+}
+
+// rc <type> <expression>                               # reinterpret_cast<type> (expression)
+
+template <class C>
+const char*
+parse_reinterpret_cast_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 'r' && first[1] == 'c')
+    {
+        const char* t = parse_type(first+2, last, db);
+        if (t != first+2)
+        {
+            const char* t1 = parse_expression(t, last, db);
+            if (t1 != t)
+            {
+                if (db.names.size() < 2)
+                    return first;
+                auto expr = db.names.back().move_full();
+                db.names.pop_back();
+                db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+                first = t1;
+            }
+        }
+    }
+    return first;
+}
+
+// sc <type> <expression>                               # static_cast<type> (expression)
+
+template <class C>
+const char*
+parse_static_cast_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 's' && first[1] == 'c')
+    {
+        const char* t = parse_type(first+2, last, db);
+        if (t != first+2)
+        {
+            const char* t1 = parse_expression(t, last, db);
+            if (t1 != t)
+            {
+                if (db.names.size() < 2)
+                    return first;
+                auto expr = db.names.back().move_full();
+                db.names.pop_back();
+                db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+                first = t1;
+            }
+        }
+    }
+    return first;
+}
+
+// sp <expression>                                  # pack expansion
+
+template <class C>
+const char*
+parse_pack_expansion(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 's' && first[1] == 'p')
+    {
+        const char* t = parse_expression(first+2, last, db);
+        if (t != first+2)
+            first = t;
+    }
+    return first;
+}
+
+// st <type>                                            # sizeof (a type)
+
+template <class C>
+const char*
+parse_sizeof_type_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 's' && first[1] == 't')
+    {
+        const char* t = parse_type(first+2, last, db);
+        if (t != first+2)
+        {
+            if (db.names.empty())
+                return first;
+            db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
+            first = t;
+        }
+    }
+    return first;
+}
+
+// sz <expr>                                            # sizeof (a expression)
+
+template <class C>
+const char*
+parse_sizeof_expr_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 's' && first[1] == 'z')
+    {
+        const char* t = parse_expression(first+2, last, db);
+        if (t != first+2)
+        {
+            if (db.names.empty())
+                return first;
+            db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
+            first = t;
+        }
+    }
+    return first;
+}
+
+// sZ <template-param>                                  # size of a parameter pack
+
+template <class C>
+const char*
+parse_sizeof_param_pack_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T')
+    {
+        size_t k0 = db.names.size();
+        const char* t = parse_template_param(first+2, last, db);
+        size_t k1 = db.names.size();
+        if (t != first+2)
+        {
+            typename C::String tmp("sizeof...(");
+            size_t k = k0;
+            if (k != k1)
+            {
+                tmp += db.names[k].move_full();
+                for (++k; k != k1; ++k)
+                    tmp += ", " + db.names[k].move_full();
+            }
+            tmp += ")";
+            for (; k1 != k0; --k1)
+                db.names.pop_back();
+            db.names.push_back(std::move(tmp));
+            first = t;
+        }
+    }
+    return first;
+}
+
+// <function-param> ::= fp <top-level CV-qualifiers> _                                     # L == 0, first parameter
+//                  ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _   # L == 0, second and later parameters
+//                  ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _         # L > 0, first parameter
+//                  ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _   # L > 0, second and later parameters
+
+template <class C>
+const char*
+parse_function_param(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && *first == 'f')
+    {
+        if (first[1] == 'p')
+        {
+            unsigned cv;
+            const char* t = parse_cv_qualifiers(first+2, last, cv);
+            const char* t1 = parse_number(t, last);
+            if (t1 != last && *t1 == '_')
+            {
+                db.names.push_back("fp" + typename C::String(t, t1));
+                first = t1+1;
+            }
+        }
+        else if (first[1] == 'L')
+        {
+            unsigned cv;
+            const char* t0 = parse_number(first+2, last);
+            if (t0 != last && *t0 == 'p')
+            {
+                ++t0;
+                const char* t = parse_cv_qualifiers(t0, last, cv);
+                const char* t1 = parse_number(t, last);
+                if (t1 != last && *t1 == '_')
+                {
+                    db.names.push_back("fp" + typename C::String(t, t1));
+                    first = t1+1;
+                }
+            }
+        }
+    }
+    return first;
+}
+
+// sZ <function-param>                                  # size of a function parameter pack
+
+template <class C>
+const char*
+parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f')
+    {
+        const char* t = parse_function_param(first+2, last, db);
+        if (t != first+2)
+        {
+            if (db.names.empty())
+                return first;
+            db.names.back() = "sizeof...(" + db.names.back().move_full() + ")";
+            first = t;
+        }
+    }
+    return first;
+}
+
+// te <expression>                                      # typeid (expression)
+// ti <type>                                            # typeid (type)
+
+template <class C>
+const char*
+parse_typeid_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i'))
+    {
+        const char* t;
+        if (first[1] == 'e')
+            t = parse_expression(first+2, last, db);
+        else
+            t = parse_type(first+2, last, db);
+        if (t != first+2)
+        {
+            if (db.names.empty())
+                return first;
+            db.names.back() = "typeid(" + db.names.back().move_full() + ")";
+            first = t;
+        }
+    }
+    return first;
+}
+
+// tw <expression>                                      # throw expression
+
+template <class C>
+const char*
+parse_throw_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 't' && first[1] == 'w')
+    {
+        const char* t = parse_expression(first+2, last, db);
+        if (t != first+2)
+        {
+            if (db.names.empty())
+                return first;
+            db.names.back() = "throw " + db.names.back().move_full();
+            first = t;
+        }
+    }
+    return first;
+}
+
+// ds <expression> <expression>                         # expr.*expr
+
+template <class C>
+const char*
+parse_dot_star_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 'd' && first[1] == 's')
+    {
+        const char* t = parse_expression(first+2, last, db);
+        if (t != first+2)
+        {
+            const char* t1 = parse_expression(t, last, db);
+            if (t1 != t)
+            {
+                if (db.names.size() < 2)
+                    return first;
+                auto expr = db.names.back().move_full();
+                db.names.pop_back();
+                db.names.back().first += ".*" + expr;
+                first = t1;
+            }
+        }
+    }
+    return first;
+}
+
+// <simple-id> ::= <source-name> [ <template-args> ]
+
+template <class C>
+const char*
+parse_simple_id(const char* first, const char* last, C& db)
+{
+    if (first != last)
+    {
+        const char* t = parse_source_name(first, last, db);
+        if (t != first)
+        {
+            const char* t1 = parse_template_args(t, last, db);
+            if (t1 != t)
+            {
+                if (db.names.size() < 2)
+                    return first;
+                auto args = db.names.back().move_full();
+                db.names.pop_back();
+                db.names.back().first += std::move(args);
+            }
+            first = t1;
+        }
+        else
+            first = t;
+    }
+    return first;
+}
+
+// <unresolved-type> ::= <template-param>
+//                   ::= <decltype>
+//                   ::= <substitution>
+
+template <class C>
+const char*
+parse_unresolved_type(const char* first, const char* last, C& db)
+{
+    if (first != last)
+    {
+        const char* t = first;
+        switch (*first)
+        {
+        case 'T':
+          {
+            size_t k0 = db.names.size();
+            t = parse_template_param(first, last, db);
+            size_t k1 = db.names.size();
+            if (t != first && k1 == k0 + 1)
+            {
+                db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                first = t;
+            }
+            else
+            {
+                for (; k1 != k0; --k1)
+                    db.names.pop_back();
+            }
+            break;
+          }
+        case 'D':
+            t = parse_decltype(first, last, db);
+            if (t != first)
+            {
+                if (db.names.empty())
+                    return first;
+                db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                first = t;
+            }
+            break;
+        case 'S':
+            t = parse_substitution(first, last, db);
+            if (t != first)
+                first = t;
+            else
+            {
+                if (last - first > 2 && first[1] == 't')
+                {
+                    t = parse_unqualified_name(first+2, last, db);
+                    if (t != first+2)
+                    {
+                        if (db.names.empty())
+                            return first;
+                        db.names.back().first.insert(0, "std::");
+                        db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                        first = t;
+                    }
+                }
+            }
+            break;
+       }
+    }
+    return first;
+}
+
+// <destructor-name> ::= <unresolved-type>                               # e.g., ~T or ~decltype(f())
+//                   ::= <simple-id>                                     # e.g., ~A<2*N>
+
+template <class C>
+const char*
+parse_destructor_name(const char* first, const char* last, C& db)
+{
+    if (first != last)
+    {
+        const char* t = parse_unresolved_type(first, last, db);
+        if (t == first)
+            t = parse_simple_id(first, last, db);
+        if (t != first)
+        {
+            if (db.names.empty())
+                return first;
+            db.names.back().first.insert(0, "~");
+            first = t;
+        }
+    }
+    return first;
+}
+
+// <base-unresolved-name> ::= <simple-id>                                # unresolved name
+//          extension     ::= <operator-name>                            # unresolved operator-function-id
+//          extension     ::= <operator-name> <template-args>            # unresolved operator template-id
+//                        ::= on <operator-name>                         # unresolved operator-function-id
+//                        ::= on <operator-name> <template-args>         # unresolved operator template-id
+//                        ::= dn <destructor-name>                       # destructor or pseudo-destructor;
+//                                                                         # e.g. ~X or ~X<N-1>
+
+template <class C>
+const char*
+parse_base_unresolved_name(const char* first, const char* last, C& db)
+{
+    if (last - first >= 2)
+    {
+        if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
+        {
+            if (first[0] == 'o')
+            {
+                const char* t = parse_operator_name(first+2, last, db);
+                if (t != first+2)
+                {
+                    first = parse_template_args(t, last, db);
+                    if (first != t)
+                    {
+                        if (db.names.size() < 2)
+                            return first;
+                        auto args = db.names.back().move_full();
+                        db.names.pop_back();
+                        db.names.back().first += std::move(args);
+                    }
+                }
+            }
+            else
+            {
+                const char* t = parse_destructor_name(first+2, last, db);
+                if (t != first+2)
+                    first = t;
+            }
+        }
+        else
+        {
+            const char* t = parse_simple_id(first, last, db);
+            if (t == first)
+            {
+                t = parse_operator_name(first, last, db);
+                if (t != first)
+                {
+                    first = parse_template_args(t, last, db);
+                    if (first != t)
+                    {
+                        if (db.names.size() < 2)
+                            return first;
+                        auto args = db.names.back().move_full();
+                        db.names.pop_back();
+                        db.names.back().first += std::move(args);
+                    }
+                }
+            }
+            else
+                first = t;
+        }
+    }
+    return first;
+}
+
+// <unresolved-qualifier-level> ::= <simple-id>
+
+template <class C>
+const char*
+parse_unresolved_qualifier_level(const char* first, const char* last, C& db)
+{
+    return parse_simple_id(first, last, db);
+}
+
+// <unresolved-name>
+//  extension        ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
+//                   ::= [gs] <base-unresolved-name>                     # x or (with "gs") ::x
+//                   ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
+//                                                                       # A::x, N::y, A<T>::z; "gs" means leading "::"
+//                   ::= sr <unresolved-type> <base-unresolved-name>     # T::x / decltype(p)::x
+//  extension        ::= sr <unresolved-type> <template-args> <base-unresolved-name>
+//                                                                       # T::N::x /decltype(p)::N::x
+//  (ignored)        ::= srN <unresolved-type>  <unresolved-qualifier-level>+ E <base-unresolved-name>
+
+template <class C>
+const char*
+parse_unresolved_name(const char* first, const char* last, C& db)
+{
+    if (last - first > 2)
+    {
+        const char* t = first;
+        bool global = false;
+        if (t[0] == 'g' && t[1] == 's')
+        {
+            global = true;
+            t += 2;
+        }
+        const char* t2 = parse_base_unresolved_name(t, last, db);
+        if (t2 != t)
+        {
+            if (global)
+            {
+                if (db.names.empty())
+                    return first;
+                db.names.back().first.insert(0, "::");
+            }
+            first = t2;
+        }
+        else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
+        {
+            if (t[2] == 'N')
+            {
+                t += 3;
+                const char* t1 = parse_unresolved_type(t, last, db);
+                if (t1 == t || t1 == last)
+                    return first;
+                t = t1;
+                t1 = parse_template_args(t, last, db);
+                if (t1 != t)
+                {
+                    if (db.names.size() < 2)
+                        return first;
+                    auto args = db.names.back().move_full();
+                    db.names.pop_back();
+                    db.names.back().first += std::move(args);
+                    t = t1;
+                    if (t == last)
+                    {
+                        db.names.pop_back();
+                        return first;
+                    }
+                }
+                while (*t != 'E')
+                {
+                    t1 = parse_unresolved_qualifier_level(t, last, db);
+                    if (t1 == t || t1 == last || db.names.size() < 2)
+                        return first;
+                    auto s = db.names.back().move_full();
+                    db.names.pop_back();
+                    db.names.back().first += "::" + std::move(s);
+                    t = t1;
+                }
+                ++t;
+                t1 = parse_base_unresolved_name(t, last, db);
+                if (t1 == t)
+                {
+                    if (!db.names.empty())
+                        db.names.pop_back();
+                    return first;
+                }
+                if (db.names.size() < 2)
+                    return first;
+                auto s = db.names.back().move_full();
+                db.names.pop_back();
+                db.names.back().first += "::" + std::move(s);
+                first = t1;
+            }
+            else
+            {
+                t += 2;
+                const char* t1 = parse_unresolved_type(t, last, db);
+                if (t1 != t)
+                {
+                    t = t1;
+                    t1 = parse_template_args(t, last, db);
+                    if (t1 != t)
+                    {
+                        if (db.names.size() < 2)
+                            return first;
+                        auto args = db.names.back().move_full();
+                        db.names.pop_back();
+                        db.names.back().first += std::move(args);
+                        t = t1;
+                    }
+                    t1 = parse_base_unresolved_name(t, last, db);
+                    if (t1 == t)
+                    {
+                        if (!db.names.empty())
+                            db.names.pop_back();
+                        return first;
+                    }
+                    if (db.names.size() < 2)
+                        return first;
+                    auto s = db.names.back().move_full();
+                    db.names.pop_back();
+                    db.names.back().first += "::" + std::move(s);
+                    first = t1;
+                }
+                else
+                {
+                    t1 = parse_unresolved_qualifier_level(t, last, db);
+                    if (t1 == t || t1 == last)
+                        return first;
+                    t = t1;
+                    if (global)
+                    {
+                        if (db.names.empty())
+                            return first;
+                        db.names.back().first.insert(0, "::");
+                    }
+                    while (*t != 'E')
+                    {
+                        t1 = parse_unresolved_qualifier_level(t, last, db);
+                        if (t1 == t || t1 == last || db.names.size() < 2)
+                            return first;
+                        auto s = db.names.back().move_full();
+                        db.names.pop_back();
+                        db.names.back().first += "::" + std::move(s);
+                        t = t1;
+                    }
+                    ++t;
+                    t1 = parse_base_unresolved_name(t, last, db);
+                    if (t1 == t)
+                    {
+                        if (!db.names.empty())
+                            db.names.pop_back();
+                        return first;
+                    }
+                    if (db.names.size() < 2)
+                        return first;
+                    auto s = db.names.back().move_full();
+                    db.names.pop_back();
+                    db.names.back().first += "::" + std::move(s);
+                    first = t1;
+                }
+            }
+        }
+    }
+    return first;
+}
+
+// dt <expression> <unresolved-name>                    # expr.name
+
+template <class C>
+const char*
+parse_dot_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 'd' && first[1] == 't')
+    {
+        const char* t = parse_expression(first+2, last, db);
+        if (t != first+2)
+        {
+            const char* t1 = parse_unresolved_name(t, last, db);
+            if (t1 != t)
+            {
+                if (db.names.size() < 2)
+                    return first;
+                auto name = db.names.back().move_full();
+                db.names.pop_back();
+                db.names.back().first += "." + name;
+                first = t1;
+            }
+        }
+    }
+    return first;
+}
+
+// cl <expression>+ E                                   # call
+
+template <class C>
+const char*
+parse_call_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')
+    {
+        const char* t = parse_expression(first+2, last, db);
+        if (t != first+2)
+        {
+            if (t == last)
+                return first;
+            if (db.names.empty())
+                return first;
+            db.names.back().first += db.names.back().second;
+            db.names.back().second = typename C::String();
+            db.names.back().first.append("(");
+            bool first_expr = true;
+            while (*t != 'E')
+            {
+                const char* t1 = parse_expression(t, last, db);
+                if (t1 == t || t1 == last)
+                    return first;
+                if (db.names.empty())
+                    return first;
+                auto tmp = db.names.back().move_full();
+                db.names.pop_back();
+                if (!tmp.empty())
+                {
+                    if (db.names.empty())
+                        return first;
+                    if (!first_expr)
+                    {
+                        db.names.back().first.append(", ");
+                        first_expr = false;
+                    }
+                    db.names.back().first.append(tmp);
+                }
+                t = t1;
+            }
+            ++t;
+            if (db.names.empty())
+                return first;
+            db.names.back().first.append(")");
+            first = t;
+        }
+    }
+    return first;
+}
+
+// [gs] nw <expression>* _ <type> E                     # new (expr-list) type
+// [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init)
+// [gs] na <expression>* _ <type> E                     # new[] (expr-list) type
+// [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init)
+// <initializer> ::= pi <expression>* E                 # parenthesized initialization
+
+template <class C>
+const char*
+parse_new_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 4)
+    {
+        const char* t = first;
+        bool parsed_gs = false;
+        if (t[0] == 'g' && t[1] == 's')
+        {
+            t += 2;
+            parsed_gs = true;
+        }
+        if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a'))
+        {
+            bool is_array = t[1] == 'a';
+            t += 2;
+            if (t == last)
+                return first;
+            bool has_expr_list = false;
+            bool first_expr = true;
+            while (*t != '_')
+            {
+                const char* t1 = parse_expression(t, last, db);
+                if (t1 == t || t1 == last)
+                    return first;
+                has_expr_list = true;
+                if (!first_expr)
+                {
+                    if (db.names.empty())
+                        return first;
+                    auto tmp = db.names.back().move_full();
+                    db.names.pop_back();
+                    if (!tmp.empty())
+                    {
+                        if (db.names.empty())
+                            return first;
+                        db.names.back().first.append(", ");
+                        db.names.back().first.append(tmp);
+                        first_expr = false;
+                    }
+                }
+                t = t1;
+            }
+            ++t;
+            const char* t1 = parse_type(t, last, db);
+            if (t1 == t || t1 == last)
+                return first;
+            t = t1;
+            bool has_init = false;
+            if (last - t >= 3 && t[0] == 'p' && t[1] == 'i')
+            {
+                t += 2;
+                has_init = true;
+                first_expr = true;
+                while (*t != 'E')
+                {
+                    t1 = parse_expression(t, last, db);
+                    if (t1 == t || t1 == last)
+                        return first;
+                    if (!first_expr)
+                    {
+                        if (db.names.empty())
+                            return first;
+                        auto tmp = db.names.back().move_full();
+                        db.names.pop_back();
+                        if (!tmp.empty())
+                        {
+                            if (db.names.empty())
+                                return first;
+                            db.names.back().first.append(", ");
+                            db.names.back().first.append(tmp);
+                            first_expr = false;
+                        }
+                    }
+                    t = t1;
+                }
+            }
+            if (*t != 'E')
+                return first;
+            typename C::String init_list;
+            if (has_init)
+            {
+                if (db.names.empty())
+                    return first;
+                init_list = db.names.back().move_full();
+                db.names.pop_back();
+            }
+            if (db.names.empty())
+                return first;
+            auto type = db.names.back().move_full();
+            db.names.pop_back();
+            typename C::String expr_list;
+            if (has_expr_list)
+            {
+                if (db.names.empty())
+                    return first;
+                expr_list = db.names.back().move_full();
+                db.names.pop_back();
+            }
+            typename C::String r;
+            if (parsed_gs)
+                r = "::";
+            if (is_array)
+                r += "[] ";
+            else
+                r += " ";
+            if (has_expr_list)
+                r += "(" + expr_list + ") ";
+            r += type;
+            if (has_init)
+                r += " (" + init_list + ")";
+            db.names.push_back(std::move(r));
+            first = t+1;
+        }
+    }
+    return first;
+}
+
+// cv <type> <expression>                               # conversion with one argument
+// cv <type> _ <expression>* E                          # conversion with a different number of arguments
+
+template <class C>
+const char*
+parse_conversion_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 'c' && first[1] == 'v')
+    {
+        bool try_to_parse_template_args = db.try_to_parse_template_args;
+        db.try_to_parse_template_args = false;
+        const char* t = parse_type(first+2, last, db);
+        db.try_to_parse_template_args = try_to_parse_template_args;
+        if (t != first+2 && t != last)
+        {
+            if (*t != '_')
+            {
+                const char* t1 = parse_expression(t, last, db);
+                if (t1 == t)
+                    return first;
+                t = t1;
+            }
+            else
+            {
+                ++t;
+                if (t == last)
+                    return first;
+                if (*t == 'E')
+                    db.names.emplace_back();
+                else
+                {
+                    bool first_expr = true;
+                    while (*t != 'E')
+                    {
+                        const char* t1 = parse_expression(t, last, db);
+                        if (t1 == t || t1 == last)
+                            return first;
+                        if (!first_expr)
+                        {
+                            if (db.names.empty())
+                                return first;
+                            auto tmp = db.names.back().move_full();
+                            db.names.pop_back();
+                            if (!tmp.empty())
+                            {
+                                if (db.names.empty())
+                                    return first;
+                                db.names.back().first.append(", ");
+                                db.names.back().first.append(tmp);
+                                first_expr = false;
+                            }
+                        }
+                        t = t1;
+                    }
+                }
+                ++t;
+            }
+            if (db.names.size() < 2)
+                return first;
+            auto tmp = db.names.back().move_full();
+            db.names.pop_back();
+            db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")";
+            first = t;
+        }
+    }
+    return first;
+}
+
+// pt <expression> <expression>                    # expr->name
+
+template <class C>
+const char*
+parse_arrow_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 'p' && first[1] == 't')
+    {
+        const char* t = parse_expression(first+2, last, db);
+        if (t != first+2)
+        {
+            const char* t1 = parse_expression(t, last, db);
+            if (t1 != t)
+            {
+                if (db.names.size() < 2)
+                    return first;
+                auto tmp = db.names.back().move_full();
+                db.names.pop_back();
+                db.names.back().first += "->";
+                db.names.back().first += tmp;
+                first = t1;
+            }
+        }
+    }
+    return first;
+}
+
+//  <ref-qualifier> ::= R                   # & ref-qualifier
+//  <ref-qualifier> ::= O                   # && ref-qualifier
+
+// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
+
+template <class C>
+const char*
+parse_function_type(const char* first, const char* last, C& db)
+{
+    if (first != last && *first == 'F')
+    {
+        const char* t = first+1;
+        if (t != last)
+        {
+            bool externC = false;
+            if (*t == 'Y')
+            {
+                externC = true;
+                if (++t == last)
+                    return first;
+            }
+            const char* t1 = parse_type(t, last, db);
+            if (t1 != t)
+            {
+                t = t1;
+                typename C::String sig("(");
+                int ref_qual = 0;
+                while (true)
+                {
+                    if (t == last)
+                    {
+                        db.names.pop_back();
+                        return first;
+                    }
+                    if (*t == 'E')
+                    {
+                        ++t;
+                        break;
+                    }
+                    if (*t == 'v')
+                    {
+                        ++t;
+                        continue;
+                    }
+                    if (*t == 'R' && t+1 != last && t[1] == 'E')
+                    {
+                        ref_qual = 1;
+                        ++t;
+                        continue;
+                    }
+                    if (*t == 'O' && t+1 != last && t[1] == 'E')
+                    {
+                        ref_qual = 2;
+                        ++t;
+                        continue;
+                    }
+                    size_t k0 = db.names.size();
+                    t1 = parse_type(t, last, db);
+                    size_t k1 = db.names.size();
+                    if (t1 == t || t1 == last)
+                        return first;
+                    for (size_t k = k0; k < k1; ++k)
+                    {
+                        if (sig.size() > 1)
+                            sig += ", ";
+                        sig += db.names[k].move_full();
+                    }
+                    for (size_t k = k0; k < k1; ++k)
+                        db.names.pop_back();
+                    t = t1;
+                }
+                sig += ")";
+                switch (ref_qual)
+                {
+                case 1:
+                    sig += " &";
+                    break;
+                case 2:
+                    sig += " &&";
+                    break;
+                }
+                if (db.names.empty())
+                    return first;
+                db.names.back().first += " ";
+                db.names.back().second.insert(0, sig);
+                first = t;
+            }
+        }
+    }
+    return first;
+}
+
+// <pointer-to-member-type> ::= M <class type> <member type>
+
+template <class C>
+const char*
+parse_pointer_to_member_type(const char* first, const char* last, C& db)
+{
+    if (first != last && *first == 'M')
+    {
+        const char* t = parse_type(first+1, last, db);
+        if (t != first+1)
+        {
+            const char* t2 = parse_type(t, last, db);
+            if (t2 != t)
+            {
+                if (db.names.size() < 2)
+                    return first;
+                auto func = std::move(db.names.back());
+                db.names.pop_back();
+                auto class_type = std::move(db.names.back());
+                if (func.second.front() == '(')
+                {
+                    db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*";
+                    db.names.back().second = ")" + std::move(func.second);
+                }
+                else
+                {
+                    db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*";
+                    db.names.back().second = std::move(func.second);
+                }
+                first = t2;
+            }
+        }
+    }
+    return first;
+}
+
+// <array-type> ::= A <positive dimension number> _ <element type>
+//              ::= A [<dimension expression>] _ <element type>
+
+template <class C>
+const char*
+parse_array_type(const char* first, const char* last, C& db)
+{
+    if (first != last && *first == 'A' && first+1 != last)
+    {
+        if (first[1] == '_')
+        {
+            const char* t = parse_type(first+2, last, db);
+            if (t != first+2)
+            {
+                if (db.names.empty())
+                    return first;
+                if (db.names.back().second.substr(0, 2) == " [")
+                    db.names.back().second.erase(0, 1);
+                db.names.back().second.insert(0, " []");
+                first = t;
+            }
+        }
+        else if ('1' <= first[1] && first[1] <= '9')
+        {
+            const char* t = parse_number(first+1, last);
+            if (t != last && *t == '_')
+            {
+                const char* t2 = parse_type(t+1, last, db);
+                if (t2 != t+1)
+                {
+                    if (db.names.empty())
+                        return first;
+                    if (db.names.back().second.substr(0, 2) == " [")
+                        db.names.back().second.erase(0, 1);
+                    db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]");
+                    first = t2;
+                }
+            }
+        }
+        else
+        {
+            const char* t = parse_expression(first+1, last, db);
+            if (t != first+1 && t != last && *t == '_')
+            {
+                const char* t2 = parse_type(++t, last, db);
+                if (t2 != t)
+                {
+                    if (db.names.size() < 2)
+                        return first;
+                    auto type = std::move(db.names.back());
+                    db.names.pop_back();
+                    auto expr = std::move(db.names.back());
+                    db.names.back().first = std::move(type.first);
+                    if (type.second.substr(0, 2) == " [")
+                        type.second.erase(0, 1);
+                    db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second);
+                    first = t2;
+                }
+            }
+        }
+    }
+    return first;
+}
+
+// <decltype>  ::= Dt <expression> E  # decltype of an id-expression or class member access (C++0x)
+//             ::= DT <expression> E  # decltype of an expression (C++0x)
+
+template <class C>
+const char*
+parse_decltype(const char* first, const char* last, C& db)
+{
+    if (last - first >= 4 && first[0] == 'D')
+    {
+        switch (first[1])
+        {
+        case 't':
+        case 'T':
+            {
+                const char* t = parse_expression(first+2, last, db);
+                if (t != first+2 && t != last && *t == 'E')
+                {
+                    if (db.names.empty())
+                        return first;
+                    db.names.back() = "decltype(" + db.names.back().move_full() + ")";
+                    first = t+1;
+                }
+            }
+            break;
+        }
+    }
+    return first;
+}
+
+// extension:
+// <vector-type>           ::= Dv <positive dimension number> _
+//                                    <extended element type>
+//                         ::= Dv [<dimension expression>] _ <element type>
+// <extended element type> ::= <element type>
+//                         ::= p # AltiVec vector pixel
+
+template <class C>
+const char*
+parse_vector_type(const char* first, const char* last, C& db)
+{
+    if (last - first > 3 && first[0] == 'D' && first[1] == 'v')
+    {
+        if ('1' <= first[2] && first[2] <= '9')
+        {
+            const char* t = parse_number(first+2, last);
+            if (t == last || *t != '_')
+                return first;
+            const char* num = first + 2;
+            size_t sz = static_cast<size_t>(t - num);
+            if (++t != last)
+            {
+                if (*t != 'p')
+                {
+                    const char* t1 = parse_type(t, last, db);
+                    if (t1 != t)
+                    {
+                        if (db.names.empty())
+                            return first;
+                        db.names.back().first += " vector[" + typename C::String(num, sz) + "]";
+                        first = t1;
+                    }
+                }
+                else
+                {
+                    ++t;
+                    db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]");
+                    first = t;
+                }
+            }
+        }
+        else
+        {
+            typename C::String num;
+            const char* t1 = first+2;
+            if (*t1 != '_')
+            {
+                const char* t = parse_expression(t1, last, db);
+                if (t != t1)
+                {
+                    if (db.names.empty())
+                        return first;
+                    num = db.names.back().move_full();
+                    db.names.pop_back();
+                    t1 = t;
+                }
+            }
+            if (t1 != last && *t1 == '_' && ++t1 != last)
+            {
+                const char* t = parse_type(t1, last, db);
+                if (t != t1)
+                {
+                    if (db.names.empty())
+                        return first;
+                    db.names.back().first += " vector[" + num + "]";
+                    first = t;
+                }
+            }
+        }
+    }
+    return first;
+}
+
+// <type> ::= <builtin-type>
+//        ::= <function-type>
+//        ::= <class-enum-type>
+//        ::= <array-type>
+//        ::= <pointer-to-member-type>
+//        ::= <template-param>
+//        ::= <template-template-param> <template-args>
+//        ::= <decltype>
+//        ::= <substitution>
+//        ::= <CV-qualifiers> <type>
+//        ::= P <type>        # pointer-to
+//        ::= R <type>        # reference-to
+//        ::= O <type>        # rvalue reference-to (C++0x)
+//        ::= C <type>        # complex pair (C 2000)
+//        ::= G <type>        # imaginary (C 2000)
+//        ::= Dp <type>       # pack expansion (C++0x)
+//        ::= U <source-name> <type>  # vendor extended type qualifier
+// extension := U <objc-name> <objc-type>  # objc-type<identifier>
+// extension := <vector-type> # <vector-type> starts with Dv
+
+// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier>  # k0 = 9 + <number of digits in k1> + k1
+// <objc-type> := <source-name>  # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
+
+template <class C>
+const char*
+parse_type(const char* first, const char* last, C& db)
+{
+    if (first != last)
+    {
+        switch (*first)
+        {
+            case 'r':
+            case 'V':
+            case 'K':
+              {
+                unsigned cv = 0;
+                const char* t = parse_cv_qualifiers(first, last, cv);
+                if (t != first)
+                {
+                    bool is_function = *t == 'F';
+                    size_t k0 = db.names.size();
+                    const char* t1 = parse_type(t, last, db);
+                    size_t k1 = db.names.size();
+                    if (t1 != t)
+                    {
+                        if (is_function)
+                            db.subs.pop_back();
+                        db.subs.emplace_back(db.names.get_allocator());
+                        for (size_t k = k0; k < k1; ++k)
+                        {
+                            if (is_function)
+                            {
+                                size_t p = db.names[k].second.size();
+                                if (db.names[k].second[p-2] == '&')
+                                    p -= 3;
+                                else if (db.names[k].second.back() == '&')
+                                    p -= 2;
+                                if (cv & 1)
+                                {
+                                    db.names[k].second.insert(p, " const");
+                                    p += 6;
+                                }
+                                if (cv & 2)
+                                {
+                                    db.names[k].second.insert(p, " volatile");
+                                    p += 9;
+                                }
+                                if (cv & 4)
+                                    db.names[k].second.insert(p, " restrict");
+                            }
+                            else
+                            {
+                                if (cv & 1)
+                                    db.names[k].first.append(" const");
+                                if (cv & 2)
+                                    db.names[k].first.append(" volatile");
+                                if (cv & 4)
+                                    db.names[k].first.append(" restrict");
+                            }
+                            db.subs.back().push_back(db.names[k]);
+                        }
+                        first = t1;
+                    }
+                }
+              }
+                break;
+            default:
+              {
+                const char* t = parse_builtin_type(first, last, db);
+                if (t != first)
+                {
+                    first = t;
+                }
+                else
+                {
+                    switch (*first)
+                    {
+                    case 'A':
+                        t = parse_array_type(first, last, db);
+                        if (t != first)
+                        {
+                            if (db.names.empty())
+                                return first;
+                            first = t;
+                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                        }
+                        break;
+                    case 'C':
+                        t = parse_type(first+1, last, db);
+                        if (t != first+1)
+                        {
+                            if (db.names.empty())
+                                return first;
+                            db.names.back().first.append(" complex");
+                            first = t;
+                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                        }
+                        break;
+                    case 'F':
+                        t = parse_function_type(first, last, db);
+                        if (t != first)
+                        {
+                            if (db.names.empty())
+                                return first;
+                            first = t;
+                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                        }
+                        break;
+                    case 'G':
+                        t = parse_type(first+1, last, db);
+                        if (t != first+1)
+                        {
+                            if (db.names.empty())
+                                return first;
+                            db.names.back().first.append(" imaginary");
+                            first = t;
+                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                        }
+                        break;
+                    case 'M':
+                        t = parse_pointer_to_member_type(first, last, db);
+                        if (t != first)
+                        {
+                            if (db.names.empty())
+                                return first;
+                            first = t;
+                            db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                        }
+                        break;
+                    case 'O':
+                      {
+                        size_t k0 = db.names.size();
+                        t = parse_type(first+1, last, db);
+                        size_t k1 = db.names.size();
+                        if (t != first+1)
+                        {
+                            db.subs.emplace_back(db.names.get_allocator());
+                            for (size_t k = k0; k < k1; ++k)
+                            {
+                                if (db.names[k].second.substr(0, 2) == " [")
+                                {
+                                    db.names[k].first += " (";
+                                    db.names[k].second.insert(0, ")");
+                                }
+                                else if (db.names[k].second.front() == '(')
+                                {
+                                    db.names[k].first += "(";
+                                    db.names[k].second.insert(0, ")");
+                                }
+                                db.names[k].first.append("&&");
+                                db.subs.back().push_back(db.names[k]);
+                            }
+                            first = t;
+                        }
+                        break;
+                      }
+                    case 'P':
+                      {
+                        size_t k0 = db.names.size();
+                        t = parse_type(first+1, last, db);
+                        size_t k1 = db.names.size();
+                        if (t != first+1)
+                        {
+                            db.subs.emplace_back(db.names.get_allocator());
+                            for (size_t k = k0; k < k1; ++k)
+                            {
+                                if (db.names[k].second.substr(0, 2) == " [")
+                                {
+                                    db.names[k].first += " (";
+                                    db.names[k].second.insert(0, ")");
+                                }
+                                else if (db.names[k].second.front() == '(')
+                                {
+                                    db.names[k].first += "(";
+                                    db.names[k].second.insert(0, ")");
+                                }
+                                if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<")
+                                {
+                                    db.names[k].first.append("*");
+                                }
+                                else
+                                {
+                                    db.names[k].first.replace(0, 11, "id");
+                                }
+                                db.subs.back().push_back(db.names[k]);
+                            }
+                            first = t;
+                        }
+                        break;
+                      }
+                    case 'R':
+                      {
+                        size_t k0 = db.names.size();
+                        t = parse_type(first+1, last, db);
+                        size_t k1 = db.names.size();
+                        if (t != first+1)
+                        {
+                            db.subs.emplace_back(db.names.get_allocator());
+                            for (size_t k = k0; k < k1; ++k)
+                            {
+                                if (db.names[k].second.substr(0, 2) == " [")
+                                {
+                                    db.names[k].first += " (";
+                                    db.names[k].second.insert(0, ")");
+                                }
+                                else if (db.names[k].second.front() == '(')
+                                {
+                                    db.names[k].first += "(";
+                                    db.names[k].second.insert(0, ")");
+                                }
+                                db.names[k].first.append("&");
+                                db.subs.back().push_back(db.names[k]);
+                            }
+                            first = t;
+                        }
+                        break;
+                      }
+                    case 'T':
+                      {
+                        size_t k0 = db.names.size();
+                        t = parse_template_param(first, last, db);
+                        size_t k1 = db.names.size();
+                        if (t != first)
+                        {
+                            db.subs.emplace_back(db.names.get_allocator());
+                            for (size_t k = k0; k < k1; ++k)
+                                db.subs.back().push_back(db.names[k]);
+                            if (db.try_to_parse_template_args && k1 == k0+1)
+                            {
+                                const char* t1 = parse_template_args(t, last, db);
+                                if (t1 != t)
+                                {
+                                    auto args = db.names.back().move_full();
+                                    db.names.pop_back();
+                                    db.names.back().first += std::move(args);
+                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                                    t = t1;
+                                }
+                            }
+                            first = t;
+                        }
+                        break;
+                      }
+                    case 'U':
+                        if (first+1 != last)
+                        {
+                            t = parse_source_name(first+1, last, db);
+                            if (t != first+1)
+                            {
+                                const char* t2 = parse_type(t, last, db);
+                                if (t2 != t)
+                                {
+                                    if (db.names.size() < 2)
+                                        return first;
+                                    auto type = db.names.back().move_full();
+                                    db.names.pop_back();
+                                    if (db.names.back().first.substr(0, 9) != "objcproto")
+                                    {
+                                        db.names.back() = type + " " + db.names.back().move_full();
+                                    }
+                                    else
+                                    {
+                                        auto proto = db.names.back().move_full();
+                                        db.names.pop_back();
+                                        t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db);
+                                        if (t != proto.data() + 9)
+                                        {
+                                            db.names.back() = type + "<" + db.names.back().move_full() + ">";
+                                        }
+                                        else
+                                        {
+                                            db.names.push_back(type + " " + proto);
+                                        }
+                                    }
+                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                                    first = t2;
+                                }
+                            }
+                        }
+                        break;
+                    case 'S':
+                        if (first+1 != last && first[1] == 't')
+                        {
+                            t = parse_name(first, last, db);
+                            if (t != first)
+                            {
+                                if (db.names.empty())
+                                    return first;
+                                db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                                first = t;
+                            }
+                        }
+                        else
+                        {
+                            t = parse_substitution(first, last, db);
+                            if (t != first)
+                            {
+                                first = t;
+                                // Parsed a substitution.  If the substitution is a
+                                //  <template-param> it might be followed by <template-args>.
+                                t = parse_template_args(first, last, db);
+                                if (t != first)
+                                {
+                                    if (db.names.size() < 2)
+                                        return first;
+                                    auto template_args = db.names.back().move_full();
+                                    db.names.pop_back();
+                                    db.names.back().first += template_args;
+                                    // Need to create substitution for <template-template-param> <template-args>
+                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                                    first = t;
+                                }
+                            }
+                        }
+                        break;
+                    case 'D':
+                        if (first+1 != last)
+                        {
+                            switch (first[1])
+                            {
+                            case 'p':
+                              {
+                                size_t k0 = db.names.size();
+                                t = parse_type(first+2, last, db);
+                                size_t k1 = db.names.size();
+                                if (t != first+2)
+                                {
+                                    db.subs.emplace_back(db.names.get_allocator());
+                                    for (size_t k = k0; k < k1; ++k)
+                                        db.subs.back().push_back(db.names[k]);
+                                    first = t;
+                                    return first;
+                                }
+                                break;
+                              }
+                            case 't':
+                            case 'T':
+                                t = parse_decltype(first, last, db);
+                                if (t != first)
+                                {
+                                    if (db.names.empty())
+                                        return first;
+                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                                    first = t;
+                                    return first;
+                                }
+                                break;
+                            case 'v':
+                                t = parse_vector_type(first, last, db);
+                                if (t != first)
+                                {
+                                    if (db.names.empty())
+                                        return first;
+                                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                                    first = t;
+                                    return first;
+                                }
+                                break;
+                            }
+                        }
+                        // drop through
+                    default:
+                        // must check for builtin-types before class-enum-types to avoid
+                        // ambiguities with operator-names
+                        t = parse_builtin_type(first, last, db);
+                        if (t != first)
+                        {
+                            first = t;
+                        }
+                        else
+                        {
+                            t = parse_name(first, last, db);
+                            if (t != first)
+                            {
+                                if (db.names.empty())
+                                    return first;
+                                db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                                first = t;
+                            }
+                        }
+                        break;
+                    }
+              }
+                break;
+            }
+        }
+    }
+    return first;
+}
+
+//   <operator-name>
+//                   ::= aa    # &&
+//                   ::= ad    # & (unary)
+//                   ::= an    # &
+//                   ::= aN    # &=
+//                   ::= aS    # =
+//                   ::= cl    # ()
+//                   ::= cm    # ,
+//                   ::= co    # ~
+//                   ::= cv <type>    # (cast)
+//                   ::= da    # delete[]
+//                   ::= de    # * (unary)
+//                   ::= dl    # delete
+//                   ::= dv    # /
+//                   ::= dV    # /=
+//                   ::= eo    # ^
+//                   ::= eO    # ^=
+//                   ::= eq    # ==
+//                   ::= ge    # >=
+//                   ::= gt    # >
+//                   ::= ix    # []
+//                   ::= le    # <=
+//                   ::= li <source-name>  # operator ""
+//                   ::= ls    # <<
+//                   ::= lS    # <<=
+//                   ::= lt    # <
+//                   ::= mi    # -
+//                   ::= mI    # -=
+//                   ::= ml    # *
+//                   ::= mL    # *=
+//                   ::= mm    # -- (postfix in <expression> context)
+//                   ::= na    # new[]
+//                   ::= ne    # !=
+//                   ::= ng    # - (unary)
+//                   ::= nt    # !
+//                   ::= nw    # new
+//                   ::= oo    # ||
+//                   ::= or    # |
+//                   ::= oR    # |=
+//                   ::= pm    # ->*
+//                   ::= pl    # +
+//                   ::= pL    # +=
+//                   ::= pp    # ++ (postfix in <expression> context)
+//                   ::= ps    # + (unary)
+//                   ::= pt    # ->
+//                   ::= qu    # ?
+//                   ::= rm    # %
+//                   ::= rM    # %=
+//                   ::= rs    # >>
+//                   ::= rS    # >>=
+//                   ::= v <digit> <source-name>        # vendor extended operator
+
+template <class C>
+const char*
+parse_operator_name(const char* first, const char* last, C& db)
+{
+    if (last - first >= 2)
+    {
+        switch (first[0])
+        {
+        case 'a':
+            switch (first[1])
+            {
+            case 'a':
+                db.names.push_back("operator&&");
+                first += 2;
+                break;
+            case 'd':
+            case 'n':
+                db.names.push_back("operator&");
+                first += 2;
+                break;
+            case 'N':
+                db.names.push_back("operator&=");
+                first += 2;
+                break;
+            case 'S':
+                db.names.push_back("operator=");
+                first += 2;
+                break;
+            }
+            break;
+        case 'c':
+            switch (first[1])
+            {
+            case 'l':
+                db.names.push_back("operator()");
+                first += 2;
+                break;
+            case 'm':
+                db.names.push_back("operator,");
+                first += 2;
+                break;
+            case 'o':
+                db.names.push_back("operator~");
+                first += 2;
+                break;
+            case 'v':
+                {
+                    bool try_to_parse_template_args = db.try_to_parse_template_args;
+                    db.try_to_parse_template_args = false;
+                    const char* t = parse_type(first+2, last, db);
+                    db.try_to_parse_template_args = try_to_parse_template_args;
+                    if (t != first+2)
+                    {
+                        if (db.names.empty())
+                            return first;
+                        db.names.back().first.insert(0, "operator ");
+#if UPSTREAM_CODE
+                        db.parsed_ctor_dtor_cv = true;
+#else
+                        db.parsed_ctor_dtor_cv = false;
+#endif
+                        first = t;
+                    }
+                }
+                break;
+            }
+            break;
+        case 'd':
+            switch (first[1])
+            {
+            case 'a':
+                db.names.push_back("operator delete[]");
+                first += 2;
+                break;
+            case 'e':
+                db.names.push_back("operator*");
+                first += 2;
+                break;
+            case 'l':
+                db.names.push_back("operator delete");
+                first += 2;
+                break;
+            case 'v':
+                db.names.push_back("operator/");
+                first += 2;
+                break;
+            case 'V':
+                db.names.push_back("operator/=");
+                first += 2;
+                break;
+            }
+            break;
+        case 'e':
+            switch (first[1])
+            {
+            case 'o':
+                db.names.push_back("operator^");
+                first += 2;
+                break;
+            case 'O':
+                db.names.push_back("operator^=");
+                first += 2;
+                break;
+            case 'q':
+                db.names.push_back("operator==");
+                first += 2;
+                break;
+            }
+            break;
+        case 'g':
+            switch (first[1])
+            {
+            case 'e':
+                db.names.push_back("operator>=");
+                first += 2;
+                break;
+            case 't':
+                db.names.push_back("operator>");
+                first += 2;
+                break;
+            }
+            break;
+        case 'i':
+            if (first[1] == 'x')
+            {
+                db.names.push_back("operator[]");
+                first += 2;
+            }
+            break;
+        case 'l':
+            switch (first[1])
+            {
+            case 'e':
+                db.names.push_back("operator<=");
+                first += 2;
+                break;
+            case 'i':
+                {
+                    const char* t = parse_source_name(first+2, last, db);
+                    if (t != first+2)
+                    {
+                        if (db.names.empty())
+                            return first;
+                        db.names.back().first.insert(0, "operator\"\" ");
+                        first = t;
+                    }
+                }
+                break;
+            case 's':
+                db.names.push_back("operator<<");
+                first += 2;
+                break;
+            case 'S':
+                db.names.push_back("operator<<=");
+                first += 2;
+                break;
+            case 't':
+                db.names.push_back("operator<");
+                first += 2;
+                break;
+            }
+            break;
+        case 'm':
+            switch (first[1])
+            {
+            case 'i':
+                db.names.push_back("operator-");
+                first += 2;
+                break;
+            case 'I':
+                db.names.push_back("operator-=");
+                first += 2;
+                break;
+            case 'l':
+                db.names.push_back("operator*");
+                first += 2;
+                break;
+            case 'L':
+                db.names.push_back("operator*=");
+                first += 2;
+                break;
+            case 'm':
+                db.names.push_back("operator--");
+                first += 2;
+                break;
+            }
+            break;
+        case 'n':
+            switch (first[1])
+            {
+            case 'a':
+                db.names.push_back("operator new[]");
+                first += 2;
+                break;
+            case 'e':
+                db.names.push_back("operator!=");
+                first += 2;
+                break;
+            case 'g':
+                db.names.push_back("operator-");
+                first += 2;
+                break;
+            case 't':
+                db.names.push_back("operator!");
+                first += 2;
+                break;
+            case 'w':
+                db.names.push_back("operator new");
+                first += 2;
+                break;
+            }
+            break;
+        case 'o':
+            switch (first[1])
+            {
+            case 'o':
+                db.names.push_back("operator||");
+                first += 2;
+                break;
+            case 'r':
+                db.names.push_back("operator|");
+                first += 2;
+                break;
+            case 'R':
+                db.names.push_back("operator|=");
+                first += 2;
+                break;
+            }
+            break;
+        case 'p':
+            switch (first[1])
+            {
+            case 'm':
+                db.names.push_back("operator->*");
+                first += 2;
+                break;
+            case 'l':
+                db.names.push_back("operator+");
+                first += 2;
+                break;
+            case 'L':
+                db.names.push_back("operator+=");
+                first += 2;
+                break;
+            case 'p':
+                db.names.push_back("operator++");
+                first += 2;
+                break;
+            case 's':
+                db.names.push_back("operator+");
+                first += 2;
+                break;
+            case 't':
+                db.names.push_back("operator->");
+                first += 2;
+                break;
+            }
+            break;
+        case 'q':
+            if (first[1] == 'u')
+            {
+                db.names.push_back("operator?");
+                first += 2;
+            }
+            break;
+        case 'r':
+            switch (first[1])
+            {
+            case 'm':
+                db.names.push_back("operator%");
+                first += 2;
+                break;
+            case 'M':
+                db.names.push_back("operator%=");
+                first += 2;
+                break;
+            case 's':
+                db.names.push_back("operator>>");
+                first += 2;
+                break;
+            case 'S':
+                db.names.push_back("operator>>=");
+                first += 2;
+                break;
+            }
+            break;
+        case 'v':
+            if (std::isdigit(first[1]))
+            {
+                const char* t = parse_source_name(first+2, last, db);
+                if (t != first+2)
+                {
+                    if (db.names.empty())
+                        return first;
+                    db.names.back().first.insert(0, "operator ");
+                    first = t;
+                }
+            }
+            break;
+        }
+    }
+    return first;
+}
+
+template <class C>
+const char*
+parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db)
+{
+    const char* t = parse_number(first, last);
+    if (t != first && t != last && *t == 'E')
+    {
+        if (lit.size() > 3)
+            db.names.push_back("(" + lit + ")");
+        else
+            db.names.emplace_back();
+        if (*first == 'n')
+        {
+            db.names.back().first += '-';
+            ++first;
+        }
+        db.names.back().first.append(first, t);
+        if (lit.size() <= 3)
+            db.names.back().first += lit;
+        first = t+1;
+    }
+    return first;
+}
+
+// <expr-primary> ::= L <type> <value number> E                          # integer literal
+//                ::= L <type> <value float> E                           # floating literal
+//                ::= L <string type> E                                  # string literal
+//                ::= L <nullptr type> E                                 # nullptr literal (i.e., "LDnE")
+//                ::= L <type> <real-part float> _ <imag-part float> E   # complex floating point literal (C 2000)
+//                ::= L <mangled-name> E                                 # external name
+
+template <class C>
+const char*
+parse_expr_primary(const char* first, const char* last, C& db)
+{
+    if (last - first >= 4 && *first == 'L')
+    {
+        switch (first[1])
+        {
+        case 'w':
+            {
+            const char* t = parse_integer_literal(first+2, last, "wchar_t", db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 'b':
+            if (first[3] == 'E')
+            {
+                switch (first[2])
+                {
+                case '0':
+                    db.names.push_back("false");
+                    first += 4;
+                    break;
+                case '1':
+                    db.names.push_back("true");
+                    first += 4;
+                    break;
+                }
+            }
+            break;
+        case 'c':
+            {
+            const char* t = parse_integer_literal(first+2, last, "char", db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 'a':
+            {
+            const char* t = parse_integer_literal(first+2, last, "signed char", db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 'h':
+            {
+            const char* t = parse_integer_literal(first+2, last, "unsigned char", db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 's':
+            {
+            const char* t = parse_integer_literal(first+2, last, "short", db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 't':
+            {
+            const char* t = parse_integer_literal(first+2, last, "unsigned short", db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 'i':
+            {
+            const char* t = parse_integer_literal(first+2, last, "", db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 'j':
+            {
+            const char* t = parse_integer_literal(first+2, last, "u", db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 'l':
+            {
+            const char* t = parse_integer_literal(first+2, last, "l", db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 'm':
+            {
+            const char* t = parse_integer_literal(first+2, last, "ul", db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 'x':
+            {
+            const char* t = parse_integer_literal(first+2, last, "ll", db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 'y':
+            {
+            const char* t = parse_integer_literal(first+2, last, "ull", db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 'n':
+            {
+            const char* t = parse_integer_literal(first+2, last, "__int128", db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 'o':
+            {
+            const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 'f':
+            {
+            const char* t = parse_floating_number<float>(first+2, last, db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case 'd':
+            {
+            const char* t = parse_floating_number<double>(first+2, last, db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+         case 'e':
+            {
+            const char* t = parse_floating_number<long double>(first+2, last, db);
+            if (t != first+2)
+                first = t;
+            }
+            break;
+        case '_':
+            if (first[2] == 'Z')
+            {
+                const char* t = parse_encoding(first+3, last, db);
+                if (t != first+3 && t != last && *t == 'E')
+                    first = t+1;
+            }
+            break;
+        case 'T':
+            // Invalid mangled name per
+            //   http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+            break;
+        default:
+            {
+                // might be named type
+                const char* t = parse_type(first+1, last, db);
+                if (t != first+1 && t != last)
+                {
+                    if (*t != 'E')
+                    {
+                        const char* n = t;
+                        for (; n != last && isdigit(*n); ++n)
+                            ;
+                        if (n != t && n != last && *n == 'E')
+                        {
+                            if (db.names.empty())
+                                return first;
+                            db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n);
+                            first = n+1;
+                            break;
+                        }
+                    }
+                    else
+                    {
+                        first = t+1;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    return first;
+}
+
+template <class String>
+String
+base_name(String& s)
+{
+    if (s.empty())
+        return s;
+    if (s == "std::string")
+    {
+        s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >";
+        return "basic_string";
+    }
+    if (s == "std::istream")
+    {
+        s = "std::basic_istream<char, std::char_traits<char> >";
+        return "basic_istream";
+    }
+    if (s == "std::ostream")
+    {
+        s = "std::basic_ostream<char, std::char_traits<char> >";
+        return "basic_ostream";
+    }
+    if (s == "std::iostream")
+    {
+        s = "std::basic_iostream<char, std::char_traits<char> >";
+        return "basic_iostream";
+    }
+    const char* const pf = s.data();
+    const char* pe = pf + s.size();
+    if (pe[-1] == '>')
+    {
+        unsigned c = 1;
+        while (true)
+        {
+            if (--pe == pf)
+                return String();
+            if (pe[-1] == '<')
+            {
+                if (--c == 0)
+                {
+                    --pe;
+                    break;
+                }
+            }
+            else if (pe[-1] == '>')
+                ++c;
+        }
+    }
+    const char* p0 = pe - 1;
+    for (; p0 != pf; --p0)
+    {
+        if (*p0 == ':')
+        {
+            ++p0;
+            break;
+        }
+    }
+    return String(p0, pe);
+}
+
+// <ctor-dtor-name> ::= C1    # complete object constructor
+//                  ::= C2    # base object constructor
+//                  ::= C3    # complete object allocating constructor
+//   extension      ::= C5    # ?
+//                  ::= D0    # deleting destructor
+//                  ::= D1    # complete object destructor
+//                  ::= D2    # base object destructor
+//   extension      ::= D5    # ?
+
+template <class C>
+const char*
+parse_ctor_dtor_name(const char* first, const char* last, C& db)
+{
+    if (last-first >= 2 && !db.names.empty())
+    {
+        switch (first[0])
+        {
+        case 'C':
+            switch (first[1])
+            {
+            case '1':
+            case '2':
+            case '3':
+            case '5':
+                if (db.names.empty())
+                    return first;
+                db.names.push_back(base_name(db.names.back().first));
+                first += 2;
+                db.parsed_ctor_dtor_cv = true;
+                break;
+            }
+            break;
+        case 'D':
+            switch (first[1])
+            {
+            case '0':
+            case '1':
+            case '2':
+            case '5':
+                if (db.names.empty())
+                    return first;
+                db.names.push_back("~" + base_name(db.names.back().first));
+                first += 2;
+                db.parsed_ctor_dtor_cv = true;
+                break;
+            }
+            break;
+        }
+    }
+    return first;
+}
+
+// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
+//                     ::= <closure-type-name>
+//
+// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+//
+// <lambda-sig> ::= <parameter type>+  # Parameter types or "v" if the lambda has no parameters
+
+template <class C>
+const char*
+parse_unnamed_type_name(const char* first, const char* last, C& db)
+{
+    if (last - first > 2 && first[0] == 'U')
+    {
+        char type = first[1];
+        switch (type)
+        {
+        case 't':
+          {
+            db.names.push_back(typename C::String("'unnamed"));
+            const char* t0 = first+2;
+            if (t0 == last)
+            {
+                db.names.pop_back();
+                return first;
+            }
+            if (std::isdigit(*t0))
+            {
+                const char* t1 = t0 + 1;
+                while (t1 != last && std::isdigit(*t1))
+                    ++t1;
+                db.names.back().first.append(t0, t1);
+                t0 = t1;
+            }
+            db.names.back().first.push_back('\'');
+            if (t0 == last || *t0 != '_')
+            {
+                db.names.pop_back();
+                return first;
+            }
+            first = t0 + 1;
+          }
+            break;
+        case 'l':
+          {
+            db.names.push_back(typename C::String("'lambda'("));
+            const char* t0 = first+2;
+            if (first[2] == 'v')
+            {
+                db.names.back().first += ')';
+                ++t0;
+            }
+            else
+            {
+                const char* t1 = parse_type(t0, last, db);
+                if (t1 == t0)
+                {
+                    db.names.pop_back();
+                    return first;
+                }
+                if (db.names.size() < 2)
+                    return first;
+                auto tmp = db.names.back().move_full();
+                db.names.pop_back();
+                db.names.back().first.append(tmp);
+                t0 = t1;
+                while (true)
+                {
+                    t1 = parse_type(t0, last, db);
+                    if (t1 == t0)
+                        break;
+                    if (db.names.size() < 2)
+                        return first;
+                    tmp = db.names.back().move_full();
+                    db.names.pop_back();
+                    if (!tmp.empty())
+                    {
+                        db.names.back().first.append(", ");
+                        db.names.back().first.append(tmp);
+                    }
+                    t0 = t1;
+                }
+                db.names.back().first.append(")");
+            }
+            if (t0 == last || *t0 != 'E')
+            {
+                db.names.pop_back();
+                return first;
+            }
+            ++t0;
+            if (t0 == last)
+            {
+                db.names.pop_back();
+                return first;
+            }
+            if (std::isdigit(*t0))
+            {
+                const char* t1 = t0 + 1;
+                while (t1 != last && std::isdigit(*t1))
+                    ++t1;
+                db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1);
+                t0 = t1;
+            }
+            if (t0 == last || *t0 != '_')
+            {
+                db.names.pop_back();
+                return first;
+            }
+            first = t0 + 1;
+          }
+            break;
+        }
+    }
+    return first;
+}
+
+// <unqualified-name> ::= <operator-name>
+//                    ::= <ctor-dtor-name>
+//                    ::= <source-name>
+//                    ::= <unnamed-type-name>
+
+template <class C>
+const char*
+parse_unqualified_name(const char* first, const char* last, C& db)
+{
+    if (first != last)
+    {
+        const char* t;
+        switch (*first)
+        {
+        case 'C':
+        case 'D':
+            t = parse_ctor_dtor_name(first, last, db);
+            if (t != first)
+                first = t;
+            break;
+        case 'U':
+            t = parse_unnamed_type_name(first, last, db);
+            if (t != first)
+                first = t;
+            break;
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+            t = parse_source_name(first, last, db);
+            if (t != first)
+                first = t;
+            break;
+        default:
+            t = parse_operator_name(first, last, db);
+            if (t != first)
+                first = t;
+            break;
+        };
+    }
+    return first;
+}
+
+// <unscoped-name> ::= <unqualified-name>
+//                 ::= St <unqualified-name>   # ::std::
+// extension       ::= StL<unqualified-name>
+
+template <class C>
+const char*
+parse_unscoped_name(const char* first, const char* last, C& db)
+{
+    if (last - first >= 2)
+    {
+        const char* t0 = first;
+        bool St = false;
+        if (first[0] == 'S' && first[1] == 't')
+        {
+            t0 += 2;
+            St = true;
+            if (t0 != last && *t0 == 'L')
+                ++t0;
+        }
+        const char* t1 = parse_unqualified_name(t0, last, db);
+        if (t1 != t0)
+        {
+            if (St)
+            {
+                if (db.names.empty())
+                    return first;
+                db.names.back().first.insert(0, "std::");
+            }
+            first = t1;
+        }
+    }
+    return first;
+}
+
+// at <type>                                            # alignof (a type)
+
+template <class C>
+const char*
+parse_alignof_type(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 'a' && first[1] == 't')
+    {
+        const char* t = parse_type(first+2, last, db);
+        if (t != first+2)
+        {
+            if (db.names.empty())
+                return first;
+            db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
+            first = t;
+        }
+    }
+    return first;
+}
+
+// az <expression>                                            # alignof (a expression)
+
+template <class C>
+const char*
+parse_alignof_expr(const char* first, const char* last, C& db)
+{
+    if (last - first >= 3 && first[0] == 'a' && first[1] == 'z')
+    {
+        const char* t = parse_expression(first+2, last, db);
+        if (t != first+2)
+        {
+            if (db.names.empty())
+                return first;
+            db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
+            first = t;
+        }
+    }
+    return first;
+}
+
+template <class C>
+const char*
+parse_noexcept_expression(const char* first, const char* last, C& db)
+{
+    const char* t1 = parse_expression(first, last, db);
+    if (t1 != first)
+    {
+        if (db.names.empty())
+            return first;
+        db.names.back().first =  "noexcept (" + db.names.back().move_full() + ")";
+        first = t1;
+    }
+    return first;
+}
+
+template <class C>
+const char*
+parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db)
+{
+    const char* t1 = parse_expression(first, last, db);
+    if (t1 != first)
+    {
+        if (db.names.empty())
+            return first;
+        db.names.back().first =  op + "(" + db.names.back().move_full() + ")";
+        first = t1;
+    }
+    return first;
+}
+
+template <class C>
+const char*
+parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db)
+{
+    const char* t1 = parse_expression(first, last, db);
+    if (t1 != first)
+    {
+        const char* t2 = parse_expression(t1, last, db);
+        if (t2 != t1)
+        {
+            if (db.names.size() < 2)
+                return first;
+            auto op2 = db.names.back().move_full();
+            db.names.pop_back();
+            auto op1 = db.names.back().move_full();
+            auto& nm = db.names.back().first;
+            nm.clear();
+            if (op == ">")
+                nm += '(';
+            nm += "(" + op1 + ") " + op + " (" + op2 + ")";
+            if (op == ">")
+                nm += ')';
+            first = t2;
+        }
+        else
+            db.names.pop_back();
+    }
+    return first;
+}
+
+// <expression> ::= <unary operator-name> <expression>
+//              ::= <binary operator-name> <expression> <expression>
+//              ::= <ternary operator-name> <expression> <expression> <expression>
+//              ::= cl <expression>+ E                                   # call
+//              ::= cv <type> <expression>                               # conversion with one argument
+//              ::= cv <type> _ <expression>* E                          # conversion with a different number of arguments
+//              ::= [gs] nw <expression>* _ <type> E                     # new (expr-list) type
+//              ::= [gs] nw <expression>* _ <type> <initializer>         # new (expr-list) type (init)
+//              ::= [gs] na <expression>* _ <type> E                     # new[] (expr-list) type
+//              ::= [gs] na <expression>* _ <type> <initializer>         # new[] (expr-list) type (init)
+//              ::= [gs] dl <expression>                                 # delete expression
+//              ::= [gs] da <expression>                                 # delete[] expression
+//              ::= pp_ <expression>                                     # prefix ++
+//              ::= mm_ <expression>                                     # prefix --
+//              ::= ti <type>                                            # typeid (type)
+//              ::= te <expression>                                      # typeid (expression)
+//              ::= dc <type> <expression>                               # dynamic_cast<type> (expression)
+//              ::= sc <type> <expression>                               # static_cast<type> (expression)
+//              ::= cc <type> <expression>                               # const_cast<type> (expression)
+//              ::= rc <type> <expression>                               # reinterpret_cast<type> (expression)
+//              ::= st <type>                                            # sizeof (a type)
+//              ::= sz <expression>                                      # sizeof (an expression)
+//              ::= at <type>                                            # alignof (a type)
+//              ::= az <expression>                                      # alignof (an expression)
+//              ::= nx <expression>                                      # noexcept (expression)
+//              ::= <template-param>
+//              ::= <function-param>
+//              ::= dt <expression> <unresolved-name>                    # expr.name
+//              ::= pt <expression> <unresolved-name>                    # expr->name
+//              ::= ds <expression> <expression>                         # expr.*expr
+//              ::= sZ <template-param>                                  # size of a parameter pack
+//              ::= sZ <function-param>                                  # size of a function parameter pack
+//              ::= sp <expression>                                      # pack expansion
+//              ::= tw <expression>                                      # throw expression
+//              ::= tr                                                   # throw with no operand (rethrow)
+//              ::= <unresolved-name>                                    # f(p), N::f(p), ::f(p),
+//                                                                       # freestanding dependent name (e.g., T::x),
+//                                                                       # objectless nonstatic member reference
+//              ::= <expr-primary>
+
+template <class C>
+const char*
+parse_expression(const char* first, const char* last, C& db)
+{
+    if (last - first >= 2)
+    {
+        const char* t = first;
+        bool parsed_gs = false;
+        if (last - first >= 4 && t[0] == 'g' && t[1] == 's')
+        {
+            t += 2;
+            parsed_gs = true;
+        }
+        switch (*t)
+        {
+        case 'L':
+            first = parse_expr_primary(first, last, db);
+            break;
+        case 'T':
+            first = parse_template_param(first, last, db);
+            break;
+        case 'f':
+            first = parse_function_param(first, last, db);
+            break;
+        case 'a':
+            switch (t[1])
+            {
+            case 'a':
+                t = parse_binary_expression(first+2, last, "&&", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'd':
+                t = parse_prefix_expression(first+2, last, "&", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'n':
+                t = parse_binary_expression(first+2, last, "&", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'N':
+                t = parse_binary_expression(first+2, last, "&=", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'S':
+                t = parse_binary_expression(first+2, last, "=", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 't':
+                first = parse_alignof_type(first, last, db);
+                break;
+            case 'z':
+                first = parse_alignof_expr(first, last, db);
+                break;
+            }
+            break;
+        case 'c':
+            switch (t[1])
+            {
+            case 'c':
+                first = parse_const_cast_expr(first, last, db);
+                break;
+            case 'l':
+                first = parse_call_expr(first, last, db);
+                break;
+            case 'm':
+                t = parse_binary_expression(first+2, last, ",", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'o':
+                t = parse_prefix_expression(first+2, last, "~", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'v':
+                first = parse_conversion_expr(first, last, db);
+                break;
+            }
+            break;
+        case 'd':
+            switch (t[1])
+            {
+            case 'a':
+                {
+                    const char* t1 = parse_expression(t+2, last, db);
+                    if (t1 != t+2)
+                    {
+                        if (db.names.empty())
+                            return first;
+                        db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
+                                          "delete[] " + db.names.back().move_full();
+                        first = t1;
+                    }
+                }
+                break;
+            case 'c':
+                first = parse_dynamic_cast_expr(first, last, db);
+                break;
+            case 'e':
+                t = parse_prefix_expression(first+2, last, "*", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'l':
+                {
+                    const char* t1 = parse_expression(t+2, last, db);
+                    if (t1 != t+2)
+                    {
+                        if (db.names.empty())
+                            return first;
+                        db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
+                                          "delete " + db.names.back().move_full();
+                        first = t1;
+                    }
+                }
+                break;
+            case 'n':
+                return parse_unresolved_name(first, last, db);
+            case 's':
+                first = parse_dot_star_expr(first, last, db);
+                break;
+            case 't':
+                first = parse_dot_expr(first, last, db);
+                break;
+            case 'v':
+                t = parse_binary_expression(first+2, last, "/", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'V':
+                t = parse_binary_expression(first+2, last, "/=", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            }
+            break;
+        case 'e':
+            switch (t[1])
+            {
+            case 'o':
+                t = parse_binary_expression(first+2, last, "^", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'O':
+                t = parse_binary_expression(first+2, last, "^=", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'q':
+                t = parse_binary_expression(first+2, last, "==", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            }
+            break;
+        case 'g':
+            switch (t[1])
+            {
+            case 'e':
+                t = parse_binary_expression(first+2, last, ">=", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 't':
+                t = parse_binary_expression(first+2, last, ">", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            }
+            break;
+        case 'i':
+            if (t[1] == 'x')
+            {
+                const char* t1 = parse_expression(first+2, last, db);
+                if (t1 != first+2)
+                {
+                    const char* t2 = parse_expression(t1, last, db);
+                    if (t2 != t1)
+                    {
+                        if (db.names.size() < 2)
+                            return first;
+                        auto op2 = db.names.back().move_full();
+                        db.names.pop_back();
+                        auto op1 = db.names.back().move_full();
+                        db.names.back() = "(" + op1 + ")[" + op2 + "]";
+                        first = t2;
+                    }
+                    else
+                        db.names.pop_back();
+                }
+            }
+            break;
+        case 'l':
+            switch (t[1])
+            {
+            case 'e':
+                t = parse_binary_expression(first+2, last, "<=", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 's':
+                t = parse_binary_expression(first+2, last, "<<", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'S':
+                t = parse_binary_expression(first+2, last, "<<=", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 't':
+                t = parse_binary_expression(first+2, last, "<", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            }
+            break;
+        case 'm':
+            switch (t[1])
+            {
+            case 'i':
+                t = parse_binary_expression(first+2, last, "-", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'I':
+                t = parse_binary_expression(first+2, last, "-=", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'l':
+                t = parse_binary_expression(first+2, last, "*", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'L':
+                t = parse_binary_expression(first+2, last, "*=", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'm':
+                if (first+2 != last && first[2] == '_')
+                {
+                    t = parse_prefix_expression(first+3, last, "--", db);
+                    if (t != first+3)
+                        first = t;
+                }
+                else
+                {
+                    const char* t1 = parse_expression(first+2, last, db);
+                    if (t1 != first+2)
+                    {
+                        if (db.names.empty())
+                            return first;
+                        db.names.back() = "(" + db.names.back().move_full() + ")--";
+                        first = t1;
+                    }
+                }
+                break;
+            }
+            break;
+        case 'n':
+            switch (t[1])
+            {
+            case 'a':
+            case 'w':
+                first = parse_new_expr(first, last, db);
+                break;
+            case 'e':
+                t = parse_binary_expression(first+2, last, "!=", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'g':
+                t = parse_prefix_expression(first+2, last, "-", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 't':
+                t = parse_prefix_expression(first+2, last, "!", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'x':
+                t = parse_noexcept_expression(first+2, last, db);
+                if (t != first+2)
+                    first = t;
+                break;
+            }
+            break;
+        case 'o':
+            switch (t[1])
+            {
+            case 'n':
+                return parse_unresolved_name(first, last, db);
+            case 'o':
+                t = parse_binary_expression(first+2, last, "||", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'r':
+                t = parse_binary_expression(first+2, last, "|", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'R':
+                t = parse_binary_expression(first+2, last, "|=", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            }
+            break;
+        case 'p':
+            switch (t[1])
+            {
+            case 'm':
+                t = parse_binary_expression(first+2, last, "->*", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'l':
+                t = parse_binary_expression(first+2, last, "+", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'L':
+                t = parse_binary_expression(first+2, last, "+=", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'p':
+                if (first+2 != last && first[2] == '_')
+                {
+                    t = parse_prefix_expression(first+3, last, "++", db);
+                    if (t != first+3)
+                        first = t;
+                }
+                else
+                {
+                    const char* t1 = parse_expression(first+2, last, db);
+                    if (t1 != first+2)
+                    {
+                        if (db.names.empty())
+                            return first;
+                        db.names.back() = "(" + db.names.back().move_full() + ")++";
+                        first = t1;
+                    }
+                }
+                break;
+            case 's':
+                t = parse_prefix_expression(first+2, last, "+", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 't':
+                first = parse_arrow_expr(first, last, db);
+                break;
+            }
+            break;
+        case 'q':
+            if (t[1] == 'u')
+            {
+                const char* t1 = parse_expression(first+2, last, db);
+                if (t1 != first+2)
+                {
+                    const char* t2 = parse_expression(t1, last, db);
+                    if (t2 != t1)
+                    {
+                        const char* t3 = parse_expression(t2, last, db);
+                        if (t3 != t2)
+                        {
+                            if (db.names.size() < 3)
+                                return first;
+                            auto op3 = db.names.back().move_full();
+                            db.names.pop_back();
+                            auto op2 = db.names.back().move_full();
+                            db.names.pop_back();
+                            auto op1 = db.names.back().move_full();
+                            db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")";
+                            first = t3;
+                        }
+                        else
+                        {
+                            db.names.pop_back();
+                            db.names.pop_back();
+                        }
+                    }
+                    else
+                        db.names.pop_back();
+                }
+            }
+            break;
+        case 'r':
+            switch (t[1])
+            {
+            case 'c':
+                first = parse_reinterpret_cast_expr(first, last, db);
+                break;
+            case 'm':
+                t = parse_binary_expression(first+2, last, "%", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'M':
+                t = parse_binary_expression(first+2, last, "%=", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 's':
+                t = parse_binary_expression(first+2, last, ">>", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            case 'S':
+                t = parse_binary_expression(first+2, last, ">>=", db);
+                if (t != first+2)
+                    first = t;
+                break;
+            }
+            break;
+        case 's':
+            switch (t[1])
+            {
+            case 'c':
+                first = parse_static_cast_expr(first, last, db);
+                break;
+            case 'p':
+                first = parse_pack_expansion(first, last, db);
+                break;
+            case 'r':
+                return parse_unresolved_name(first, last, db);
+            case 't':
+                first = parse_sizeof_type_expr(first, last, db);
+                break;
+            case 'z':
+                first = parse_sizeof_expr_expr(first, last, db);
+                break;
+            case 'Z':
+                if (last - t >= 3)
+                {
+                    switch (t[2])
+                    {
+                    case 'T':
+                        first = parse_sizeof_param_pack_expr(first, last, db);
+                        break;
+                    case 'f':
+                        first = parse_sizeof_function_param_pack_expr(first, last, db);
+                        break;
+                    }
+                }
+                break;
+            }
+            break;
+        case 't':
+            switch (t[1])
+            {
+            case 'e':
+            case 'i':
+                first = parse_typeid_expr(first, last, db);
+                break;
+            case 'r':
+                db.names.push_back("throw");
+                first += 2;
+                break;
+            case 'w':
+                first = parse_throw_expr(first, last, db);
+                break;
+            }
+            break;
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+            return parse_unresolved_name(first, last, db);
+        }
+    }
+    return first;
+}
+
+// <template-arg> ::= <type>                                             # type or template
+//                ::= X <expression> E                                   # expression
+//                ::= <expr-primary>                                     # simple expressions
+//                ::= J <template-arg>* E                                # argument pack
+//                ::= LZ <encoding> E                                    # extension
+
+template <class C>
+const char*
+parse_template_arg(const char* first, const char* last, C& db)
+{
+    if (first != last)
+    {
+        const char* t;
+        switch (*first)
+        {
+        case 'X':
+            t = parse_expression(first+1, last, db);
+            if (t != first+1)
+            {
+                if (t != last && *t == 'E')
+                    first = t+1;
+            }
+            break;
+        case 'J':
+            t = first+1;
+            if (t == last)
+                return first;
+            while (*t != 'E')
+            {
+                const char* t1 = parse_template_arg(t, last, db);
+                if (t1 == t)
+                    return first;
+                t = t1;
+            }
+            first = t+1;
+            break;
+        case 'L':
+            // <expr-primary> or LZ <encoding> E
+            if (first+1 != last && first[1] == 'Z')
+            {
+                t = parse_encoding(first+2, last, db);
+                if (t != first+2 && t != last && *t == 'E')
+                    first = t+1;
+            }
+            else
+                first = parse_expr_primary(first, last, db);
+            break;
+        default:
+            // <type>
+            first = parse_type(first, last, db);
+            break;
+        }
+    }
+    return first;
+}
+
+// <template-args> ::= I <template-arg>* E
+//     extension, the abi says <template-arg>+
+
+template <class C>
+const char*
+parse_template_args(const char* first, const char* last, C& db)
+{
+    if (last - first >= 2 && *first == 'I')
+    {
+        if (db.tag_templates)
+            db.template_param.back().clear();
+        const char* t = first+1;
+        typename C::String args("<");
+        while (*t != 'E')
+        {
+            if (db.tag_templates)
+                db.template_param.emplace_back(db.names.get_allocator());
+            size_t k0 = db.names.size();
+            const char* t1 = parse_template_arg(t, last, db);
+            size_t k1 = db.names.size();
+            if (db.tag_templates)
+                db.template_param.pop_back();
+            if (t1 == t || t1 == last)
+                return first;
+            if (db.tag_templates)
+            {
+                db.template_param.back().emplace_back(db.names.get_allocator());
+                for (size_t k = k0; k < k1; ++k)
+                    db.template_param.back().back().push_back(db.names[k]);
+            }
+            for (size_t k = k0; k < k1; ++k)
+            {
+                if (args.size() > 1)
+                    args += ", ";
+                args += db.names[k].move_full();
+            }
+            for (; k1 != k0; --k1)
+                db.names.pop_back();
+            t = t1;
+        }
+        first = t + 1;
+        if (args.back() != '>')
+            args += ">";
+        else
+            args += " >";
+        db.names.push_back(std::move(args));
+
+    }
+    return first;
+}
+
+// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+//               ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+//
+// <prefix> ::= <prefix> <unqualified-name>
+//          ::= <template-prefix> <template-args>
+//          ::= <template-param>
+//          ::= <decltype>
+//          ::= # empty
+//          ::= <substitution>
+//          ::= <prefix> <data-member-prefix>
+//  extension ::= L
+//
+// <template-prefix> ::= <prefix> <template unqualified-name>
+//                   ::= <template-param>
+//                   ::= <substitution>
+
+template <class C>
+const char*
+parse_nested_name(const char* first, const char* last, C& db,
+                  bool* ends_with_template_args)
+{
+    if (first != last && *first == 'N')
+    {
+        unsigned cv;
+        const char* t0 = parse_cv_qualifiers(first+1, last, cv);
+        if (t0 == last)
+            return first;
+        db.ref = 0;
+        if (*t0 == 'R')
+        {
+            db.ref = 1;
+            ++t0;
+        }
+        else if (*t0 == 'O')
+        {
+            db.ref = 2;
+            ++t0;
+        }
+        db.names.emplace_back();
+        if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')
+        {
+            t0 += 2;
+            db.names.back().first = "std";
+        }
+        if (t0 == last)
+        {
+            db.names.pop_back();
+            return first;
+        }
+        bool pop_subs = false;
+        bool component_ends_with_template_args = false;
+        while (*t0 != 'E')
+        {
+            component_ends_with_template_args = false;
+            const char* t1;
+            switch (*t0)
+            {
+            case 'S':
+                if (t0 + 1 != last && t0[1] == 't')
+                    goto do_parse_unqualified_name;
+                t1 = parse_substitution(t0, last, db);
+                if (t1 != t0 && t1 != last)
+                {
+                    auto name = db.names.back().move_full();
+                    db.names.pop_back();
+                    if (!db.names.back().first.empty())
+                    {
+                        db.names.back().first += "::" + name;
+                        db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                    }
+                    else
+                        db.names.back().first = name;
+                    pop_subs = true;
+                    t0 = t1;
+                }
+                else
+                    return first;
+                break;
+            case 'T':
+                t1 = parse_template_param(t0, last, db);
+                if (t1 != t0 && t1 != last)
+                {
+                    auto name = db.names.back().move_full();
+                    db.names.pop_back();
+                    if (!db.names.back().first.empty())
+                        db.names.back().first += "::" + name;
+                    else
+                        db.names.back().first = name;
+                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                    pop_subs = true;
+                    t0 = t1;
+                }
+                else
+                    return first;
+                break;
+            case 'D':
+                if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T')
+                    goto do_parse_unqualified_name;
+                t1 = parse_decltype(t0, last, db);
+                if (t1 != t0 && t1 != last)
+                {
+                    auto name = db.names.back().move_full();
+                    db.names.pop_back();
+                    if (!db.names.back().first.empty())
+                        db.names.back().first += "::" + name;
+                    else
+                        db.names.back().first = name;
+                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                    pop_subs = true;
+                    t0 = t1;
+                }
+                else
+                    return first;
+                break;
+            case 'I':
+                t1 = parse_template_args(t0, last, db);
+                if (t1 != t0 && t1 != last)
+                {
+                    auto name = db.names.back().move_full();
+                    db.names.pop_back();
+                    db.names.back().first += name;
+                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                    t0 = t1;
+                    component_ends_with_template_args = true;
+                }
+                else
+                    return first;
+                break;
+            case 'L':
+                if (++t0 == last)
+                    return first;
+                break;
+            default:
+            do_parse_unqualified_name:
+                t1 = parse_unqualified_name(t0, last, db);
+                if (t1 != t0 && t1 != last)
+                {
+                    auto name = db.names.back().move_full();
+                    db.names.pop_back();
+                    if (!db.names.back().first.empty())
+                        db.names.back().first += "::" + name;
+                    else
+                        db.names.back().first = name;
+                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                    pop_subs = true;
+                    t0 = t1;
+                }
+                else
+                    return first;
+            }
+        }
+        first = t0 + 1;
+        db.cv = cv;
+        if (pop_subs && !db.subs.empty())
+            db.subs.pop_back();
+        if (ends_with_template_args)
+            *ends_with_template_args = component_ends_with_template_args;
+    }
+    return first;
+}
+
+// <discriminator> := _ <non-negative number>      # when number < 10
+//                 := __ <non-negative number> _   # when number >= 10
+//  extension      := decimal-digit+
+
+const char*
+parse_discriminator(const char* first, const char* last)
+{
+    // parse but ignore discriminator
+    if (first != last)
+    {
+        if (*first == '_')
+        {
+            const char* t1 = first+1;
+            if (t1 != last)
+            {
+                if (std::isdigit(*t1))
+                    first = t1+1;
+                else if (*t1 == '_')
+                {
+                    for (++t1; t1 != last && std::isdigit(*t1); ++t1)
+                        ;
+                    if (t1 != last && *t1 == '_')
+                        first = t1 + 1;
+                }
+            }
+        }
+        else if (std::isdigit(*first))
+        {
+            const char* t1 = first+1;
+            for (; t1 != last && std::isdigit(*t1); ++t1)
+                ;
+            first = t1;
+        }
+    }
+    return first;
+}
+
+// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+//              := Z <function encoding> E s [<discriminator>]
+//              := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
+
+template <class C>
+const char*
+parse_local_name(const char* first, const char* last, C& db,
+                 bool* ends_with_template_args)
+{
+    if (first != last && *first == 'Z')
+    {
+        const char* t = parse_encoding(first+1, last, db);
+        if (t != first+1 && t != last && *t == 'E' && ++t != last)
+        {
+            switch (*t)
+            {
+            case 's':
+                first = parse_discriminator(t+1, last);
+                if (db.names.empty())
+                    return first;
+                db.names.back().first.append("::string literal");
+                break;
+            case 'd':
+                if (++t != last)
+                {
+                    const char* t1 = parse_number(t, last);
+                    if (t1 != last && *t1 == '_')
+                    {
+                        t = t1 + 1;
+                        t1 = parse_name(t, last, db,
+                                        ends_with_template_args);
+                        if (t1 != t)
+                        {
+                            if (db.names.size() < 2)
+                                return first;
+                            auto name = db.names.back().move_full();
+                            db.names.pop_back();
+                            db.names.back().first.append("::");
+                            db.names.back().first.append(name);
+                            first = t1;
+                        }
+                        else
+                            db.names.pop_back();
+                    }
+                }
+                break;
+            default:
+                {
+                    const char* t1 = parse_name(t, last, db,
+                                                ends_with_template_args);
+                    if (t1 != t)
+                    {
+                        // parse but ignore discriminator
+                        first = parse_discriminator(t1, last);
+                        if (db.names.size() < 2)
+                            return first;
+                        auto name = db.names.back().move_full();
+                        db.names.pop_back();
+                        db.names.back().first.append("::");
+                        db.names.back().first.append(name);
+                    }
+                    else
+                        db.names.pop_back();
+                }
+                break;
+            }
+        }
+    }
+    return first;
+}
+
+// <name> ::= <nested-name> // N
+//        ::= <local-name> # See Scope Encoding below  // Z
+//        ::= <unscoped-template-name> <template-args>
+//        ::= <unscoped-name>
+
+// <unscoped-template-name> ::= <unscoped-name>
+//                          ::= <substitution>
+
+template <class C>
+const char*
+parse_name(const char* first, const char* last, C& db,
+           bool* ends_with_template_args)
+{
+    if (last - first >= 2)
+    {
+        const char* t0 = first;
+        // extension: ignore L here
+        if (*t0 == 'L')
+            ++t0;
+        switch (*t0)
+        {
+        case 'N':
+          {
+            const char* t1 = parse_nested_name(t0, last, db,
+                                               ends_with_template_args);
+            if (t1 != t0)
+                first = t1;
+            break;
+          }
+        case 'Z':
+          {
+            const char* t1 = parse_local_name(t0, last, db,
+                                              ends_with_template_args);
+            if (t1 != t0)
+                first = t1;
+            break;
+          }
+        default:
+          {
+            const char* t1 = parse_unscoped_name(t0, last, db);
+            if (t1 != t0)
+            {
+                if (t1 != last && *t1 == 'I')  // <unscoped-template-name> <template-args>
+                {
+                    if (db.names.empty())
+                        return first;
+                    db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+                    t0 = t1;
+                    t1 = parse_template_args(t0, last, db);
+                    if (t1 != t0)
+                    {
+                        if (db.names.size() < 2)
+                            return first;
+                        auto tmp = db.names.back().move_full();
+                        db.names.pop_back();
+                        db.names.back().first += tmp;
+                        first = t1;
+                        if (ends_with_template_args)
+                            *ends_with_template_args = true;
+                    }
+                }
+                else   // <unscoped-name>
+                    first = t1;
+            }
+            else
+            {   // try <substitution> <template-args>
+                t1 = parse_substitution(t0, last, db);
+                if (t1 != t0 && t1 != last && *t1 == 'I')
+                {
+                    t0 = t1;
+                    t1 = parse_template_args(t0, last, db);
+                    if (t1 != t0)
+                    {
+                        if (db.names.size() < 2)
+                            return first;
+                        auto tmp = db.names.back().move_full();
+                        db.names.pop_back();
+                        db.names.back().first += tmp;
+                        first = t1;
+                        if (ends_with_template_args)
+                            *ends_with_template_args = true;
+                    }
+                }
+            }
+            break;
+          }
+        }
+    }
+    return first;
+}
+
+// <call-offset> ::= h <nv-offset> _
+//               ::= v <v-offset> _
+//
+// <nv-offset> ::= <offset number>
+//               # non-virtual base override
+//
+// <v-offset>  ::= <offset number> _ <virtual offset number>
+//               # virtual base override, with vcall offset
+
+const char*
+parse_call_offset(const char* first, const char* last)
+{
+    if (first != last)
+    {
+        switch (*first)
+        {
+        case 'h':
+            {
+            const char* t = parse_number(first + 1, last);
+            if (t != first + 1 && t != last && *t == '_')
+                first = t + 1;
+            }
+            break;
+        case 'v':
+            {
+            const char* t = parse_number(first + 1, last);
+            if (t != first + 1 && t != last && *t == '_')
+            {
+                const char* t2 = parse_number(++t, last);
+                if (t2 != t && t2 != last && *t2 == '_')
+                    first = t2 + 1;
+            }
+            }
+            break;
+        }
+    }
+    return first;
+}
+
+// <special-name> ::= TV <type>    # virtual table
+//                ::= TT <type>    # VTT structure (construction vtable index)
+//                ::= TI <type>    # typeinfo structure
+//                ::= TS <type>    # typeinfo name (null-terminated byte string)
+//                ::= Tc <call-offset> <call-offset> <base encoding>
+//                    # base is the nominal target function of thunk
+//                    # first call-offset is 'this' adjustment
+//                    # second call-offset is result adjustment
+//                ::= T <call-offset> <base encoding>
+//                    # base is the nominal target function of thunk
+//                ::= GV <object name> # Guard variable for one-time initialization
+//                                     # No <type>
+//      extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+//      extension ::= GR <object name> # reference temporary for object
+
+template <class C>
+const char*
+parse_special_name(const char* first, const char* last, C& db)
+{
+    if (last - first > 2)
+    {
+        const char* t;
+        switch (*first)
+        {
+        case 'T':
+            switch (first[1])
+            {
+            case 'V':
+                // TV <type>    # virtual table
+                t = parse_type(first+2, last, db);
+                if (t != first+2)
+                {
+                    if (db.names.empty())
+                        return first;
+                    db.names.back().first.insert(0, "vtable for ");
+                    first = t;
+                }
+                break;
+            case 'T':
+                // TT <type>    # VTT structure (construction vtable index)
+                t = parse_type(first+2, last, db);
+                if (t != first+2)
+                {
+                    if (db.names.empty())
+                        return first;
+                    db.names.back().first.insert(0, "VTT for ");
+                    first = t;
+                }
+                break;
+            case 'I':
+                // TI <type>    # typeinfo structure
+                t = parse_type(first+2, last, db);
+                if (t != first+2)
+                {
+                    if (db.names.empty())
+                        return first;
+                    db.names.back().first.insert(0, "typeinfo for ");
+                    first = t;
+                }
+                break;
+            case 'S':
+                // TS <type>    # typeinfo name (null-terminated byte string)
+                t = parse_type(first+2, last, db);
+                if (t != first+2)
+                {
+                    if (db.names.empty())
+                        return first;
+                    db.names.back().first.insert(0, "typeinfo name for ");
+                    first = t;
+                }
+                break;
+            case 'c':
+                // Tc <call-offset> <call-offset> <base encoding>
+              {
+                const char* t0 = parse_call_offset(first+2, last);
+                if (t0 == first+2)
+                    break;
+                const char* t1 = parse_call_offset(t0, last);
+                if (t1 == t0)
+                    break;
+                t = parse_encoding(t1, last, db);
+                if (t != t1)
+                {
+                    if (db.names.empty())
+                        return first;
+                    db.names.back().first.insert(0, "covariant return thunk to ");
+                    first = t;
+                }
+              }
+                break;
+            case 'C':
+                // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+                t = parse_type(first+2, last, db);
+                if (t != first+2)
+                {
+                    const char* t0 = parse_number(t, last);
+                    if (t0 != t && t0 != last && *t0 == '_')
+                    {
+                        const char* t1 = parse_type(++t0, last, db);
+                        if (t1 != t0)
+                        {
+                            if (db.names.size() < 2)
+                                return first;
+                            auto left = db.names.back().move_full();
+                            db.names.pop_back();
+                            db.names.back().first = "construction vtable for " +
+                                                    std::move(left) + "-in-" +
+                                                    db.names.back().move_full();
+                            first = t1;
+                        }
+                    }
+                }
+                break;
+            default:
+                // T <call-offset> <base encoding>
+                {
+                const char* t0 = parse_call_offset(first+1, last);
+                if (t0 == first+1)
+                    break;
+                t = parse_encoding(t0, last, db);
+                if (t != t0)
+                {
+                    if (db.names.empty())
+                        return first;
+                    if (first[2] == 'v')
+                    {
+                        db.names.back().first.insert(0, "virtual thunk to ");
+                        first = t;
+                    }
+                    else
+                    {
+                        db.names.back().first.insert(0, "non-virtual thunk to ");
+                        first = t;
+                    }
+                }
+                }
+                break;
+            }
+            break;
+        case 'G':
+            switch (first[1])
+            {
+            case 'V':
+                // GV <object name> # Guard variable for one-time initialization
+                t = parse_name(first+2, last, db);
+                if (t != first+2)
+                {
+                    if (db.names.empty())
+                        return first;
+                    db.names.back().first.insert(0, "guard variable for ");
+                    first = t;
+                }
+                break;
+            case 'R':
+                // extension ::= GR <object name> # reference temporary for object
+                t = parse_name(first+2, last, db);
+                if (t != first+2)
+                {
+                    if (db.names.empty())
+                        return first;
+                    db.names.back().first.insert(0, "reference temporary for ");
+                    first = t;
+                }
+                break;
+            }
+            break;
+        }
+    }
+    return first;
+}
+
+template <class T>
+class save_value
+{
+    T& restore_;
+    T original_value_;
+public:
+    save_value(T& restore)
+        : restore_(restore),
+          original_value_(restore)
+        {}
+
+    ~save_value()
+    {
+        restore_ = std::move(original_value_);
+    }
+
+    save_value(const save_value&) = delete;
+    save_value& operator=(const save_value&) = delete;
+};
+
+// <encoding> ::= <function name> <bare-function-type>
+//            ::= <data name>
+//            ::= <special-name>
+
+template <class C>
+const char*
+parse_encoding(const char* first, const char* last, C& db)
+{
+    if (first != last)
+    {
+        save_value<decltype(db.encoding_depth)> su(db.encoding_depth);
+        ++db.encoding_depth;
+        save_value<decltype(db.tag_templates)> sb(db.tag_templates);
+        if (db.encoding_depth > 1)
+            db.tag_templates = true;
+        switch (*first)
+        {
+        case 'G':
+        case 'T':
+            first = parse_special_name(first, last, db);
+            break;
+        default:
+          {
+            bool ends_with_template_args = false;
+            const char* t = parse_name(first, last, db,
+                                       &ends_with_template_args);
+            unsigned cv = db.cv;
+            unsigned ref = db.ref;
+            if (t != first)
+            {
+                if (t != last && *t != 'E' && *t != '.')
+                {
+                    save_value<bool> sb2(db.tag_templates);
+                    db.tag_templates = false;
+                    const char* t2;
+                    typename C::String ret2;
+                    if (db.names.empty())
+                        return first;
+                    const typename C::String& nm = db.names.back().first;
+                    if (nm.empty())
+                        return first;
+                    if (!db.parsed_ctor_dtor_cv && ends_with_template_args)
+                    {
+                        t2 = parse_type(t, last, db);
+                        if (t2 == t)
+                            return first;
+                        if (db.names.size() < 2)
+                            return first;
+                        auto ret1 = std::move(db.names.back().first);
+                        ret2 = std::move(db.names.back().second);
+                        if (ret2.empty())
+                            ret1 += ' ';
+                        db.names.pop_back();
+                        db.names.back().first.insert(0, ret1);
+                        t = t2;
+                    }
+                    db.names.back().first += '(';
+                    if (t != last && *t == 'v')
+                    {
+                        ++t;
+                    }
+                    else
+                    {
+                        bool first_arg = true;
+                        while (true)
+                        {
+                            size_t k0 = db.names.size();
+                            t2 = parse_type(t, last, db);
+                            size_t k1 = db.names.size();
+                            if (t2 == t)
+                                break;
+                            if (k1 > k0)
+                            {
+                                typename C::String tmp;
+                                for (size_t k = k0; k < k1; ++k)
+                                {
+                                    if (!tmp.empty())
+                                        tmp += ", ";
+                                    tmp += db.names[k].move_full();
+                                }
+                                for (size_t k = k0; k < k1; ++k)
+                                    db.names.pop_back();
+                                if (!tmp.empty())
+                                {
+                                    if (db.names.empty())
+                                        return first;
+                                    if (!first_arg)
+                                        db.names.back().first += ", ";
+                                    else
+                                        first_arg = false;
+                                    db.names.back().first += tmp;
+                                }
+                            }
+                            t = t2;
+                        }
+                    }
+                    if (db.names.empty())
+                        return first;
+                    db.names.back().first += ')';
+                    if (cv & 1)
+                        db.names.back().first.append(" const");
+                    if (cv & 2)
+                        db.names.back().first.append(" volatile");
+                    if (cv & 4)
+                        db.names.back().first.append(" restrict");
+                    if (ref == 1)
+                        db.names.back().first.append(" &");
+                    else if (ref == 2)
+                        db.names.back().first.append(" &&");
+                    db.names.back().first += ret2;
+                    first = t;
+                }
+                else
+                    first = t;
+            }
+            break;
+          }
+        }
+    }
+    return first;
+}
+
+// _block_invoke
+// _block_invoke<decimal-digit>+
+// _block_invoke_<decimal-digit>+
+
+template <class C>
+const char*
+parse_block_invoke(const char* first, const char* last, C& db)
+{
+    if (last - first >= 13)
+    {
+        const char test[] = "_block_invoke";
+        const char* t = first;
+        for (int i = 0; i < 13; ++i, ++t)
+        {
+            if (*t != test[i])
+                return first;
+        }
+        if (t != last)
+        {
+            if (*t == '_')
+            {
+                // must have at least 1 decimal digit
+                if (++t == last || !std::isdigit(*t))
+                    return first;
+                ++t;
+            }
+            // parse zero or more digits
+            while (t != last && isdigit(*t))
+                ++t;
+        }
+        if (db.names.empty())
+            return first;
+        db.names.back().first.insert(0, "invocation function for block in ");
+        first = t;
+    }
+    return first;
+}
+
+// extension
+// <dot-suffix> := .<anything and everything>
+
+template <class C>
+const char*
+parse_dot_suffix(const char* first, const char* last, C& db)
+{
+    if (first != last && *first == '.')
+    {
+        if (db.names.empty())
+            return first;
+        db.names.back().first += " (" + typename C::String(first, last) + ")";
+        first = last;
+    }
+    return first;
+}
+
+// <block-involcaton-function> ___Z<encoding>_block_invoke
+// <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+
+// <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+
+// <mangled-name> ::= _Z<encoding>
+//                ::= <type>
+
+template <class C>
+void
+demangle(const char* first, const char* last, C& db, int& status)
+{
+    if (first >= last)
+    {
+        status = invalid_mangled_name;
+        return;
+    }
+    if (*first == '_')
+    {
+        if (last - first >= 4)
+        {
+            if (first[1] == 'Z')
+            {
+                const char* t = parse_encoding(first+2, last, db);
+                if (t != first+2 && t != last && *t == '.')
+                    t = parse_dot_suffix(t, last, db);
+                if (t != last)
+                    status = invalid_mangled_name;
+            }
+            else if (first[1] == '_' && first[2] == '_' && first[3] == 'Z')
+            {
+                const char* t = parse_encoding(first+4, last, db);
+                if (t != first+4 && t != last)
+                {
+                    const char* t1 = parse_block_invoke(t, last, db);
+                    if (t1 != last)
+                        status = invalid_mangled_name;
+                }
+                else
+                    status = invalid_mangled_name;
+            }
+            else
+                status = invalid_mangled_name;
+        }
+        else
+            status = invalid_mangled_name;
+    }
+    else
+    {
+        const char* t = parse_type(first, last, db);
+        if (t != last)
+            status = invalid_mangled_name;
+    }
+    if (status == success && db.names.empty())
+        status = invalid_mangled_name;
+}
+
+template <std::size_t N>
+class arena
+{
+    static const std::size_t alignment = 16;
+    alignas(alignment) char buf_[N];
+    char* ptr_;
+
+#if UPSTREAM_CODE
+    std::size_t
+    align_up(std::size_t n) noexcept
+        {return n + (alignment-1) & ~(alignment-1);}
+#else
+    std::size_t
+    align_up(std::size_t n) noexcept
+        {return (n + (alignment-1)) & ~(alignment-1);}
+#endif
+
+    bool
+    pointer_in_buffer(char* p) noexcept
+        {return buf_ <= p && p <= buf_ + N;}
+
+public:
+    arena() noexcept : ptr_(buf_) {}
+    ~arena() {ptr_ = nullptr;}
+    arena(const arena&) = delete;
+    arena& operator=(const arena&) = delete;
+
+    char* allocate(std::size_t n);
+    void deallocate(char* p, std::size_t n) noexcept;
+
+    static constexpr std::size_t size() {return N;}
+    std::size_t used() const {return static_cast<std::size_t>(ptr_ - buf_);}
+    void reset() {ptr_ = buf_;}
+};
+
+template <std::size_t N>
+char*
+arena<N>::allocate(std::size_t n)
+{
+    n = align_up(n);
+    if (static_cast<std::size_t>(buf_ + N - ptr_) >= n)
+    {
+        char* r = ptr_;
+        ptr_ += n;
+        return r;
+    }
+    return static_cast<char*>(std::malloc(n));
+}
+
+template <std::size_t N>
+void
+arena<N>::deallocate(char* p, std::size_t n) noexcept
+{
+    if (pointer_in_buffer(p))
+    {
+        n = align_up(n);
+        if (p + n == ptr_)
+            ptr_ = p;
+    }
+    else
+        std::free(p);
+}
+
+template <class T, std::size_t N>
+class short_alloc
+{
+    arena<N>& a_;
+public:
+    typedef T value_type;
+
+public:
+    template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;};
+
+    short_alloc(arena<N>& a) noexcept : a_(a) {}
+    template <class U>
+        short_alloc(const short_alloc<U, N>& a) noexcept
+            : a_(a.a_) {}
+    short_alloc(const short_alloc&) = default;
+    short_alloc& operator=(const short_alloc&) = delete;
+
+    T* allocate(std::size_t n)
+    {
+        return reinterpret_cast<T*>(a_.allocate(n*sizeof(T)));
+    }
+    void deallocate(T* p, std::size_t n) noexcept
+    {
+        a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
+    }
+
+    template <class T1, std::size_t N1, class U, std::size_t M>
+    friend
+    bool
+    operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) noexcept;
+
+    template <class U, std::size_t M> friend class short_alloc;
+};
+
+template <class T, std::size_t N, class U, std::size_t M>
+inline
+bool
+operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
+{
+    return N == M && &x.a_ == &y.a_;
+}
+
+template <class T, std::size_t N, class U, std::size_t M>
+inline
+bool
+operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
+{
+    return !(x == y);
+}
+
+template <class T>
+class malloc_alloc
+{
+public:
+    typedef T value_type;
+
+    malloc_alloc() = default;
+    template <class U> malloc_alloc(const malloc_alloc<U>&) noexcept {}
+
+    T* allocate(std::size_t n)
+    {
+        return static_cast<T*>(std::malloc(n*sizeof(T)));
+    }
+    void deallocate(T* p, std::size_t) noexcept
+    {
+        std::free(p);
+    }
+};
+
+template <class T, class U>
+inline
+bool
+operator==(const malloc_alloc<T>&, const malloc_alloc<U>&) noexcept
+{
+    return true;
+}
+
+template <class T, class U>
+inline
+bool
+operator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) noexcept
+{
+    return !(x == y);
+}
+
+const size_t bs = 4 * 1024;
+template <class T> using Alloc = short_alloc<T, bs>;
+template <class T> using Vector = std::vector<T, Alloc<T>>;
+
+template <class StrT>
+struct string_pair
+{
+    StrT first;
+    StrT second;
+
+    string_pair() = default;
+    string_pair(StrT f) : first(std::move(f)) {}
+    string_pair(StrT f, StrT s)
+        : first(std::move(f)), second(std::move(s)) {}
+    template <size_t N>
+        string_pair(const char (&s)[N]) : first(s, N-1) {}
+
+    size_t size() const {return first.size() + second.size();}
+    StrT full() const {return first + second;}
+    StrT move_full() {return std::move(first) + std::move(second);}
+};
+
+struct Db
+{
+#if UPSTREAM_CODE
+    typedef std::basic_string<char, std::char_traits<char>,
+                              malloc_alloc<char>> String;
+#else
+    typedef std::basic_string<char, std::char_traits<char> > String;
+#endif
+    typedef Vector<string_pair<String>> sub_type;
+    typedef Vector<sub_type> template_param_type;
+    sub_type names;
+    template_param_type subs;
+    Vector<template_param_type> template_param;
+    unsigned cv;
+    unsigned ref;
+    unsigned encoding_depth;
+    bool parsed_ctor_dtor_cv;
+    bool tag_templates;
+    bool fix_forward_references;
+    bool try_to_parse_template_args;
+
+    template <size_t N>
+    Db(arena<N>& ar) :
+        names(ar),
+        subs(0, names, ar),
+        template_param(0, subs, ar)
+    {}
+};
+
+#if UPSTREAM_CODE
+extern "C"
+__attribute__ ((__visibility__("default")))
+char*
+__cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status)
+{
+    if (mangled_name == nullptr || (buf != nullptr && n == nullptr))
+    {
+        if (status)
+            *status = invalid_args;
+        return nullptr;
+    }
+    size_t internal_size = buf != nullptr ? *n : 0;
+    arena<bs> a;
+    Db db(a);
+    db.cv = 0;
+    db.ref = 0;
+    db.encoding_depth = 0;
+    db.parsed_ctor_dtor_cv = false;
+    db.tag_templates = true;
+    db.template_param.emplace_back(a);
+    db.fix_forward_references = false;
+    db.try_to_parse_template_args = true;
+    int internal_status = success;
+    size_t len = std::strlen(mangled_name);
+    demangle(mangled_name, mangled_name + len, db,
+             internal_status);
+    if (internal_status == success && db.fix_forward_references &&
+           !db.template_param.empty() && !db.template_param.front().empty())
+    {
+        db.fix_forward_references = false;
+        db.tag_templates = false;
+        db.names.clear();
+        db.subs.clear();
+        demangle(mangled_name, mangled_name + len, db, internal_status);
+        if (db.fix_forward_references)
+            internal_status = invalid_mangled_name;
+    }
+    if (internal_status == success)
+    {
+        size_t sz = db.names.back().size() + 1;
+        if (sz > internal_size)
+        {
+            char* newbuf = static_cast<char*>(std::realloc(buf, sz));
+            if (newbuf == nullptr)
+            {
+                internal_status = memory_alloc_failure;
+                buf = nullptr;
+            }
+            else
+            {
+                buf = newbuf;
+                if (n != nullptr)
+                    *n = sz;
+            }
+        }
+        if (buf != nullptr)
+        {
+            db.names.back().first += db.names.back().second;
+            std::memcpy(buf, db.names.back().first.data(), sz-1);
+            buf[sz-1] = char(0);
+        }
+    }
+    else
+        buf = nullptr;
+    if (status)
+        *status = internal_status;
+    return buf;
+}
+#endif
+
+}  // namespace mcld
diff --git a/include/mcld/Support/Demangle.h b/include/mcld/Support/Demangle.h
new file mode 100644
index 0000000..b6f7412
--- /dev/null
+++ b/include/mcld/Support/Demangle.h
@@ -0,0 +1,22 @@
+//===- Demangle.h ---------------------------------------------------------===//
+//
+//                     The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MCLD_SUPPORT_DEMANGLE_H
+#define MCLD_SUPPORT_DEMANGLE_H
+
+#include <string>
+
+namespace mcld {
+
+std::string demangleName(const std::string& mangled_name);
+
+bool isCtorOrDtor(const char* pName, size_t pLength);
+
+} // namespace mcld
+
+#endif
diff --git a/include/mcld/Support/FileOutputBuffer.h b/include/mcld/Support/FileOutputBuffer.h
index 94cf640..6b48e14 100644
--- a/include/mcld/Support/FileOutputBuffer.h
+++ b/include/mcld/Support/FileOutputBuffer.h
@@ -10,11 +10,10 @@
 #define MCLD_SUPPORT_FILEOUTPUTBUFFER_H
 
 #include <mcld/Support/MemoryRegion.h>
-#include <llvm/ADT/OwningPtr.h>
 #include <llvm/ADT/StringRef.h>
 #include <llvm/Support/DataTypes.h>
 #include <llvm/Support/FileSystem.h>
-#include <llvm/Support/system_error.h>
+#include <system_error>
 
 namespace mcld {
 
@@ -27,9 +26,9 @@
   /// Factory method to create an OutputBuffer object which manages a read/write
   /// buffer of the specified size. When committed, the buffer will be written
   /// to the file at the specified path.
-  static llvm::error_code create(FileHandle& pFileHandle,
-                                 size_t pSize,
-                                 llvm::OwningPtr<FileOutputBuffer>& pResult);
+  static std::error_code create(FileHandle& pFileHandle,
+                                size_t pSize,
+                                std::unique_ptr<FileOutputBuffer>& pResult);
 
   /// Returns a pointer to the start of the buffer.
   uint8_t* getBufferStart() {
@@ -60,7 +59,7 @@
   FileOutputBuffer(llvm::sys::fs::mapped_file_region* pRegion,
                    FileHandle& pFileHandle);
 
-  llvm::OwningPtr<llvm::sys::fs::mapped_file_region> m_pRegion;
+  std::unique_ptr<llvm::sys::fs::mapped_file_region> m_pRegion;
   FileHandle& m_FileHandle;
 };
 
diff --git a/include/mcld/Support/MemoryArea.h b/include/mcld/Support/MemoryArea.h
index 2fef506..570e293 100644
--- a/include/mcld/Support/MemoryArea.h
+++ b/include/mcld/Support/MemoryArea.h
@@ -11,7 +11,6 @@
 
 #include <mcld/ADT/Uncopyable.h>
 
-#include <llvm/ADT/OwningPtr.h>
 #include <llvm/ADT/StringRef.h>
 #include <llvm/Support/MemoryBuffer.h>
 
diff --git a/include/mcld/Target/GNULDBackend.h b/include/mcld/Target/GNULDBackend.h
index 15337f6..351111d 100644
--- a/include/mcld/Target/GNULDBackend.h
+++ b/include/mcld/Target/GNULDBackend.h
@@ -19,6 +19,8 @@
 
 #include <llvm/Support/ELF.h>
 
+#include <cstdint>
+
 namespace mcld {
 
 class Module;
@@ -258,8 +260,8 @@
                          bool pSymHasPLT,
                          bool isAbsReloc) const;
 
-  /// isSymbolPreemtible - whether the symbol can be preemted by other
-  /// link unit
+  /// isSymbolPreemptible - whether the symbol can be preemted by other link
+  /// units
   /// @ref Google gold linker, symtab.h:551
   bool isSymbolPreemptible(const ResolveInfo& pSym) const;
 
@@ -309,9 +311,13 @@
   /// getStubFactory
   StubFactory*         getStubFactory()     { return m_pStubFactory; }
 
-  /// maxBranchOffset - return the max (forward) branch offset of the backend.
+  /// maxFwdBranchOffset - return the max forward branch offset of the backend.
   /// Target can override this function if needed.
-  virtual uint64_t maxBranchOffset() { return (uint64_t)-1; }
+  virtual int64_t maxFwdBranchOffset() { return INT64_MAX; }
+
+  /// maxBwdBranchOffset - return the max backward branch offset of the backend.
+  /// Target can override this function if needed.
+  virtual int64_t maxBwdBranchOffset() { return 0; }
 
   /// checkAndSetHasTextRel - check pSection flag to set HasTextRel
   void checkAndSetHasTextRel(const LDSection& pSection);
@@ -330,6 +336,10 @@
   /// attribute - the attribute section data.
   const ELFAttribute& attribute() const { return *m_pAttribute; }
 
+  /// mayHaveUnsafeFunctionPointerAccess - check if the section may have unsafe
+  /// function pointer access
+  bool mayHaveUnsafeFunctionPointerAccess(const LDSection& pSection) const;
+
 protected:
   /// getRelEntrySize - the size in BYTE of rel type relocation
   virtual size_t getRelEntrySize() = 0;
diff --git a/include/mcld/Target/TargetLDBackend.h b/include/mcld/Target/TargetLDBackend.h
index 29fb395..a1a5f1c 100644
--- a/include/mcld/Target/TargetLDBackend.h
+++ b/include/mcld/Target/TargetLDBackend.h
@@ -35,6 +35,7 @@
 class ObjectReader;
 class ObjectWriter;
 class Relocator;
+class ResolveInfo;
 class SectionData;
 class StubFactory;
 
@@ -62,6 +63,7 @@
   virtual bool initRelocator() = 0;
 
   virtual Relocator* getRelocator() = 0;
+  virtual const Relocator* getRelocator() const = 0;
 
   // -----  format dependent  ----- //
   virtual ArchiveReader* createArchiveReader(Module&) = 0;
@@ -167,6 +169,15 @@
   /// entry in the middle
   virtual void createAndSizeEhFrameHdr(Module& pModule) = 0;
 
+  /// isSymbolPreemptible - whether the symbol can be preemted by other link
+  /// units
+  virtual bool isSymbolPreemptible(const ResolveInfo& pSym) const = 0;
+
+  /// mayHaveUnsafeFunctionPointerAccess - check if the section may have unsafe
+  /// function pointer access
+  virtual bool mayHaveUnsafeFunctionPointerAccess(const LDSection& pSection)
+      const = 0;
+
 protected:
   const LinkerConfig& config() const { return m_Config; }
 
diff --git a/lib/CodeGen/MCLDTargetMachine.cpp b/lib/CodeGen/MCLDTargetMachine.cpp
index e1d9a0e..7749748 100644
--- a/lib/CodeGen/MCLDTargetMachine.cpp
+++ b/lib/CodeGen/MCLDTargetMachine.cpp
@@ -15,7 +15,6 @@
 #include <mcld/Support/ToolOutputFile.h>
 #include <mcld/Target/TargetLDBackend.h>
 
-#include <llvm/ADT/OwningPtr.h>
 #include <llvm/Analysis/Passes.h>
 #include <llvm/CodeGen/AsmPrinter.h>
 #include <llvm/CodeGen/MachineFunctionAnalysis.h>
@@ -127,7 +126,7 @@
     // FALLTHROUGH
   case llvm::ExceptionHandling::DwarfCFI:
   case llvm::ExceptionHandling::ARM:
-  case llvm::ExceptionHandling::Win64:
+  case llvm::ExceptionHandling::WinEH:
     PM.add(createDwarfEHPass(TM));
     break;
   case llvm::ExceptionHandling::None:
@@ -300,7 +299,7 @@
 
 
   // now, we have MCCodeEmitter and MCAsmBackend, we can create AsmStreamer.
-  OwningPtr<MCStreamer> AsmStreamer(
+  std::unique_ptr<MCStreamer> AsmStreamer(
     m_pLLVMTarget->createAsmStreamer(*Context, pOutput,
                                      getVerboseAsm(getTM()),
                                      getTM().Options.MCOptions.MCUseDwarfDirectory,
@@ -314,7 +313,7 @@
   if (funcPass == 0)
     return true;
   // If successful, createAsmPrinter took ownership of AsmStreamer
-  AsmStreamer.take();
+  AsmStreamer.release();
   pPM.add(funcPass);
   return false;
 }
@@ -338,7 +337,7 @@
     return true;
 
   // now, we have MCCodeEmitter and MCAsmBackend, we can create AsmStreamer.
-  OwningPtr<MCStreamer> AsmStreamer(m_pLLVMTarget->createMCObjectStreamer(
+  std::unique_ptr<MCStreamer> AsmStreamer(m_pLLVMTarget->createMCObjectStreamer(
     m_Triple, *Context, *MAB, pOutput, MCE, STI,
     getTM().Options.MCOptions.MCRelaxAll, getTM().Options.MCOptions.MCNoExecStack));
 
@@ -348,7 +347,7 @@
   if (funcPass == 0)
     return true;
   // If successful, createAsmPrinter took ownership of AsmStreamer
-  AsmStreamer.take();
+  AsmStreamer.release();
   pPM.add(funcPass);
   return false;
 }
diff --git a/lib/Core/GeneralOptions.cpp b/lib/Core/GeneralOptions.cpp
index 7f9b81c..f6e86b9 100644
--- a/lib/Core/GeneralOptions.cpp
+++ b/lib/Core/GeneralOptions.cpp
@@ -9,6 +9,7 @@
 #include <mcld/GeneralOptions.h>
 #include <mcld/MC/Input.h>
 #include <mcld/MC/ZOption.h>
+#include <cassert>
 
 using namespace mcld;
 
@@ -54,7 +55,11 @@
     m_bNoStdlib(false),
     m_bWarnMismatch(true),
     m_bGCSections(false),
+    m_bPrintGCSections(false),
     m_bGenUnwindInfo(true),
+    m_bPrintICFSections(false),
+    m_ICF(ICF_None),
+    m_ICFIterations(0) ,
     m_GPSize(8),
     m_StripSymbols(KeepAllSymbols),
     m_HashStyle(SystemV) {
@@ -145,3 +150,26 @@
       break;
   }
 }
+
+bool GeneralOptions::isInExcludeLIBS(const Input& pInput) const
+{
+  assert(pInput.type() == Input::Archive);
+
+  if (m_ExcludeLIBS.empty()) {
+    return false;
+  }
+
+  // Specifying "--exclude-libs ALL" excludes symbols in all archive libraries
+  // from automatic export.
+  if (m_ExcludeLIBS.count("ALL") != 0) {
+    return true;
+  }
+
+  std::string name(pInput.name());
+  name.append(".a");
+  if (m_ExcludeLIBS.count(name) != 0) {
+    return true;
+  }
+
+  return false;
+}
diff --git a/lib/Core/IRBuilder.cpp b/lib/Core/IRBuilder.cpp
index 080a122..bc44990 100644
--- a/lib/Core/IRBuilder.cpp
+++ b/lib/Core/IRBuilder.cpp
@@ -62,8 +62,12 @@
   case llvm::ELF::SHT_INIT_ARRAY:
   case llvm::ELF::SHT_FINI_ARRAY:
   case llvm::ELF::SHT_PREINIT_ARRAY:
-  case llvm::ELF::SHT_PROGBITS:
-    return LDFileFormat::Regular;
+  case llvm::ELF::SHT_PROGBITS: {
+    if ((pFlag & llvm::ELF::SHF_EXECINSTR) != 0)
+      return LDFileFormat::TEXT;
+    else
+      return LDFileFormat::DATA;
+  }
   case llvm::ELF::SHT_SYMTAB:
   case llvm::ELF::SHT_DYNSYM:
   case llvm::ELF::SHT_STRTAB:
@@ -423,6 +427,13 @@
       name = renameSym.getEntry()->value();
   }
 
+  // Fix up the visibility if object has no export set.
+  if (pInput.noExport() && (pDesc != ResolveInfo::Undefined)) {
+    if ((pVis == ResolveInfo::Default) || (pVis == ResolveInfo::Protected)) {
+      pVis = ResolveInfo::Hidden;
+    }
+  }
+
   switch (pInput.type()) {
     case Input::Object: {
 
diff --git a/lib/Core/Linker.cpp b/lib/Core/Linker.cpp
index 464f039..c8638a7 100644
--- a/lib/Core/Linker.cpp
+++ b/lib/Core/Linker.cpp
@@ -28,8 +28,6 @@
 #include <mcld/Fragment/Relocation.h>
 #include <mcld/Fragment/FragmentRef.h>
 
-#include <llvm/ADT/OwningPtr.h>
-
 #include <cassert>
 
 using namespace mcld;
@@ -96,7 +94,12 @@
   if (!Diagnose())
     return false;
 
-  // 4. - normalize the input tree
+  // 4.a - add undefined symbols
+  //   before reading the inputs, we should add undefined symbols set by -u to
+  //   ensure that correspoding objects (e.g. in an archive) will be included
+  m_pObjLinker->addUndefinedSymbols();
+
+  // 4.b - normalize the input tree
   //   read out sections and symbol/string tables (from the files) and
   //   set them in Module. When reading out the symbol, resolve their symbols
   //   immediately and set their ResolveInfo (i.e., Symbol Resolution).
@@ -204,7 +207,6 @@
   assert(NULL != m_pConfig && NULL != m_pObjLinker);
 
   // 10. - add standard symbols, target-dependent symbols and script symbols
-  // m_pObjLinker->addUndefSymbols();
   if (!m_pObjLinker->addStandardSymbols() ||
       !m_pObjLinker->addTargetSymbols() ||
       !m_pObjLinker->addScriptSymbols())
@@ -280,7 +282,7 @@
     return false;
   }
 
-  llvm::OwningPtr<FileOutputBuffer> output;
+  std::unique_ptr<FileOutputBuffer> output;
   FileOutputBuffer::create(file,
                            m_pObjLinker->getWriter()->getOutputSize(pModule),
                            output);
@@ -295,7 +297,7 @@
   FileHandle file;
   file.delegate(pFileDescriptor);
 
-  llvm::OwningPtr<FileOutputBuffer> output;
+  std::unique_ptr<FileOutputBuffer> output;
   FileOutputBuffer::create(file,
                            m_pObjLinker->getWriter()->getOutputSize(pModule),
                            output);
diff --git a/lib/LD/BranchIslandFactory.cpp b/lib/LD/BranchIslandFactory.cpp
index 116f075..fcaa2eb 100644
--- a/lib/LD/BranchIslandFactory.cpp
+++ b/lib/LD/BranchIslandFactory.cpp
@@ -19,14 +19,16 @@
 //===----------------------------------------------------------------------===//
 
 /// ctor
-/// @param pMaxBranchRange - the max branch range of the target backend
-/// @param pMaxIslandSize - a predifned value (1KB here) to decide the max
-///                         size of the island
-BranchIslandFactory::BranchIslandFactory(uint64_t pMaxBranchRange,
-                                         uint64_t pMaxIslandSize)
- : GCFactory<BranchIsland, 0>(1u), // magic number
-   m_MaxBranchRange(pMaxBranchRange - pMaxIslandSize),
-   m_MaxIslandSize(pMaxIslandSize)
+/// @param pMaxFwdBranchRange - the max forward branch range of the target
+/// @param pMaxBwdBranchRange - the max backward branch range of the target
+/// @param pMaxIslandSize - the predefined value for the max size of a island
+BranchIslandFactory::BranchIslandFactory(int64_t pMaxFwdBranchRange,
+                                         int64_t pMaxBwdBranchRange,
+                                         size_t pMaxIslandSize)
+    : GCFactory<BranchIsland, 0>(1u), // magic number
+      m_MaxFwdBranchRange(pMaxFwdBranchRange - pMaxIslandSize),
+      m_MaxBwdBranchRange(pMaxBwdBranchRange + pMaxIslandSize),
+      m_MaxIslandSize(pMaxIslandSize)
 {
 }
 
@@ -38,11 +40,11 @@
 /// @param pSectionData - the SectionData holds fragments need to be grouped
 void BranchIslandFactory::group(Module& pModule)
 {
-  /* Currently only support relaxing .text section! */
+  /* FIXME: Currently only support relaxing .text section! */
   LDSection* text = pModule.getSection(".text");
   if (text != NULL && text->hasSectionData()) {
     SectionData& sd = *text->getSectionData();
-    uint64_t group_end = m_MaxBranchRange - m_MaxIslandSize;
+    uint64_t group_end = m_MaxFwdBranchRange;
     for (SectionData::iterator it = sd.begin(), ie = sd.end(); it != ie; ++it) {
       if ((*it).getOffset() + (*it).size() > group_end) {
         Fragment* frag = (*it).getPrevNode();
@@ -51,11 +53,11 @@
         }
         if (frag != NULL) {
           produce(*frag);
-          group_end = (*it).getOffset() + m_MaxBranchRange - m_MaxIslandSize;
+          group_end = (*it).getOffset() + m_MaxFwdBranchRange;
         }
       }
     }
-    if (find(sd.back()) == NULL)
+    if (getIslands(sd.back()).first == NULL)
       produce(sd.back());
   }
 }
@@ -71,17 +73,29 @@
   return island;
 }
 
-/// find - find a island for the given fragment
-/// @param pFragment - the fragment needs a branch isladn
-BranchIsland* BranchIslandFactory::find(const Fragment& pFragment)
+/// getIsland - find fwd and bwd islands for the fragment
+/// @param pFragment - the fragment needs a branch island
+std::pair<BranchIsland*, BranchIsland*>
+BranchIslandFactory::getIslands(const Fragment& pFragment)
 {
-  // Currently we always find the island in a forward direction.
-  // TODO: If we can search backward, then we may reduce the number of stubs.
-  for (iterator it = begin(), ie = end(); it != ie; ++it) {
+  BranchIsland* fwd = NULL;
+  BranchIsland* bwd = NULL;
+  for (iterator it = begin(), ie = end(), prev = ie; it != ie;
+       prev = it, ++it) {
     if ((pFragment.getOffset() < (*it).offset()) &&
-        ((pFragment.getOffset() + m_MaxBranchRange) >= (*it).offset()))
-      return &(*it);
-  }
-  return NULL;
-}
+        ((pFragment.getOffset() + m_MaxFwdBranchRange) >= (*it).offset())) {
 
+      fwd = &*it;
+
+      if (prev != ie) {
+        int64_t bwd_off = (int64_t)pFragment.getOffset() + m_MaxBwdBranchRange;
+        if ((pFragment.getOffset() > (*prev).offset()) &&
+            (bwd_off <= (*prev).offset())) {
+          bwd = &*prev;
+        }
+      }
+      break;
+    }
+  }
+  return std::make_pair(fwd, bwd);
+}
diff --git a/lib/LD/DiagnosticInfos.cpp b/lib/LD/DiagnosticInfos.cpp
index 943b046..aed389a 100644
--- a/lib/LD/DiagnosticInfos.cpp
+++ b/lib/LD/DiagnosticInfos.cpp
@@ -141,18 +141,17 @@
           else
             severity = DiagnosticEngine::Ignore;
           break;
-        case LinkerConfig::Exec:
-          if (m_Config.options().isNoUndefined())
-            severity = DiagnosticEngine::Error;
-          else
-            severity = DiagnosticEngine::Ignore;
-          break;
         default:
           severity = DiagnosticEngine::Error;
           break;
       }
       break;
     }
+    case diag::debug_print_gc_sections: {
+      if (!m_Config.options().getPrintGCSections())
+        severity = DiagnosticEngine::Ignore;
+      break;
+    }
     default:
       break;
   } // end of switch
diff --git a/lib/LD/ELFBinaryReader.cpp b/lib/LD/ELFBinaryReader.cpp
index ee537c2..c72fa58 100644
--- a/lib/LD/ELFBinaryReader.cpp
+++ b/lib/LD/ELFBinaryReader.cpp
@@ -52,7 +52,7 @@
   LDSection* data_sect =
     m_Builder.CreateELFHeader(pInput,
                               ".data",
-                              LDFileFormat::Regular,
+                              LDFileFormat::DATA,
                               llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC,
                               0x1);
 
diff --git a/lib/LD/ELFDynObjReader.cpp b/lib/LD/ELFDynObjReader.cpp
index ebeba63..94eef58 100644
--- a/lib/LD/ELFDynObjReader.cpp
+++ b/lib/LD/ELFDynObjReader.cpp
@@ -17,7 +17,6 @@
 
 #include <llvm/ADT/StringRef.h>
 #include <llvm/ADT/Twine.h>
-#include <llvm/ADT/OwningPtr.h>
 #include <llvm/Support/ErrorHandling.h>
 
 #include <string>
diff --git a/lib/LD/ELFFileFormat.cpp b/lib/LD/ELFFileFormat.cpp
index 551a60d..318e595 100644
--- a/lib/LD/ELFFileFormat.cpp
+++ b/lib/LD/ELFFileFormat.cpp
@@ -67,7 +67,7 @@
 void ELFFileFormat::initStdSections(ObjectBuilder& pBuilder, unsigned int pBitClass)
 {
   f_pTextSection     = pBuilder.CreateSection(".text",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::TEXT,
                                               llvm::ELF::SHT_PROGBITS,
                                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
                                               0x1);
@@ -76,7 +76,7 @@
                                               llvm::ELF::SHT_NULL,
                                               0x0);
   f_pReadOnlySection = pBuilder.CreateSection(".rodata",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::TEXT,
                                               llvm::ELF::SHT_PROGBITS,
                                               llvm::ELF::SHF_ALLOC,
                                               0x1);
@@ -92,12 +92,12 @@
                                               0x0,
                                               0x1);
   f_pDataSection     = pBuilder.CreateSection(".data",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::DATA,
                                               llvm::ELF::SHT_PROGBITS,
                                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
                                               0x1);
   f_pData1           = pBuilder.CreateSection(".data1",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::DATA,
                                               llvm::ELF::SHT_PROGBITS,
                                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
                                               0x1);
@@ -107,22 +107,22 @@
                                               0x0,
                                               0x1);
   f_pInit            = pBuilder.CreateSection(".init",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::TEXT,
                                               llvm::ELF::SHT_PROGBITS,
                                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
                                               0x1);
   f_pInitArray       = pBuilder.CreateSection(".init_array",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::DATA,
                                               llvm::ELF::SHT_INIT_ARRAY,
                                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
                                               0x1);
   f_pFini            = pBuilder.CreateSection(".fini",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::TEXT,
                                               llvm::ELF::SHT_PROGBITS,
                                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
                                               0x1);
   f_pFiniArray       = pBuilder.CreateSection(".fini_array",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::DATA,
                                               llvm::ELF::SHT_FINI_ARRAY,
                                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
                                               0x1);
@@ -132,14 +132,14 @@
                                               0x0,
                                               0x1);
   f_pPreInitArray    = pBuilder.CreateSection(".preinit_array",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::DATA,
                                               llvm::ELF::SHT_PREINIT_ARRAY,
                                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
                                               0x1);
   // the definition of SHF_XXX attributes of rodata in Linux Standard Base
   // conflicts with System V standard. We follow System V standard.
   f_pROData1         = pBuilder.CreateSection(".rodata1",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::TEXT,
                                               llvm::ELF::SHT_PROGBITS,
                                               llvm::ELF::SHF_ALLOC,
                                               0x1);
@@ -170,7 +170,7 @@
                                               llvm::ELF::SHF_TLS,
                                               0x1);
   f_pTData           = pBuilder.CreateSection(".tdata",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::DATA,
                                               llvm::ELF::SHT_PROGBITS,
                                               llvm::ELF::SHF_ALLOC |
                                               llvm::ELF::SHF_WRITE |
@@ -179,17 +179,17 @@
 
   /// @ref 10.3.1.2, ISO/IEC 23360, Part 1:2010(E), p. 24.
   f_pCtors           = pBuilder.CreateSection(".ctors",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::DATA,
                                               llvm::ELF::SHT_PROGBITS,
                                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
                                               0x1);
   f_pDataRelRo       = pBuilder.CreateSection(".data.rel.ro",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::DATA,
                                               llvm::ELF::SHT_PROGBITS,
                                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
                                               0x1);
   f_pDtors           = pBuilder.CreateSection(".dtors",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::DATA,
                                               llvm::ELF::SHT_PROGBITS,
                                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
                                               0x1);
@@ -219,7 +219,7 @@
                                               llvm::ELF::SHF_ALLOC,
                                               0x1);
   f_pJCR             = pBuilder.CreateSection(".jcr",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::DATA,
                                               llvm::ELF::SHT_PROGBITS,
                                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
                                               0x1);
@@ -241,7 +241,7 @@
 
   /// @ref GCC convention, see http://www.airs.com/blog/archives/189
   f_pDataRelRoLocal  = pBuilder.CreateSection(".data.rel.ro.local",
-                                              LDFileFormat::Regular,
+                                              LDFileFormat::DATA,
                                               llvm::ELF::SHT_PROGBITS,
                                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
                                               0x1);
diff --git a/lib/LD/ELFObjectReader.cpp b/lib/LD/ELFObjectReader.cpp
index a34739a..a0ece0f 100644
--- a/lib/LD/ELFObjectReader.cpp
+++ b/lib/LD/ELFObjectReader.cpp
@@ -170,7 +170,10 @@
                 fatal(diag::err_cannot_read_section) << (*section)->name();
             }
           } else {
-            (*section)->setKind(LDFileFormat::Regular);
+            if (((*section)->flag() & llvm::ELF::SHF_EXECINSTR) != 0)
+              (*section)->setKind(LDFileFormat::TEXT);
+            else
+              (*section)->setKind(LDFileFormat::DATA);
             SectionData* sd = IRBuilder::CreateSectionData(**section);
             if (!m_pELFReader->readRegularSection(pInput, *sd))
               fatal(diag::err_cannot_read_section) << (*section)->name();
@@ -199,7 +202,8 @@
       // FIXME: support GCCExceptTable Kind
       case LDFileFormat::GCCExceptTable:
       /** Fall through **/
-      case LDFileFormat::Regular:
+      case LDFileFormat::TEXT:
+      case LDFileFormat::DATA:
       case LDFileFormat::Note:
       case LDFileFormat::MetaData: {
         SectionData* sd = IRBuilder::CreateSectionData(**section);
diff --git a/lib/LD/ELFObjectWriter.cpp b/lib/LD/ELFObjectWriter.cpp
index dca6936..c90efdf 100644
--- a/lib/LD/ELFObjectWriter.cpp
+++ b/lib/LD/ELFObjectWriter.cpp
@@ -29,8 +29,8 @@
 #include <mcld/LD/ELFFileFormat.h>
 #include <mcld/Target/GNUInfo.h>
 
+#include <llvm/Support/Errc.h>
 #include <llvm/Support/ErrorHandling.h>
-#include <llvm/Support/system_error.h>
 #include <llvm/Support/ELF.h>
 #include <llvm/Support/Casting.h>
 
@@ -61,7 +61,8 @@
     if (section->getSectionData() == NULL)
       return;
     // Fall through
-  case LDFileFormat::Regular:
+  case LDFileFormat::TEXT:
+  case LDFileFormat::DATA:
   case LDFileFormat::Relocation:
   case LDFileFormat::Target:
   case LDFileFormat::Debug:
@@ -94,7 +95,8 @@
   // Write out sections with data
   switch(section->kind()) {
   case LDFileFormat::GCCExceptTable:
-  case LDFileFormat::Regular:
+  case LDFileFormat::TEXT:
+  case LDFileFormat::DATA:
   case LDFileFormat::Debug:
   case LDFileFormat::Note:
     emitSectionData(*section, region);
@@ -116,8 +118,8 @@
   }
 }
 
-llvm::error_code ELFObjectWriter::writeObject(Module& pModule,
-                                              FileOutputBuffer& pOutput)
+std::error_code ELFObjectWriter::writeObject(Module& pModule,
+                                             FileOutputBuffer& pOutput)
 {
   bool is_dynobj = m_Config.codeGenType() == LinkerConfig::DynObj;
   bool is_exec = m_Config.codeGenType() == LinkerConfig::Exec;
@@ -180,10 +182,10 @@
       emitSectionHeader<64>(pModule, m_Config, pOutput);
     }
     else
-      return make_error_code(errc::not_supported);
+      return llvm::make_error_code(llvm::errc::function_not_supported);
   }
 
-  return llvm::make_error_code(llvm::errc::success);
+  return std::error_code();
 }
 
 // getOutputSize - count the final output size
diff --git a/lib/LD/GNUArchiveReader.cpp b/lib/LD/GNUArchiveReader.cpp
index 3dc95a5..4553bfb 100644
--- a/lib/LD/GNUArchiveReader.cpp
+++ b/lib/LD/GNUArchiveReader.cpp
@@ -401,6 +401,10 @@
 
     if (m_ELFObjectReader.isMyFormat(*member, doContinue)) {
       member->setType(Input::Object);
+      // Set this object as no export if the archive is in the exclude libs.
+      if (pArchive.getARFile().noExport()) {
+        member->setNoExport();
+      }
       pArchive.addObjectMember(pFileOffset, parent->lastPos);
       m_ELFObjectReader.readHeader(*member);
       m_ELFObjectReader.readSections(*member);
@@ -468,4 +472,3 @@
   }
   return true;
 }
-
diff --git a/lib/LD/GarbageCollection.cpp b/lib/LD/GarbageCollection.cpp
index 4ea40ac..44c9b5a 100644
--- a/lib/LD/GarbageCollection.cpp
+++ b/lib/LD/GarbageCollection.cpp
@@ -18,6 +18,7 @@
 #include <mcld/LinkerConfig.h>
 #include <mcld/LinkerScript.h>
 #include <mcld/Module.h>
+#include <mcld/Support/MsgHandling.h>
 #include <mcld/Target/TargetLDBackend.h>
 
 #include <llvm/Support/Casting.h>
@@ -63,7 +64,8 @@
 /// shouldProcessGC - check if the section kind is handled in GC
 static bool mayProcessGC(const LDSection& pSection)
 {
-  if (pSection.kind() == LDFileFormat::Regular ||
+  if (pSection.kind() == LDFileFormat::TEXT ||
+      pSection.kind() == LDFileFormat::DATA ||
       pSection.kind() == LDFileFormat::BSS ||
       pSection.kind() == LDFileFormat::GCCExceptTable)
     return true;
@@ -270,6 +272,24 @@
       pEntry.push_back(sect);
     }
   }
+
+  // symbols set by -u should not be garbage collected. Set them entries.
+  GeneralOptions::const_undef_sym_iterator usym;
+  GeneralOptions::const_undef_sym_iterator usymEnd =
+                                             m_Config.options().undef_sym_end();
+  for (usym = m_Config.options().undef_sym_begin(); usym != usymEnd; ++usym) {
+    LDSymbol* sym = m_Module.getNamePool().findSymbol(*usym);
+    assert(sym);
+    ResolveInfo* info = sym->resolveInfo();
+    assert(info);
+    if (!info->isDefine() || !sym->hasFragRef())
+      continue;
+    // only the symbols defined in the concerned sections can be entries
+    const LDSection* sect = &sym->fragRef()->frag()->getParent()->getSection();
+    if (!mayProcessGC(*sect))
+      continue;
+    pEntry.push_back(sect);
+  }
 }
 
 void GarbageCollection::findReferencedSections(SectionVecTy& pEntry)
@@ -323,8 +343,11 @@
       if (!mayProcessGC(*section))
         continue;
 
-      if (m_ReferencedSections.find(section) == m_ReferencedSections.end())
+      if (m_ReferencedSections.find(section) == m_ReferencedSections.end()) {
         section->setKind(LDFileFormat::Ignore);
+        debug(diag::debug_print_gc_sections) << section->name()
+                                             << (*obj)->name();
+      }
     }
   }
 
diff --git a/lib/LD/Relocator.cpp b/lib/LD/Relocator.cpp
index bf76573..fa3a94f 100644
--- a/lib/LD/Relocator.cpp
+++ b/lib/LD/Relocator.cpp
@@ -6,7 +6,6 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
-#include <mcld/Config/Config.h>
 #include <mcld/Fragment/Fragment.h>
 #include <mcld/LD/LDContext.h>
 #include <mcld/LD/LDSection.h>
@@ -14,40 +13,14 @@
 #include <mcld/LD/Relocator.h>
 #include <mcld/LD/ResolveInfo.h>
 #include <mcld/LD/SectionData.h>
+#include <mcld/Support/Demangle.h>
 #include <mcld/Support/MsgHandling.h>
 #include <mcld/Module.h>
-#ifdef HAVE_CXXABI_H
-#include <cxxabi.h>
-#endif
 #include <sstream>
 
 using namespace mcld;
 
 //===----------------------------------------------------------------------===//
-// Helper functions
-//===----------------------------------------------------------------------===//
-std::string demangleSymbol(const std::string& mangled_name) {
-#ifdef HAVE_CXXABI_H
-  // __cxa_demangle needs manually handle the memory release, so we wrap
-  // it into this helper function.
-  size_t output_leng;
-  int status;
-  char* buffer = abi::__cxa_demangle(mangled_name.c_str(), /*buffer=*/0,
-                                     &output_leng, &status);
-  if (status != 0) { // Failed
-    return mangled_name;
-  }
-  std::string demangled_name(buffer);
-  free(buffer);
-
-  return demangled_name;
-#else
-  return mangled_name;
-#endif
-}
-
-
-//===----------------------------------------------------------------------===//
 // Relocator
 //===----------------------------------------------------------------------===//
 Relocator::~Relocator()
@@ -87,8 +60,7 @@
   sect_name = sect_name.substr(sect_name.find('.', /*pos=*/1));  // Drop .rel(a) prefix
 
   std::string reloc_sym(pReloc.symInfo()->name());
-  if (reloc_sym.substr(0, 2) == "_Z")
-    reloc_sym = demangleSymbol(reloc_sym);
+  reloc_sym = demangleName(reloc_sym);
 
   std::stringstream ss;
   ss << "0x" << std::hex << undef_sym_pos;
@@ -119,8 +91,7 @@
     }
   }
 
-  if (caller_func_name.substr(0, 2) == "_Z")
-    caller_func_name = demangleSymbol(caller_func_name);
+  caller_func_name = demangleName(caller_func_name);
 
   fatal(diag::undefined_reference_text) << reloc_sym
                                         << pInput.path()
diff --git a/lib/LD/StaticResolver.cpp b/lib/LD/StaticResolver.cpp
index d7daf1d..3dad005 100644
--- a/lib/LD/StaticResolver.cpp
+++ b/lib/LD/StaticResolver.cpp
@@ -8,10 +8,9 @@
 //===----------------------------------------------------------------------===//
 #include <mcld/LD/StaticResolver.h>
 #include <mcld/LD/LDSymbol.h>
+#include <mcld/Support/Demangle.h>
 #include <mcld/Support/MsgHandling.h>
 
-#include <cxxabi.h>
-
 using namespace mcld;
 
 //==========================
@@ -171,9 +170,6 @@
       }
       /* Fall through */
       case MDEF: {       /* multiple definition error.  */
-        int status;
-        char* demangled_name = abi::__cxa_demangle(pNew.name(), NULL, NULL,
-                                                   &status);
         if (pOld.isDefine() && pNew.isDefine() &&
             pOld.isAbsolute() && pNew.isAbsolute() &&
             (pOld.desc() == pNew.desc() || pOld.desc() == ResolveInfo::NoType ||
@@ -183,21 +179,15 @@
             old->override(pNew);
             break;
           } else {
-            if (demangled_name != NULL) {
-              error(diag::multiple_absolute_definitions) << demangled_name
-                << pOld.outSymbol()->value() << pValue;
-            } else {
-              error(diag::multiple_absolute_definitions) << pNew.name()
-                << pOld.outSymbol()->value() << pValue;
-            }
+            error(diag::multiple_absolute_definitions)
+                << demangleName(pNew.name())
+                << pOld.outSymbol()->value()
+                << pValue;
             break;
           }
         }
-        if (demangled_name != NULL) {
-          error(diag::multiple_definitions) << demangled_name;
-        } else {
-          error(diag::multiple_definitions) << pNew.name();
-        }
+
+        error(diag::multiple_definitions) << demangleName(pNew.name());
         break;
       }
       case REFC: {       /* Mark indirect symbol referenced and then CYCLE.  */
diff --git a/lib/LD/StubFactory.cpp b/lib/LD/StubFactory.cpp
index 3d7c56a..52c372c 100644
--- a/lib/LD/StubFactory.cpp
+++ b/lib/LD/StubFactory.cpp
@@ -14,7 +14,6 @@
 #include <mcld/LD/ResolveInfo.h>
 #include <mcld/Fragment/Stub.h>
 #include <mcld/Fragment/Relocation.h>
-#include <mcld/Fragment/FragmentRef.h>
 
 #include <string>
 
@@ -43,67 +42,78 @@
                           BranchIslandFactory& pBRIslandFactory)
 {
   // find if there is a prototype stub for the input relocation
-  Stub* prototype = findPrototype(pReloc,
-                                  pReloc.place(),
-                                  pTargetSymValue);
-  if (NULL != prototype) {
-    // find the island for the input relocation
-    BranchIsland* island = pBRIslandFactory.find(*(pReloc.targetRef().frag()));
-    if (NULL == island) {
+  Stub* stub = NULL;
+  Stub* prototype = findPrototype(pReloc, pReloc.place(), pTargetSymValue);
+  if (prototype != NULL) {
+    const Fragment* frag = pReloc.targetRef().frag();
+    // find the islands for the input relocation
+    std::pair<BranchIsland*, BranchIsland*> islands =
+        pBRIslandFactory.getIslands(*frag);
+    if (islands.first == NULL) {
+      // early exit if we can not find the forward island.
       return NULL;
     }
 
-    // find if there is such a stub in the island already
-    Stub* stub = island->findStub(prototype, pReloc);
-    if (NULL != stub) {
+    // find if there is such a stub in the backward island first.
+    if (islands.second != NULL) {
+      stub = islands.second->findStub(prototype, pReloc);
+    }
+
+    if (stub != NULL) {
       // reset the branch target to the stub instead!
       pReloc.setSymInfo(stub->symInfo());
-    }
-    else {
-      // create a stub from the prototype
-      stub = prototype->clone();
+    } else {
+      // find if there is such a stub in the forward island.
+      stub = islands.first->findStub(prototype, pReloc);
+      if (stub != NULL) {
+        // reset the branch target to the stub instead!
+        pReloc.setSymInfo(stub->symInfo());
+      } else {
+        // create a stub from the prototype
+        stub = prototype->clone();
 
-      // build a name for stub symbol
-      std::string name("__");
-      name.append(pReloc.symInfo()->name());
-      name.append("_");
-      name.append(stub->name());
-      name.append("@");
-      name.append(island->name());
+        // build a name for stub symbol
+        std::string name("__");
+        name.append(pReloc.symInfo()->name())
+            .append("_")
+            .append(stub->name())
+            .append("@")
+            .append(islands.first->name());
 
-      // create LDSymbol for the stub
-      LDSymbol* symbol =
-        pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
-                               name,
-                               ResolveInfo::Function,
-                               ResolveInfo::Define,
-                               ResolveInfo::Local,
-                               stub->size(), // size
-                               stub->initSymValue(), // value
-                               FragmentRef::Create(*stub, stub->initSymValue()),
-                               ResolveInfo::Default);
-      stub->setSymInfo(symbol->resolveInfo());
+        // create LDSymbol for the stub
+        LDSymbol* symbol =
+            pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
+                name,
+                ResolveInfo::Function,
+                ResolveInfo::Define,
+                ResolveInfo::Local,
+                stub->size(), // size
+                stub->initSymValue(), // value
+                FragmentRef::Create(*stub, stub->initSymValue()),
+                ResolveInfo::Default);
+        stub->setSymInfo(symbol->resolveInfo());
 
-      // add relocations of this stub (i.e., set the branch target of the stub)
-      for (Stub::fixup_iterator it = stub->fixup_begin(),
+        // add relocations of this stub (i.e., set the branch target of the stub)
+        for (Stub::fixup_iterator it = stub->fixup_begin(),
              ie = stub->fixup_end(); it != ie; ++it) {
 
-        Relocation* reloc = Relocation::Create((*it)->type(),
+          Relocation* reloc =
+              Relocation::Create((*it)->type(),
                                  *(FragmentRef::Create(*stub, (*it)->offset())),
                                  (*it)->addend());
-        reloc->setSymInfo(pReloc.symInfo());
-        island->addRelocation(*reloc);
+          reloc->setSymInfo(pReloc.symInfo());
+          islands.first->addRelocation(*reloc);
+        }
+
+        // add stub to the forward branch island
+        islands.first->addStub(prototype, pReloc, *stub);
+
+        // reset the branch target of the input reloc to this stub instead!
+        pReloc.setSymInfo(stub->symInfo());
       }
-
-      // add stub to the branch island
-      island->addStub(prototype, pReloc, *stub);
-
-      // reset the branch target of the input reloc to this stub instead!
-      pReloc.setSymInfo(stub->symInfo());
-      return stub;
     }
   }
-  return NULL;
+  return stub;
 }
 
 /// findPrototype - find if there is a registered stub prototype for the given
@@ -119,4 +129,3 @@
   }
   return NULL;
 }
-
diff --git a/lib/MC/Input.cpp b/lib/MC/Input.cpp
index 2d948c2..26234fc 100644
--- a/lib/MC/Input.cpp
+++ b/lib/MC/Input.cpp
@@ -21,6 +21,7 @@
     m_Path(),
     m_pAttr(NULL),
     m_bNeeded(false),
+    m_bNoExport(false),
     m_fileOffset(0),
     m_pMemArea(NULL),
     m_pContext(NULL) {
@@ -32,6 +33,7 @@
     m_Path(),
     m_pAttr(const_cast<Attribute*>(pProxy.attr())),
     m_bNeeded(false),
+    m_bNoExport(false),
     m_fileOffset(0),
     m_pMemArea(NULL),
     m_pContext(NULL) {
@@ -46,6 +48,7 @@
     m_Path(pPath),
     m_pAttr(NULL),
     m_bNeeded(false),
+    m_bNoExport(false),
     m_fileOffset(pFileOffset),
     m_pMemArea(NULL),
     m_pContext(NULL) {
@@ -61,6 +64,7 @@
     m_Path(pPath),
     m_pAttr(const_cast<Attribute*>(pProxy.attr())),
     m_bNeeded(false),
+    m_bNoExport(false),
     m_fileOffset(pFileOffset),
     m_pMemArea(NULL),
     m_pContext(NULL) {
diff --git a/lib/Object/ObjectLinker.cpp b/lib/Object/ObjectLinker.cpp
index d4df036..dfc7f37 100644
--- a/lib/Object/ObjectLinker.cpp
+++ b/lib/Object/ObjectLinker.cpp
@@ -22,6 +22,7 @@
 #include <mcld/LD/GroupReader.h>
 #include <mcld/LD/BinaryReader.h>
 #include <mcld/LD/GarbageCollection.h>
+#include <mcld/LD/IdenticalCodeFolding.h>
 #include <mcld/LD/ObjectWriter.h>
 #include <mcld/LD/ResolveInfo.h>
 #include <mcld/LD/RelocData.h>
@@ -42,6 +43,7 @@
 
 #include <llvm/Support/Casting.h>
 #include <llvm/Support/Host.h>
+#include <system_error>
 
 using namespace llvm;
 using namespace mcld;
@@ -111,6 +113,37 @@
   return true;
 }
 
+void ObjectLinker::addUndefinedSymbols()
+{
+  // Add the symbol set by -u as an undefind global symbol into symbol pool
+  GeneralOptions::const_undef_sym_iterator usym;
+  GeneralOptions::const_undef_sym_iterator usymEnd =
+                                             m_Config.options().undef_sym_end();
+  for (usym = m_Config.options().undef_sym_begin(); usym != usymEnd; ++usym) {
+    Resolver::Result result;
+    m_pModule->getNamePool().insertSymbol(*usym, // name
+                                          false, // isDyn
+                                          ResolveInfo::NoType,
+                                          ResolveInfo::Undefined,
+                                          ResolveInfo::Global,
+                                          0x0, // size
+                                          0x0, // value
+                                          ResolveInfo::Default,
+                                          NULL,
+                                          result);
+
+    LDSymbol* output_sym = result.info->outSymbol();
+    bool has_output_sym = (NULL != output_sym);
+
+    // create the output symbol if it dose not have one
+    if (!result.existent || !has_output_sym) {
+      output_sym = LDSymbol::Create(*result.info);
+      result.info->setSymPtr(output_sym);
+      output_sym->setFragmentRef(FragmentRef::Null());
+    }
+  }
+}
+
 void ObjectLinker::normalize()
 {
   // -----  set up inputs  ----- //
@@ -165,6 +198,9 @@
     // is an archive
     else if (doContinue && getArchiveReader()->isMyFormat(**input, doContinue)) {
       (*input)->setType(Input::Archive);
+      if (m_Config.options().isInExcludeLIBS(**input)) {
+        (*input)->setNoExport();
+      }
       Archive archive(**input, m_pBuilder->getInputBuilder());
       getArchiveReader()->readArchive(m_Config, archive);
       if(archive.numOfObjectMember() > 0) {
@@ -236,6 +272,12 @@
     GarbageCollection GC(m_Config, m_LDBackend, *m_pModule);
     GC.run();
   }
+
+  // Identical code folding
+  if (m_Config.options().getICFMode() != GeneralOptions::ICF_None) {
+    IdenticalCodeFolding icf(m_Config, m_LDBackend, *m_pModule);
+    icf.foldIdenticalCode();
+  }
   return;
 }
 
@@ -267,6 +309,7 @@
     for (sect = (*obj)->context()->sectBegin(); sect != sectEnd; ++sect) {
       switch ((*sect)->kind()) {
         // Some *INPUT sections should not be merged.
+        case LDFileFormat::Folded:
         case LDFileFormat::Ignore:
         case LDFileFormat::Null:
         case LDFileFormat::NamePool:
@@ -278,7 +321,8 @@
           if (!(*sect)->hasRelocData())
             continue; // skip
 
-          if ((*sect)->getLink()->kind() == LDFileFormat::Ignore)
+          if ((*sect)->getLink()->kind() == LDFileFormat::Ignore ||
+              (*sect)->getLink()->kind() == LDFileFormat::Folded)
             (*sect)->setKind(LDFileFormat::Ignore);
           break;
         }
@@ -741,7 +785,7 @@
 /// emitOutput - emit the output file.
 bool ObjectLinker::emitOutput(FileOutputBuffer& pOutput)
 {
-  return llvm::errc::success == getWriter()->writeObject(*m_pModule, pOutput);
+  return std::error_code() == getWriter()->writeObject(*m_pModule, pOutput);
 }
 
 
diff --git a/lib/Object/SectionMap.cpp b/lib/Object/SectionMap.cpp
index 64c4a87..4453d42 100644
--- a/lib/Object/SectionMap.cpp
+++ b/lib/Object/SectionMap.cpp
@@ -46,7 +46,7 @@
     WildcardPattern::create(pName, WildcardPattern::SORT_NONE));
   m_Spec.m_pWildcardSections = sections;
 
-  m_pSection = LDSection::Create(pName, LDFileFormat::Regular, 0, 0);
+  m_pSection = LDSection::Create(pName, LDFileFormat::TEXT, 0, 0);
   SectionData* sd = SectionData::Create(*m_pSection);
   m_pSection->setSectionData(sd);
   new NullFragment(sd);
@@ -59,7 +59,7 @@
   m_Spec.m_pWildcardFile = pInputDesc.spec().m_pWildcardFile;
   m_Spec.m_pExcludeFiles = pInputDesc.spec().m_pExcludeFiles;
   m_Spec.m_pWildcardSections = pInputDesc.spec().m_pWildcardSections;
-  m_pSection = LDSection::Create("", LDFileFormat::Regular, 0, 0);
+  m_pSection = LDSection::Create("", LDFileFormat::TEXT, 0, 0);
   SectionData* sd = SectionData::Create(*m_pSection);
   m_pSection->setSectionData(sd);
   new NullFragment(sd);
@@ -85,7 +85,7 @@
   m_Epilog.m_pPhdrs = NULL;
   m_Epilog.m_pFillExp = NULL;
 
-  m_pSection = LDSection::Create(pName, LDFileFormat::Regular, 0, 0);
+  m_pSection = LDSection::Create(pName, LDFileFormat::TEXT, 0, 0);
   SectionData* sd = SectionData::Create(*m_pSection);
   m_pSection->setSectionData(sd);
 
@@ -98,7 +98,7 @@
     m_Epilog(pOutputDesc.epilog()),
     m_Order(UINT_MAX)
 {
-  m_pSection = LDSection::Create(m_Name, LDFileFormat::Regular, 0, 0);
+  m_pSection = LDSection::Create(m_Name, LDFileFormat::TEXT, 0, 0);
   SectionData* sd = SectionData::Create(*m_pSection);
   m_pSection->setSectionData(sd);
 
diff --git a/lib/Support/Demangle.cpp b/lib/Support/Demangle.cpp
new file mode 100644
index 0000000..6db5c34
--- /dev/null
+++ b/lib/Support/Demangle.cpp
@@ -0,0 +1,76 @@
+//===- Demangle.cpp -------------------------------------------------------===//
+//
+//                     The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Config/Config.h>
+#include <mcld/Support/CXADemangle.tcc>
+#include <mcld/Support/Demangle.h>
+
+#ifdef HAVE_CXXABI_H
+#include <cxxabi.h>
+#endif
+
+namespace mcld {
+
+std::string demangleName(const std::string& pName) {
+#ifdef HAVE_CXXABI_H
+  // Spoil names of symbols with C linkage, so use an heuristic approach to
+  // check if the name should be demangled.
+  if (pName.substr(0, 2) != "_Z")
+    return pName;
+  // __cxa_demangle needs manually handle the memory release, so we wrap
+  // it into this helper function.
+  size_t output_leng;
+  int status;
+  char* buffer = abi::__cxa_demangle(pName.c_str(), /*buffer=*/0,
+                                     &output_leng, &status);
+  if (status != 0) { // Failed
+    return pName;
+  }
+  std::string result(buffer);
+  free(buffer);
+
+  return result;
+#else
+  return pName;
+#endif
+}
+
+bool isCtorOrDtor(const char* pName, size_t pLength)
+{
+  arena<bs> a;
+  Db db(a);
+  db.cv = 0;
+  db.ref = 0;
+  db.encoding_depth = 0;
+  db.parsed_ctor_dtor_cv = false;
+  db.tag_templates = true;
+  db.template_param.emplace_back(a);
+  db.fix_forward_references = false;
+  db.try_to_parse_template_args = true;
+  int internal_status = success;
+  demangle(pName, pName + pLength, db, internal_status);
+  if (internal_status == success &&
+      db.fix_forward_references &&
+      !db.template_param.empty() &&
+      !db.template_param.front().empty()) {
+    db.fix_forward_references = false;
+    db.tag_templates = false;
+    db.names.clear();
+    db.subs.clear();
+    demangle(pName, pName + pLength, db, internal_status);
+    if (db.fix_forward_references)
+      internal_status = invalid_mangled_name;
+  }
+
+  if (internal_status != success) {
+    db.parsed_ctor_dtor_cv = false;
+  }
+  return db.parsed_ctor_dtor_cv;
+}
+
+} // namespace mcld
diff --git a/lib/Support/FileOutputBuffer.cpp b/lib/Support/FileOutputBuffer.cpp
index ed8c898..4887e6b 100644
--- a/lib/Support/FileOutputBuffer.cpp
+++ b/lib/Support/FileOutputBuffer.cpp
@@ -25,25 +25,25 @@
   m_pRegion.reset(0);
 }
 
-llvm::error_code FileOutputBuffer::create(FileHandle& pFileHandle,
-    size_t pSize, llvm::OwningPtr<FileOutputBuffer>& pResult)
+std::error_code FileOutputBuffer::create(FileHandle& pFileHandle,
+    size_t pSize, std::unique_ptr<FileOutputBuffer>& pResult)
 {
-  llvm::error_code EC;
-  llvm::OwningPtr<mapped_file_region> mapped_file(new mapped_file_region(
+  std::error_code ec;
+  std::unique_ptr<mapped_file_region> mapped_file(new mapped_file_region(
       pFileHandle.handler(),
       false,
       mapped_file_region::readwrite,
       pSize,
       0,
-      EC));
+      ec));
 
-  if (EC)
-    return EC;
+  if (ec)
+    return ec;
 
   pResult.reset(new FileOutputBuffer(mapped_file.get(), pFileHandle));
   if (pResult)
-    mapped_file.take();
-  return llvm::error_code::success();
+    mapped_file.release();
+  return std::error_code();
 }
 
 MemoryRegion FileOutputBuffer::request(size_t pOffset, size_t pLength)
diff --git a/lib/Support/MemoryArea.cpp b/lib/Support/MemoryArea.cpp
index 0c7f3c1..548ac72 100644
--- a/lib/Support/MemoryArea.cpp
+++ b/lib/Support/MemoryArea.cpp
@@ -8,9 +8,11 @@
 //===----------------------------------------------------------------------===//
 #include <mcld/Support/MemoryArea.h>
 #include <mcld/Support/MsgHandling.h>
-#include <llvm/Support/system_error.h>
+
+#include <llvm/Support/ErrorOr.h>
 
 #include <cassert>
+#include <system_error>
 
 using namespace mcld;
 
@@ -19,12 +21,13 @@
 //===--------------------------------------------------------------------===//
 MemoryArea::MemoryArea(llvm::StringRef pFilename)
 {
-  llvm::error_code ec =
-      llvm::MemoryBuffer::getFile(pFilename, m_pMemoryBuffer, /*FileSize*/ -1,
+  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer_or_error =
+      llvm::MemoryBuffer::getFile(pFilename, /*FileSize*/ -1,
                                   /*RequiresNullTerminator*/ false);
-  if (ec != llvm::errc::success) {
+  if (std::error_code ec = buffer_or_error.getError()) {
     fatal(diag::fatal_cannot_read_input) << pFilename.str();
   }
+  m_pMemoryBuffer = std::move(buffer_or_error.get());
 }
 
 MemoryArea::MemoryArea(const char* pMemBuffer, size_t pSize)
diff --git a/lib/Target/AArch64/AArch64LDBackend.cpp b/lib/Target/AArch64/AArch64LDBackend.cpp
index 09f6766..cf07428 100644
--- a/lib/Target/AArch64/AArch64LDBackend.cpp
+++ b/lib/Target/AArch64/AArch64LDBackend.cpp
@@ -152,6 +152,12 @@
   return true;
 }
 
+const Relocator* AArch64GNULDBackend::getRelocator() const
+{
+  assert(NULL != m_pRelocator);
+  return m_pRelocator;
+}
+
 Relocator* AArch64GNULDBackend::getRelocator()
 {
   assert(NULL != m_pRelocator);
diff --git a/lib/Target/AArch64/AArch64LDBackend.h b/lib/Target/AArch64/AArch64LDBackend.h
index c79bfa6..00e14fa 100644
--- a/lib/Target/AArch64/AArch64LDBackend.h
+++ b/lib/Target/AArch64/AArch64LDBackend.h
@@ -27,6 +27,10 @@
 class AArch64GNULDBackend : public GNULDBackend
 {
 public:
+  static const int64_t AARCH64_MAX_FWD_BRANCH_OFFSET = (((1 << 25) - 1) << 2);
+  static const int64_t AARCH64_MAX_BWD_BRANCH_OFFSET = (-((1 << 25) << 2));
+
+public:
   AArch64GNULDBackend(const LinkerConfig& pConfig, GNUInfo* pInfo);
   ~AArch64GNULDBackend();
 
@@ -41,9 +45,9 @@
   bool initRelocator();
 
   /// getRelocator - return relocator.
+  const Relocator* getRelocator() const;
   Relocator* getRelocator();
 
-
   /// doPreLayout - Backend can do any needed modification before layout
   void doPreLayout(IRBuilder& pBuilder);
 
@@ -110,9 +114,8 @@
 private:
   void defineGOTSymbol(IRBuilder& pBuilder);
 
-  /// maxBranchOffset
-  /// FIXME:
-  uint64_t maxBranchOffset() { return 0x0; }
+  int64_t maxFwdBranchOffset() { return AARCH64_MAX_FWD_BRANCH_OFFSET; }
+  int64_t maxBwdBranchOffset() { return AARCH64_MAX_BWD_BRANCH_OFFSET; }
 
   /// mayRelax - Backends should override this function if they need relaxation
   bool mayRelax() { return true; }
diff --git a/lib/Target/ARM/ARMELFAttributeData.cpp b/lib/Target/ARM/ARMELFAttributeData.cpp
index afab867..8656b7e 100644
--- a/lib/Target/ARM/ARMELFAttributeData.cpp
+++ b/lib/Target/ARM/ARMELFAttributeData.cpp
@@ -1073,3 +1073,21 @@
 
   return (buffer - pBuf);
 }
+
+bool ARMELFAttributeData::usingThumb() const
+{
+  int arch = m_Attrs[Tag_CPU_arch].getIntValue();
+  if ((arch == CPU_Arch_ARM_V6_M) || (arch == CPU_Arch_ARM_V6S_M))
+    return true;
+  if ((arch != CPU_Arch_ARM_V7) && (arch != CPU_Arch_ARM_V7E_M))
+    return false;
+
+  arch = m_Attrs[Tag_CPU_arch_profile].getIntValue();
+  return arch == Arch_Profile_Microcontroller;
+}
+
+bool ARMELFAttributeData::usingThumb2() const
+{
+  int arch = m_Attrs[Tag_CPU_arch].getIntValue();
+  return (arch == CPU_Arch_ARM_V6T2) || (arch == CPU_Arch_ARM_V7);
+}
diff --git a/lib/Target/ARM/ARMELFAttributeData.h b/lib/Target/ARM/ARMELFAttributeData.h
index c4128fa..1183b3d 100644
--- a/lib/Target/ARM/ARMELFAttributeData.h
+++ b/lib/Target/ARM/ARMELFAttributeData.h
@@ -180,6 +180,10 @@
 
   virtual size_t emit(char *pBuf) const;
 
+  virtual bool usingThumb() const;
+
+  virtual bool usingThumb2() const;
+
 private:
   /// GetAttributeValueType - obtain the value type of the indicated tag.
   static unsigned int GetAttributeValueType(TagType pTag);
diff --git a/lib/Target/ARM/ARMLDBackend.cpp b/lib/Target/ARM/ARMLDBackend.cpp
index e0ca782..2b30df8 100644
--- a/lib/Target/ARM/ARMLDBackend.cpp
+++ b/lib/Target/ARM/ARMLDBackend.cpp
@@ -17,13 +17,6 @@
 #include "THMToTHMStub.h"
 #include "THMToARMStub.h"
 
-#include <cstring>
-
-#include <llvm/ADT/Triple.h>
-#include <llvm/ADT/Twine.h>
-#include <llvm/Support/ELF.h>
-#include <llvm/Support/Casting.h>
-
 #include <mcld/IRBuilder.h>
 #include <mcld/LinkerConfig.h>
 #include <mcld/Fragment/FillFragment.h>
@@ -45,6 +38,14 @@
 #include <mcld/Target/GNUInfo.h>
 #include <mcld/Object/ObjectBuilder.h>
 
+#include <llvm/ADT/StringRef.h>
+#include <llvm/ADT/Triple.h>
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ELF.h>
+#include <llvm/Support/Casting.h>
+
+#include <cstring>
+
 using namespace mcld;
 
 //===----------------------------------------------------------------------===//
@@ -205,6 +206,12 @@
   return true;
 }
 
+const Relocator* ARMGNULDBackend::getRelocator() const
+{
+  assert(NULL != m_pRelocator);
+  return m_pRelocator;
+}
+
 Relocator* ARMGNULDBackend::getRelocator()
 {
   assert(NULL != m_pRelocator);
@@ -471,7 +478,8 @@
           // the reference
           const LDSection* target_sect =
                 &sym->outSymbol()->fragRef()->frag()->getParent()->getSection();
-          if (target_sect->kind() != LDFileFormat::Regular &&
+          if (target_sect->kind() != LDFileFormat::TEXT &&
+              target_sect->kind() != LDFileFormat::DATA &&
               target_sect->kind() != LDFileFormat::BSS)
             continue;
 
@@ -716,13 +724,35 @@
   if (NULL != getStubFactory()) {
     getStubFactory()->addPrototype(new ARMToARMStub(config().isCodeIndep()));
     getStubFactory()->addPrototype(new ARMToTHMStub(config().isCodeIndep()));
-    getStubFactory()->addPrototype(new THMToTHMStub(config().isCodeIndep()));
-    getStubFactory()->addPrototype(new THMToARMStub(config().isCodeIndep()));
+    getStubFactory()->addPrototype(
+        new THMToTHMStub(config().isCodeIndep(), m_pAttrData->usingThumb2()));
+    getStubFactory()->addPrototype(
+        new THMToARMStub(config().isCodeIndep(), m_pAttrData->usingThumb2()));
     return true;
   }
   return false;
 }
 
+/// maxFwdBranchOffset
+int64_t ARMGNULDBackend::maxFwdBranchOffset()
+{
+  if (m_pAttrData->usingThumb2()) {
+    return THM2_MAX_FWD_BRANCH_OFFSET;
+  } else {
+    return THM_MAX_FWD_BRANCH_OFFSET;
+  }
+}
+
+/// maxBwdBranchOffset
+int64_t ARMGNULDBackend::maxBwdBranchOffset()
+{
+  if (m_pAttrData->usingThumb2()) {
+    return THM2_MAX_BWD_BRANCH_OFFSET;
+  } else {
+    return THM_MAX_BWD_BRANCH_OFFSET;
+  }
+}
+
 /// doCreateProgramHdrs - backend can implement this function to create the
 /// target-dependent segments
 void ARMGNULDBackend::doCreateProgramHdrs(Module& pModule)
@@ -735,6 +765,19 @@
    }
 }
 
+/// mayHaveUnsafeFunctionPointerAccess - check if the section may have unsafe
+/// function pointer access
+bool
+ARMGNULDBackend::mayHaveUnsafeFunctionPointerAccess(const LDSection& pSection)
+    const
+{
+  llvm::StringRef name(pSection.name());
+  return !name.startswith(".ARM.exidx") &&
+         !name.startswith(".ARM.extab") &&
+         GNULDBackend::mayHaveUnsafeFunctionPointerAccess(pSection);
+}
+
+
 namespace mcld {
 
 //===----------------------------------------------------------------------===//
diff --git a/lib/Target/ARM/ARMLDBackend.h b/lib/Target/ARM/ARMLDBackend.h
index cae589d..14d3fde 100644
--- a/lib/Target/ARM/ARMLDBackend.h
+++ b/lib/Target/ARM/ARMLDBackend.h
@@ -55,9 +55,9 @@
   bool initRelocator();
 
   /// getRelocator - return relocator.
+  const Relocator* getRelocator() const;
   Relocator* getRelocator();
 
-
   /// doPreLayout - Backend can do any needed modification before layout
   void doPreLayout(IRBuilder& pBuilder);
 
@@ -126,12 +126,17 @@
   /// readSection - read target dependent sections
   bool readSection(Input& pInput, SectionData& pSD);
 
+  /// mayHaveUnsafeFunctionPointerAccess - check if the section may have unsafe
+  /// function pointer access
+  bool mayHaveUnsafeFunctionPointerAccess(const LDSection& pSection) const;
+
 private:
   void defineGOTSymbol(IRBuilder& pBuilder);
 
-  /// maxBranchOffset
-  /// FIXME: if we can handle arm attributes, we may refine this!
-  uint64_t maxBranchOffset() { return THM_MAX_FWD_BRANCH_OFFSET; }
+  /// maxFwdBranchOffset
+  int64_t maxFwdBranchOffset();
+  /// maxBwdBranchOffset
+  int64_t maxBwdBranchOffset();
 
   /// mayRelax - Backends should override this function if they need relaxation
   bool mayRelax() { return true; }
diff --git a/lib/Target/ARM/ARMRelocationFunctions.h b/lib/Target/ARM/ARMRelocationFunctions.h
index 790ed1f..58f00ce 100644
--- a/lib/Target/ARM/ARMRelocationFunctions.h
+++ b/lib/Target/ARM/ARMRelocationFunctions.h
@@ -32,6 +32,7 @@
 DECL_ARM_APPLY_RELOC_FUNC(prel31)           \
 DECL_ARM_APPLY_RELOC_FUNC(got_prel)         \
 DECL_ARM_APPLY_RELOC_FUNC(tls)              \
+DECL_ARM_APPLY_RELOC_FUNC(thm_jump8)        \
 DECL_ARM_APPLY_RELOC_FUNC(thm_jump11)       \
 DECL_ARM_APPLY_RELOC_FUNC(thm_jump19)       \
 DECL_ARM_APPLY_RELOC_FUNC(unsupport)
@@ -141,7 +142,7 @@
   { &unsupport,        100, "R_ARM_GNU_VTENTRY"       },  \
   { &unsupport,        101, "R_ARM_GNU_VTINERIT"      },  \
   { &thm_jump11,       102, "R_ARM_THM_JUMP11"        },  \
-  { &unsupport,        103, "R_ARM_THM_JUMP8"         },  \
+  { &thm_jump8,        103, "R_ARM_THM_JUMP8"         },  \
   { &tls,              104, "R_ARM_TLS_GD32"          },  \
   { &unsupport,        105, "R_ARM_TLS_LDM32"         },  \
   { &unsupport,        106, "R_ARM_TLS_LDO32"         },  \
diff --git a/lib/Target/ARM/ARMRelocator.cpp b/lib/Target/ARM/ARMRelocator.cpp
index 088b219..248c528 100644
--- a/lib/Target/ARM/ARMRelocator.cpp
+++ b/lib/Target/ARM/ARMRelocator.cpp
@@ -460,6 +460,29 @@
   }
 }
 
+bool ARMRelocator::mayHaveFunctionPointerAccess(const Relocation& pReloc) const
+{
+  switch (pReloc.type()) {
+    case llvm::ELF::R_ARM_PC24:
+    case llvm::ELF::R_ARM_THM_CALL:
+    case llvm::ELF::R_ARM_PLT32:
+    case llvm::ELF::R_ARM_CALL:
+    case llvm::ELF::R_ARM_JUMP24:
+    case llvm::ELF::R_ARM_THM_JUMP24:
+    case llvm::ELF::R_ARM_SBREL31:
+    case llvm::ELF::R_ARM_PREL31:
+    case llvm::ELF::R_ARM_THM_JUMP19:
+    case llvm::ELF::R_ARM_THM_JUMP6:
+    case llvm::ELF::R_ARM_THM_JUMP11:
+    case llvm::ELF::R_ARM_THM_JUMP8: {
+      return false;
+    }
+    default: {
+      return true;
+    }
+  }
+}
+
 void
 ARMRelocator::scanLocalReloc(Relocation& pReloc, const LDSection& pSection)
 {
@@ -936,6 +959,25 @@
   return Relocator::OK;
 }
 
+// R_ARM_THM_JUMP8: S + A - P
+ARMRelocator::Result thm_jump8(Relocation& pReloc, ARMRelocator& pParent)
+{
+  Relocator::DWord P = pReloc.place();
+  Relocator::DWord A = helper_sign_extend((pReloc.target() & 0x00ff) << 1, 8) +
+                       pReloc.addend();
+  // S depends on PLT exists or not
+  Relocator::Address S = pReloc.symValue();
+  if (pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT)
+    S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
+
+  Relocator::DWord X = S + A - P;
+  if (helper_check_signed_overflow(X, 9))
+    return Relocator::Overflow;
+  //                    Make sure the Imm is 0.          Result Mask.
+  pReloc.target() = (pReloc.target() & 0xFFFFFF00u) | ((X & 0x01FEu) >> 1);
+  return Relocator::OK;
+}
+
 // R_ARM_THM_JUMP11: S + A - P
 ARMRelocator::Result thm_jump11(Relocation& pReloc, ARMRelocator& pParent)
 {
@@ -948,7 +990,7 @@
     S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
 
   Relocator::DWord X = S + A - P;
-  if (helper_check_signed_overflow(X, 11))
+  if (helper_check_signed_overflow(X, 12))
     return Relocator::Overflow;
   //                    Make sure the Imm is 0.          Result Mask.
   pReloc.target() = (pReloc.target() & 0xFFFFF800u) | ((X & 0x0FFEu) >> 1);
diff --git a/lib/Target/ARM/ARMRelocator.h b/lib/Target/ARM/ARMRelocator.h
index da4e96b..9c3156b 100644
--- a/lib/Target/ARM/ARMRelocator.h
+++ b/lib/Target/ARM/ARMRelocator.h
@@ -98,6 +98,11 @@
                       LDSection& pSection,
                       Input& pInput);
 
+
+  /// mayHaveFunctionPointerAccess - check if the given reloc would possibly
+  /// access a function pointer.
+  virtual bool mayHaveFunctionPointerAccess(const Relocation& pReloc) const;
+
 private:
   void scanLocalReloc(Relocation& pReloc, const LDSection& pSection);
 
diff --git a/lib/Target/ARM/ARMToARMStub.cpp b/lib/Target/ARM/ARMToARMStub.cpp
index 3f5e6f6..ba3acf4 100644
--- a/lib/Target/ARM/ARMToARMStub.cpp
+++ b/lib/Target/ARM/ARMToARMStub.cpp
@@ -32,7 +32,7 @@
 };
 
 ARMToARMStub::ARMToARMStub(bool pIsOutputPIC)
- : Stub(), m_Name("A2A_prototype"), m_pData(NULL), m_Size(0x0)
+ : m_pData(NULL), m_Name("A2A_prototype"), m_Size(0x0)
 {
   if (pIsOutputPIC) {
     m_pData = PIC_TEMPLATE;
@@ -51,7 +51,7 @@
                            size_t pSize,
                            const_fixup_iterator pBegin,
                            const_fixup_iterator pEnd)
- : Stub(), m_Name("A2A_veneer"), m_pData(pData), m_Size(pSize)
+ : m_pData(pData), m_Name("A2A_veneer"), m_Size(pSize)
 {
   for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it)
     addFixup(**it);
@@ -113,4 +113,3 @@
 {
   return new ARMToARMStub(m_pData, m_Size, fixup_begin(), fixup_end());
 }
-
diff --git a/lib/Target/ARM/ARMToARMStub.h b/lib/Target/ARM/ARMToARMStub.h
index a38dd90..afb26a8 100644
--- a/lib/Target/ARM/ARMToARMStub.h
+++ b/lib/Target/ARM/ARMToARMStub.h
@@ -61,10 +61,10 @@
   Stub* doClone();
 
 private:
-  std::string m_Name;
   static const uint32_t PIC_TEMPLATE[];
   static const uint32_t TEMPLATE[];
   const uint32_t* m_pData;
+  std::string m_Name;
   size_t m_Size;
 };
 
diff --git a/lib/Target/ARM/ARMToTHMStub.cpp b/lib/Target/ARM/ARMToTHMStub.cpp
index 702df38..a46a0c8 100644
--- a/lib/Target/ARM/ARMToTHMStub.cpp
+++ b/lib/Target/ARM/ARMToTHMStub.cpp
@@ -34,7 +34,7 @@
 };
 
 ARMToTHMStub::ARMToTHMStub(bool pIsOutputPIC)
- : Stub(), m_Name("A2T_prototype"), m_pData(NULL), m_Size(0x0)
+ : m_pData(NULL), m_Name("A2T_prototype"), m_Size(0x0)
 {
   if (pIsOutputPIC) {
     m_pData = PIC_TEMPLATE;
@@ -53,7 +53,7 @@
                            size_t pSize,
                            const_fixup_iterator pBegin,
                            const_fixup_iterator pEnd)
- : Stub(), m_Name("A2T_veneer"), m_pData(pData), m_Size(pSize)
+ : m_pData(pData), m_Name("A2T_veneer"), m_Size(pSize)
 {
   for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it)
     addFixup(**it);
@@ -121,4 +121,3 @@
 {
   return new ARMToTHMStub(m_pData, m_Size, fixup_begin(), fixup_end());
 }
-
diff --git a/lib/Target/ARM/ARMToTHMStub.h b/lib/Target/ARM/ARMToTHMStub.h
index f39db84..e7a44bf 100644
--- a/lib/Target/ARM/ARMToTHMStub.h
+++ b/lib/Target/ARM/ARMToTHMStub.h
@@ -61,10 +61,10 @@
   Stub* doClone();
 
 private:
-  std::string m_Name;
   static const uint32_t PIC_TEMPLATE[];
   static const uint32_t TEMPLATE[];
   const uint32_t* m_pData;
+  std::string m_Name;
   size_t m_Size;
 };
 
diff --git a/lib/Target/ARM/THMToARMStub.cpp b/lib/Target/ARM/THMToARMStub.cpp
index e32222e..34e0cbf 100644
--- a/lib/Target/ARM/THMToARMStub.cpp
+++ b/lib/Target/ARM/THMToARMStub.cpp
@@ -33,15 +33,17 @@
   0x0         // dcd   R_ARM_ABS32(X)
 };
 
-THMToARMStub::THMToARMStub(bool pIsOutputPIC)
- : Stub(), m_Name("T2A_prototype"), m_pData(NULL), m_Size(0x0)
+THMToARMStub::THMToARMStub(bool pIsOutputPIC, bool pUsingThumb2)
+ : m_pData(NULL),
+   m_Name("T2A_prototype"),
+   m_Size(0x0),
+   m_bUsingThumb2(pUsingThumb2)
 {
   if (pIsOutputPIC) {
     m_pData = PIC_TEMPLATE;
     m_Size = sizeof(PIC_TEMPLATE);
     addFixup(12u, -4, llvm::ELF::R_ARM_REL32);
-  }
-  else {
+  } else {
     m_pData = TEMPLATE;
     m_Size = sizeof(TEMPLATE);
     addFixup(8u, 0x0, llvm::ELF::R_ARM_ABS32);
@@ -52,8 +54,12 @@
 THMToARMStub::THMToARMStub(const uint32_t* pData,
                            size_t pSize,
                            const_fixup_iterator pBegin,
-                           const_fixup_iterator pEnd)
- : Stub(), m_Name("T2A_veneer"), m_pData(pData), m_Size(pSize)
+                           const_fixup_iterator pEnd,
+                           bool pUsingThumb2)
+ : m_pData(pData),
+   m_Name("T2A_veneer"),
+   m_Size(pSize),
+   m_bUsingThumb2(pUsingThumb2)
 {
   for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it)
     addFixup(**it);
@@ -76,9 +82,19 @@
         // then, we do not need a stub unless the branch target is too far.
         uint64_t dest = pTargetSymValue + pReloc.addend() + 4u;
         int64_t branch_offset = static_cast<int64_t>(dest) - pSource;
-        if ((branch_offset > ARMGNULDBackend::THM_MAX_FWD_BRANCH_OFFSET) ||
-            (branch_offset < ARMGNULDBackend::THM_MAX_BWD_BRANCH_OFFSET))
-          result = true;
+        if (m_bUsingThumb2) {
+          if ((branch_offset > ARMGNULDBackend::THM2_MAX_FWD_BRANCH_OFFSET) ||
+              (branch_offset < ARMGNULDBackend::THM2_MAX_BWD_BRANCH_OFFSET)) {
+            result = true;
+            break;
+          }
+        } else {
+          if ((branch_offset > ARMGNULDBackend::THM_MAX_FWD_BRANCH_OFFSET) ||
+              (branch_offset < ARMGNULDBackend::THM_MAX_BWD_BRANCH_OFFSET)) {
+            result = true;
+            break;
+          }
+        }
         break;
       }
       case llvm::ELF::R_ARM_THM_JUMP24: {
@@ -121,6 +137,9 @@
 
 Stub* THMToARMStub::doClone()
 {
-  return new THMToARMStub(m_pData, m_Size, fixup_begin(), fixup_end());
+  return new THMToARMStub(m_pData,
+                          m_Size,
+                          fixup_begin(),
+                          fixup_end(),
+                          m_bUsingThumb2);
 }
-
diff --git a/lib/Target/ARM/THMToARMStub.h b/lib/Target/ARM/THMToARMStub.h
index a7b6cad..af5a926 100644
--- a/lib/Target/ARM/THMToARMStub.h
+++ b/lib/Target/ARM/THMToARMStub.h
@@ -13,7 +13,6 @@
 #include <llvm/Support/DataTypes.h>
 #include <mcld/Fragment/Stub.h>
 #include <string>
-#include <vector>
 
 namespace mcld
 {
@@ -28,7 +27,7 @@
 class THMToARMStub : public Stub
 {
 public:
-  THMToARMStub(bool pIsOutputPIC);
+  THMToARMStub(bool pIsOutputPIC, bool pUsingThumb2);
 
   ~THMToARMStub();
 
@@ -58,17 +57,19 @@
   THMToARMStub(const uint32_t* pData,
                size_t pSize,
                const_fixup_iterator pBegin,
-               const_fixup_iterator pEnd);
+               const_fixup_iterator pEnd,
+               bool pUsingThumb2);
 
   /// doClone
   Stub* doClone();
 
 private:
-  std::string m_Name;
   static const uint32_t PIC_TEMPLATE[];
   static const uint32_t TEMPLATE[];
   const uint32_t* m_pData;
+  std::string m_Name;
   size_t m_Size;
+  bool m_bUsingThumb2;
 };
 
 } // namespace of mcld
diff --git a/lib/Target/ARM/THMToTHMStub.cpp b/lib/Target/ARM/THMToTHMStub.cpp
index b58de77..f167f28 100644
--- a/lib/Target/ARM/THMToTHMStub.cpp
+++ b/lib/Target/ARM/THMToTHMStub.cpp
@@ -35,15 +35,17 @@
   0x0         // dcd   R_ARM_ABS32(X)
 };
 
-THMToTHMStub::THMToTHMStub(bool pIsOutputPIC)
- : Stub(), m_Name("T2T_prototype"), m_pData(NULL), m_Size(0x0)
+THMToTHMStub::THMToTHMStub(bool pIsOutputPIC, bool pUsingThumb2)
+ : m_pData(NULL),
+   m_Name("T2T_prototype"),
+   m_Size(0x0),
+   m_bUsingThumb2(pUsingThumb2)
 {
   if (pIsOutputPIC) {
     m_pData = PIC_TEMPLATE;
     m_Size = sizeof(PIC_TEMPLATE);
     addFixup(16u, 0x0, llvm::ELF::R_ARM_REL32);
-  }
-  else {
+  } else {
     m_pData = TEMPLATE;
     m_Size = sizeof(TEMPLATE);
     addFixup(12u, 0x0, llvm::ELF::R_ARM_ABS32);
@@ -54,8 +56,12 @@
 THMToTHMStub::THMToTHMStub(const uint32_t* pData,
                            size_t pSize,
                            const_fixup_iterator pBegin,
-                           const_fixup_iterator pEnd)
- : Stub(), m_Name("T2T_veneer"), m_pData(pData), m_Size(pSize)
+                           const_fixup_iterator pEnd,
+                           bool pUsingThumb2)
+ : m_pData(pData),
+   m_Name("T2T_veneer"),
+   m_Size(pSize),
+   m_bUsingThumb2(pUsingThumb2)
 {
   for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it)
     addFixup(**it);
@@ -78,9 +84,19 @@
         // Check if the branch target is too far
         uint64_t dest = pTargetSymValue + pReloc.addend() + 4u;
         int64_t branch_offset = static_cast<int64_t>(dest) - pSource;
-        if ((branch_offset > ARMGNULDBackend::THM_MAX_FWD_BRANCH_OFFSET) ||
-            (branch_offset < ARMGNULDBackend::THM_MAX_BWD_BRANCH_OFFSET))
-          result =  true;
+        if (m_bUsingThumb2) {
+           if ((branch_offset > ARMGNULDBackend::THM2_MAX_FWD_BRANCH_OFFSET) ||
+               (branch_offset < ARMGNULDBackend::THM2_MAX_BWD_BRANCH_OFFSET)) {
+             result = true;
+             break;
+           }
+        } else {
+          if ((branch_offset > ARMGNULDBackend::THM_MAX_FWD_BRANCH_OFFSET) ||
+              (branch_offset < ARMGNULDBackend::THM_MAX_BWD_BRANCH_OFFSET)) {
+            result = true;
+            break;
+          }
+        }
         break;
       }
       default:
@@ -117,6 +133,9 @@
 
 Stub* THMToTHMStub::doClone()
 {
-  return new THMToTHMStub(m_pData, m_Size, fixup_begin(), fixup_end());
+  return new THMToTHMStub(m_pData,
+                          m_Size,
+                          fixup_begin(),
+                          fixup_end(),
+                          m_bUsingThumb2);
 }
-
diff --git a/lib/Target/ARM/THMToTHMStub.h b/lib/Target/ARM/THMToTHMStub.h
index f6d155e..4f3f363 100644
--- a/lib/Target/ARM/THMToTHMStub.h
+++ b/lib/Target/ARM/THMToTHMStub.h
@@ -13,7 +13,6 @@
 #include <llvm/Support/DataTypes.h>
 #include <mcld/Fragment/Stub.h>
 #include <string>
-#include <vector>
 
 namespace mcld
 {
@@ -28,7 +27,7 @@
 class THMToTHMStub : public Stub
 {
 public:
-  THMToTHMStub(bool pIsOutputPIC);
+  THMToTHMStub(bool pIsOutputPIC, bool pUsingThumb2);
 
   ~THMToTHMStub();
 
@@ -58,17 +57,19 @@
   THMToTHMStub(const uint32_t* pData,
                size_t pSize,
                const_fixup_iterator pBegin,
-               const_fixup_iterator pEnd);
+               const_fixup_iterator pEnd,
+               bool pUsingThumb2);
 
   /// doClone
   Stub* doClone();
 
 private:
-  std::string m_Name;
   static const uint32_t PIC_TEMPLATE[];
   static const uint32_t TEMPLATE[];
   const uint32_t* m_pData;
+  std::string m_Name;
   size_t m_Size;
+  bool m_bUsingThumb2;
 };
 
 } // namespace of mcld
diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp
index e888bc9..7021c5f 100644
--- a/lib/Target/GNULDBackend.cpp
+++ b/lib/Target/GNULDBackend.cpp
@@ -8,13 +8,6 @@
 //===----------------------------------------------------------------------===//
 #include <mcld/Target/GNULDBackend.h>
 
-#include <string>
-#include <cstring>
-#include <cassert>
-#include <vector>
-#include <algorithm>
-#include <map>
-
 #include <mcld/Module.h>
 #include <mcld/LinkerConfig.h>
 #include <mcld/LinkerScript.h>
@@ -49,8 +42,16 @@
 #include <mcld/Fragment/FillFragment.h>
 #include <mcld/MC/Attribute.h>
 
+#include <llvm/ADT/StringRef.h>
 #include <llvm/Support/Host.h>
 
+#include <algorithm>
+#include <cstring>
+#include <cassert>
+#include <map>
+#include <string>
+#include <vector>
+
 namespace {
 
 //===--------------------------------------------------------------------===//
@@ -1380,7 +1381,8 @@
   bool is_exec = (pSectHdr.flag() & llvm::ELF::SHF_EXECINSTR) != 0;
   // TODO: need to take care other possible output sections
   switch (pSectHdr.kind()) {
-    case LDFileFormat::Regular:
+    case LDFileFormat::TEXT:
+    case LDFileFormat::DATA:
       if (is_exec) {
         if (&pSectHdr == &file_format->getInit())
           return SHO_INIT;
@@ -2415,7 +2417,8 @@
            config().codeGenType() == LinkerConfig::Object))
         wanted = true;
       break;
-    case LDFileFormat::Regular:
+    case LDFileFormat::TEXT:
+    case LDFileFormat::DATA:
     case LDFileFormat::Target:
     case LDFileFormat::MetaData:
     case LDFileFormat::BSS:
@@ -2580,6 +2583,19 @@
   }
 }
 
+/// mayHaveUnsafeFunctionPointerAccess - check if the section may have unsafe
+/// function pointer access
+bool GNULDBackend::mayHaveUnsafeFunctionPointerAccess(const LDSection& pSection)
+    const
+{
+  llvm::StringRef name(pSection.name());
+  return !name.startswith(".rodata._ZTV") &&
+         !name.startswith(".data.rel.ro._ZTV") &&
+         !name.startswith(".rodata._ZTC") &&
+         !name.startswith(".data.rel.ro._ZTC") &&
+         !name.startswith(".eh_frame");
+}
+
 /// preLayout - Backend can do any needed modification before layout
 void GNULDBackend::preLayout(Module& pModule, IRBuilder& pBuilder)
 {
@@ -3014,7 +3030,8 @@
 bool GNULDBackend::initBRIslandFactory()
 {
   if (NULL == m_pBRIslandFactory) {
-    m_pBRIslandFactory = new BranchIslandFactory(maxBranchOffset());
+    m_pBRIslandFactory = new BranchIslandFactory(maxFwdBranchOffset(),
+                                                 maxBwdBranchOffset());
   }
   return true;
 }
diff --git a/lib/Target/Hexagon/HexagonLDBackend.cpp b/lib/Target/Hexagon/HexagonLDBackend.cpp
index 9d16804..eb3458b 100644
--- a/lib/Target/Hexagon/HexagonLDBackend.cpp
+++ b/lib/Target/Hexagon/HexagonLDBackend.cpp
@@ -72,6 +72,12 @@
   return true;
 }
 
+const Relocator* HexagonLDBackend::getRelocator() const
+{
+  assert(NULL != m_pRelocator);
+  return m_pRelocator;
+}
+
 Relocator* HexagonLDBackend::getRelocator()
 {
   assert(NULL != m_pRelocator);
@@ -553,7 +559,9 @@
 bool HexagonLDBackend::initBRIslandFactory()
 {
   if (NULL == m_pBRIslandFactory) {
-    m_pBRIslandFactory = new BranchIslandFactory(maxBranchOffset(), 0);
+    m_pBRIslandFactory = new BranchIslandFactory(maxFwdBranchOffset(),
+                                                 maxBwdBranchOffset(),
+                                                 0);
   }
   return true;
 }
diff --git a/lib/Target/Hexagon/HexagonLDBackend.h b/lib/Target/Hexagon/HexagonLDBackend.h
index 21d2e38..0fc909c 100644
--- a/lib/Target/Hexagon/HexagonLDBackend.h
+++ b/lib/Target/Hexagon/HexagonLDBackend.h
@@ -83,6 +83,7 @@
   bool initRelocator();
 
   /// getRelocator - return relocator.
+  const Relocator* getRelocator() const;
   Relocator* getRelocator();
 
   ResolveInfo::Desc getSymDesc(uint16_t shndx) const
@@ -162,7 +163,8 @@
   /// target-dependent segments
   void doCreateProgramHdrs(Module& pModule);
 
-  uint64_t maxBranchOffset() { return ~(~0 << 6); }
+  /// maxFwdBranchOffset
+  int64_t maxFwdBranchOffset() { return ~(~0 << 6); }
 
   virtual void setGOTSectionSize(IRBuilder& pBuilder);
 
diff --git a/lib/Target/Mips/MipsLDBackend.cpp b/lib/Target/Mips/MipsLDBackend.cpp
index 46c580d..9714e91 100644
--- a/lib/Target/Mips/MipsLDBackend.cpp
+++ b/lib/Target/Mips/MipsLDBackend.cpp
@@ -143,6 +143,21 @@
                    0x0,  // value
                    FragmentRef::Null(), // FragRef
                    ResolveInfo::Default);
+  pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Unresolve>(
+                   "_gp",
+                   ResolveInfo::NoType,
+                   ResolveInfo::Define,
+                   ResolveInfo::Absolute,
+                   0x0,  // size
+                   0x0,  // value
+                   FragmentRef::Null(), // FragRef
+                   ResolveInfo::Default);
+}
+
+const Relocator* MipsGNULDBackend::getRelocator() const
+{
+  assert(NULL != m_pRelocator);
+  return m_pRelocator;
 }
 
 Relocator* MipsGNULDBackend::getRelocator()
diff --git a/lib/Target/Mips/MipsLDBackend.h b/lib/Target/Mips/MipsLDBackend.h
index 78c5c58..991b3c4 100644
--- a/lib/Target/Mips/MipsLDBackend.h
+++ b/lib/Target/Mips/MipsLDBackend.h
@@ -47,6 +47,7 @@
   void initTargetSymbols(IRBuilder& pBuilder, Module& pModule);
 
   /// getRelocator - return relocator.
+  const Relocator* getRelocator() const;
   Relocator* getRelocator();
 
   /// preLayout - Backend can do any needed modification before layout
diff --git a/lib/Target/X86/X86LDBackend.cpp b/lib/Target/X86/X86LDBackend.cpp
index f105dd3..eb4c6c6 100644
--- a/lib/Target/X86/X86LDBackend.cpp
+++ b/lib/Target/X86/X86LDBackend.cpp
@@ -72,6 +72,12 @@
   delete m_pDynamic;
 }
 
+const Relocator* X86GNULDBackend::getRelocator() const
+{
+  assert(NULL != m_pRelocator);
+  return m_pRelocator;
+}
+
 Relocator* X86GNULDBackend::getRelocator()
 {
   assert(NULL != m_pRelocator);
diff --git a/lib/Target/X86/X86LDBackend.h b/lib/Target/X86/X86LDBackend.h
index 779c2d1..503fca9 100644
--- a/lib/Target/X86/X86LDBackend.h
+++ b/lib/Target/X86/X86LDBackend.h
@@ -76,6 +76,7 @@
   virtual bool initRelocator() = 0;
 
   /// getRelocator - return relocator.
+  const Relocator* getRelocator() const;
   Relocator* getRelocator();
 
   virtual void initTargetSections(Module& pModule, ObjectBuilder& pBuilder) = 0;
diff --git a/lib/Target/X86/X86Relocator.cpp b/lib/Target/X86/X86Relocator.cpp
index 8cc916e..794296b 100644
--- a/lib/Target/X86/X86Relocator.cpp
+++ b/lib/Target/X86/X86Relocator.cpp
@@ -323,6 +323,23 @@
   return X86_32ApplyFunctions[pType].size;;
 }
 
+bool
+X86_32Relocator::mayHaveFunctionPointerAccess(const Relocation& pReloc) const
+{
+  switch (pReloc.type()) {
+    case llvm::ELF::R_386_32:
+    case llvm::ELF::R_386_16:
+    case llvm::ELF::R_386_8:
+    case llvm::ELF::R_386_GOTOFF:
+    case llvm::ELF::R_386_GOT32: {
+      return true;
+    }
+    default: {
+      return false;
+    }
+  }
+}
+
 void X86_32Relocator::scanLocalReloc(Relocation& pReloc,
                                      IRBuilder& pBuilder,
                                      Module& pModule,
@@ -1297,6 +1314,40 @@
   return X86_64ApplyFunctions[pType].size;
 }
 
+bool
+X86_64Relocator::mayHaveFunctionPointerAccess(const Relocation& pReloc) const
+{
+  bool possible_funcptr_reloc = false;
+  switch (pReloc.type()) {
+    case llvm::ELF::R_X86_64_64:
+    case llvm::ELF::R_X86_64_32:
+    case llvm::ELF::R_X86_64_32S:
+    case llvm::ELF::R_X86_64_16:
+    case llvm::ELF::R_X86_64_8:
+    case llvm::ELF::R_X86_64_GOT64:
+    case llvm::ELF::R_X86_64_GOT32:
+    case llvm::ELF::R_X86_64_GOTPCREL64:
+    case llvm::ELF::R_X86_64_GOTPCREL:
+    case llvm::ELF::R_X86_64_GOTPLT64: {
+      possible_funcptr_reloc = true;
+      break;
+    }
+    default: {
+      possible_funcptr_reloc = false;
+      break;
+    }
+  }
+
+ if (pReloc.symInfo()->isGlobal()) {
+    return (config().codeGenType() == LinkerConfig::DynObj) &&
+           ((pReloc.symInfo()->visibility() != ResolveInfo::Default) ||
+            possible_funcptr_reloc);
+ } else {
+    return (config().codeGenType() == LinkerConfig::DynObj) ||
+           possible_funcptr_reloc;
+ }
+}
+
 void X86_64Relocator::scanLocalReloc(Relocation& pReloc,
                                      IRBuilder& pBuilder,
                                      Module& pModule,
diff --git a/lib/Target/X86/X86Relocator.h b/lib/Target/X86/X86Relocator.h
index caf259f..84170fe 100644
--- a/lib/Target/X86/X86Relocator.h
+++ b/lib/Target/X86/X86Relocator.h
@@ -151,6 +151,10 @@
 
   X86_32GOTEntry& getTLSModuleID();
 
+  /// mayHaveFunctionPointerAccess - check if the given reloc would possibly
+  /// access a function pointer.
+  virtual bool mayHaveFunctionPointerAccess(const Relocation& pReloc) const;
+
 private:
   void scanLocalReloc(Relocation& pReloc,
                       IRBuilder& pBuilder,
@@ -207,6 +211,10 @@
   const RelRelMap& getRelRelMap() const { return m_RelRelMap; }
   RelRelMap&       getRelRelMap()       { return m_RelRelMap; }
 
+  /// mayHaveFunctionPointerAccess - check if the given reloc would possibly
+  /// access a function pointer.
+  virtual bool mayHaveFunctionPointerAccess(const Relocation& pReloc) const;
+
 private:
   void scanLocalReloc(Relocation& pReloc,
                       IRBuilder& pBuilder,
diff --git a/tools/llvm-mcld/llvm-mcld.cpp b/tools/llvm-mcld/llvm-mcld.cpp
deleted file mode 100644
index e984501..0000000
--- a/tools/llvm-mcld/llvm-mcld.cpp
+++ /dev/null
@@ -1,1552 +0,0 @@
-//===- llvm-mcld.cpp ------------------------------------------------------===//
-//
-//                     The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include <mcld/Module.h>
-#include <mcld/LinkerConfig.h>
-#include <mcld/LinkerScript.h>
-#include <mcld/Target/TargetMachine.h>
-#include <mcld/Support/TargetSelect.h>
-#include <mcld/Support/TargetRegistry.h>
-#include <mcld/Support/CommandLine.h>
-#include <mcld/Support/Path.h>
-#include <mcld/Support/RealPath.h>
-#include <mcld/Support/MsgHandling.h>
-#include <mcld/Support/FileHandle.h>
-#include <mcld/Support/FileSystem.h>
-#include <mcld/Support/raw_ostream.h>
-#include <mcld/Support/SystemUtils.h>
-#include <mcld/Support/ToolOutputFile.h>
-#include <mcld/LD/DiagnosticLineInfo.h>
-#include <mcld/LD/TextDiagnosticPrinter.h>
-
-#include <llvm/PassManager.h>
-#include <llvm/Pass.h>
-#include <llvm/IR/Module.h>
-#include <llvm/IR/DataLayout.h>
-#include <llvm/IR/LLVMContext.h>
-#include <llvm/ADT/Triple.h>
-#include <llvm/ADT/StringSwitch.h>
-#include <llvm/MC/SubtargetFeature.h>
-#include <llvm/Support/CommandLine.h>
-#include <llvm/Support/Debug.h>
-#include <llvm/Support/FormattedStream.h>
-#include <llvm/Support/Host.h>
-#include <llvm/Support/IRReader.h>
-#include <llvm/Support/ManagedStatic.h>
-#include <llvm/Support/Signals.h>
-#include <llvm/Support/TargetRegistry.h>
-#include <llvm/Support/TargetSelect.h>
-#include <llvm/Support/Process.h>
-#include <llvm/Target/TargetMachine.h>
-
-#if defined(HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#if defined(_MSC_VER) || defined(__MINGW32__)
-#include <io.h>
-#ifndef STDIN_FILENO
-# define STDIN_FILENO 0
-#endif
-#ifndef STDOUT_FILENO
-# define STDOUT_FILENO 1
-#endif
-#ifndef STDERR_FILENO
-# define STDERR_FILENO 2
-#endif
-#endif
-
-using namespace llvm;
-
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-
-static cl::opt<bool>
-UnitTest("unittest",  cl::desc("do unit test") );
-
-int unit_test( int argc, char* argv[] )
-{
-  testing::InitGoogleTest( &argc, argv );
-  return RUN_ALL_TESTS();
-}
-
-#endif
-
-// General options for llc.  Other pass-specific options are specified
-// within the corresponding llc passes, and target-specific options
-// and back-end code generation options are specified with the target machine.
-//
-// Determine optimization level.
-static cl::opt<char>
-OptLevel("O",
-         cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
-                  "(default = '-O2')"),
-         cl::Prefix,
-         cl::ZeroOrMore,
-         cl::init(' '));
-
-static cl::opt<std::string>
-TargetTriple("mtriple", cl::desc("Override target triple for module"));
-
-static cl::opt<std::string>
-MArch("march", cl::desc("Architecture to generate code for (see --version)"));
-
-static cl::opt<std::string>
-MCPU("mcpu",
-  cl::desc("Target a specific cpu type (-mcpu=help for details)"),
-  cl::value_desc("cpu-name"),
-  cl::init(""));
-
-static cl::list<std::string>
-MAttrs("mattr",
-  cl::CommaSeparated,
-  cl::desc("Target specific attributes (-mattr=help for details)"),
-  cl::value_desc("a1,+a2,-a3,..."));
-
-static cl::opt<llvm::CodeModel::Model>
-CMModel("code-model",
-        cl::desc("Choose code model"),
-        cl::init(CodeModel::Default),
-        cl::values(clEnumValN(CodeModel::Default, "default",
-                              "Target default code model"),
-                   clEnumValN(CodeModel::Small, "small",
-                              "Small code model"),
-                   clEnumValN(CodeModel::Kernel, "kernel",
-                              "Kernel code model"),
-                   clEnumValN(CodeModel::Medium, "medium",
-                              "Medium code model"),
-                   clEnumValN(CodeModel::Large, "large",
-                              "Large code model"),
-                   clEnumValEnd));
-
-cl::opt<bool> NoVerify("disable-verify", cl::Hidden,
-                       cl::desc("Do not verify input module"));
-
-static cl::opt<bool>
-EnableFPMAD("enable-fp-mad",
-  cl::desc("Enable less precise MAD instructions to be generated"),
-  cl::init(false));
-
-static cl::opt<bool>
-DisableFPElim("disable-fp-elim",
-  cl::desc("Disable frame pointer elimination optimization"),
-  cl::init(false));
-
-static cl::opt<bool>
-DisableFPElimNonLeaf("disable-non-leaf-fp-elim",
-  cl::desc("Disable frame pointer elimination optimization for non-leaf funcs"),
-  cl::init(false));
-
-static cl::opt<llvm::FPOpFusion::FPOpFusionMode>
-FuseFPOps("fuse-fp-ops",
-  cl::desc("Enable aggresive formation of fused FP ops"),
-  cl::init(FPOpFusion::Standard),
-  cl::values(
-    clEnumValN(FPOpFusion::Fast, "fast",
-               "Fuse FP ops whenever profitable"),
-    clEnumValN(FPOpFusion::Standard, "standard",
-               "Only fuse 'blessed' FP ops."),
-    clEnumValN(FPOpFusion::Strict, "strict",
-               "Only fuse FP ops when the result won't be effected."),
-    clEnumValEnd));
-
-static cl::opt<bool>
-EnableUnsafeFPMath("enable-unsafe-fp-math",
-  cl::desc("Enable optimizations that may decrease FP precision"),
-  cl::init(false));
-
-static cl::opt<bool>
-EnableNoInfsFPMath("enable-no-infs-fp-math",
-  cl::desc("Enable FP math optimizations that assume no +-Infs"),
-  cl::init(false));
-
-static cl::opt<bool>
-EnableNoNaNsFPMath("enable-no-nans-fp-math",
-  cl::desc("Enable FP math optimizations that assume no NaNs"),
-  cl::init(false));
-
-static cl::opt<bool>
-EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math",
-  cl::Hidden,
-  cl::desc("Force codegen to assume rounding mode can change dynamically"),
-  cl::init(false));
-
-static cl::opt<bool>
-GenerateSoftFloatCalls("soft-float",
-  cl::desc("Generate software floating point library calls"),
-  cl::init(false));
-
-static cl::opt<llvm::FloatABI::ABIType>
-FloatABIForCalls("float-abi",
-  cl::desc("Choose float ABI type"),
-  cl::init(FloatABI::Default),
-  cl::values(
-    clEnumValN(FloatABI::Default, "default",
-               "Target default float ABI type"),
-    clEnumValN(FloatABI::Soft, "soft",
-               "Soft float ABI (implied by -soft-float)"),
-    clEnumValN(FloatABI::Hard, "hard",
-               "Hard float ABI (uses FP registers)"),
-    clEnumValEnd));
-
-static cl::opt<bool>
-DontPlaceZerosInBSS("nozero-initialized-in-bss",
-  cl::desc("Don't place zero-initialized symbols into bss section"),
-  cl::init(false));
-
-static cl::opt<bool>
-EnableJITExceptionHandling("jit-enable-eh",
-  cl::desc("Emit exception handling information"),
-  cl::init(false));
-
-// In debug builds, make this default to true.
-#ifdef NDEBUG
-#define EMIT_DEBUG false
-#else
-#define EMIT_DEBUG true
-#endif
-static cl::opt<bool>
-EmitJitDebugInfo("jit-emit-debug",
-  cl::desc("Emit debug information to debugger"),
-  cl::init(EMIT_DEBUG));
-#undef EMIT_DEBUG
-
-static cl::opt<bool>
-EmitJitDebugInfoToDisk("jit-emit-debug-to-disk",
-  cl::Hidden,
-  cl::desc("Emit debug info objfiles to disk"),
-  cl::init(false));
-
-static cl::opt<bool>
-EnableGuaranteedTailCallOpt("tailcallopt",
-  cl::desc("Turn fastcc calls into tail calls by (potentially) changing ABI."),
-  cl::init(false));
-
-static cl::opt<unsigned>
-OverrideStackAlignment("stack-alignment",
-  cl::desc("Override default stack alignment"),
-  cl::init(0));
-
-static cl::opt<bool>
-EnableRealignStack("realign-stack",
-  cl::desc("Realign stack if needed"),
-  cl::init(true));
-
-static cl::opt<std::string>
-TrapFuncName("trap-func", cl::Hidden,
-  cl::desc("Emit a call to trap function rather than a trap instruction"),
-  cl::init(""));
-
-static cl::opt<bool>
-SegmentedStacks("segmented-stacks",
-  cl::desc("Use segmented stacks if possible."),
-  cl::init(false));
-
-//===----------------------------------------------------------------------===//
-// Command Line Options
-// There are four kinds of command line options:
-//   1. Bitcode option. Used to represent a bitcode.
-//   2. Attribute options. Attributes describes the input file after them. For
-//      example, --as-needed affects the input file after this option. Attribute
-//      options are not attributes. Attribute options are the options that is
-//      used to define a legal attribute.
-//   3. Scripting options, Used to represent a subset of link scripting
-//      language, such as --defsym.
-//   4. General options. (the rest of options)
-//===----------------------------------------------------------------------===//
-// Bitcode Options
-//===----------------------------------------------------------------------===//
-static cl::opt<mcld::sys::fs::Path, false, llvm::cl::parser<mcld::sys::fs::Path> >
-ArgBitcodeFilename("dB",
-              cl::desc("set default bitcode"),
-              cl::value_desc("bitcode"));
-
-//===----------------------------------------------------------------------===//
-// General Options
-//===----------------------------------------------------------------------===//
-static cl::opt<mcld::sys::fs::Path, false, llvm::cl::parser<mcld::sys::fs::Path> >
-ArgOutputFilename("o",
-               cl::desc("Output filename"),
-               cl::value_desc("filename"));
-
-static cl::alias
-AliasOutputFilename("output",
-                    cl::desc("alias for -o"),
-                    cl::aliasopt(ArgOutputFilename));
-
-static cl::opt<mcld::sys::fs::Path, false, llvm::cl::parser<mcld::sys::fs::Path> >
-ArgSysRoot("sysroot",
-           cl::desc("Use directory as the location of the sysroot, overriding the configure-time default."),
-           cl::value_desc("directory"),
-           cl::ValueRequired);
-
-static cl::list<std::string, bool, llvm::cl::SearchDirParser>
-ArgSearchDirList("L",
-                 cl::ZeroOrMore,
-                 cl::desc("Add path searchdir to the list of paths that ld will search for archive libraries and ld control scripts."),
-                 cl::value_desc("searchdir"),
-                 cl::Prefix);
-
-static cl::alias
-ArgSearchDirListAlias("library-path",
-                      cl::desc("alias for -L"),
-                      cl::aliasopt(ArgSearchDirList));
-
-static cl::opt<bool>
-ArgTrace("t",
-         cl::desc("Print the names of the input files as ld processes them."));
-
-static cl::alias
-ArgTraceAlias("trace",
-              cl::desc("alias for -t"),
-              cl::aliasopt(ArgTrace));
-
-static cl::opt<int>
-ArgVerbose("verbose",
-           cl::init(-1),
-           cl::desc("Display the version number for ld and list the linker emulations supported."));
-
-static cl::opt<bool>
-ArgVersion("V",
-           cl::init(false),
-           cl::desc("Display the version number for MCLinker."));
-
-static cl::opt<int>
-ArgMaxErrorNum("error-limit",
-               cl::init(-1),
-               cl::desc("limits the maximum number of erros."));
-
-static cl::opt<int>
-ArgMaxWarnNum("warning-limit",
-               cl::init(-1),
-               cl::desc("limits the maximum number of warnings."));
-
-static cl::opt<std::string>
-ArgEntry("e",
-         cl::desc("Use entry as the explicit symbol for beginning execution of your program."),
-         cl::value_desc("entry"),
-         cl::ValueRequired);
-
-static cl::alias
-ArgEntryAlias("entry",
-              cl::desc("alias for -e"),
-              cl::aliasopt(ArgEntry));
-
-static cl::opt<bool>
-ArgBsymbolic("Bsymbolic",
-             cl::desc("Bind references within the shared library."),
-             cl::init(false));
-
-static cl::opt<bool>
-ArgBgroup("Bgroup",
-          cl::desc("Info the dynamic linker to perform lookups only inside the group."),
-          cl::init(false));
-
-static cl::opt<std::string>
-ArgSOName("soname",
-          cl::desc("Set internal name of shared library"),
-          cl::value_desc("name"));
-
-static cl::opt<bool>
-ArgNoUndefined("no-undefined",
-               cl::desc("Do not allow unresolved references"),
-               cl::init(false));
-
-static cl::opt<bool>
-ArgAllowMulDefs("allow-multiple-definition",
-                cl::desc("Allow multiple definition"),
-                cl::init(false));
-
-static cl::opt<bool>
-ArgEhFrameHdr("eh-frame-hdr",
-              cl::desc("Request creation of \".eh_frame_hdr\" section and ELF \"PT_GNU_EH_FRAME\" segment header."),
-              cl::init(false));
-
-static cl::list<mcld::ZOption, bool, llvm::cl::parser<mcld::ZOption> >
-ArgZOptionList("z",
-               cl::ZeroOrMore,
-               cl::desc("The -z options for GNU ld compatibility."),
-               cl::value_desc("keyword"),
-               cl::Prefix);
-
-cl::opt<mcld::CodeGenFileType>
-ArgFileType("filetype", cl::init(mcld::CGFT_EXEFile),
-  cl::desc("Choose a file type (not all types are supported by all targets):"),
-  cl::values(
-       clEnumValN(mcld::CGFT_ASMFile, "asm",
-                  "Emit an assembly ('.s') file"),
-       clEnumValN(mcld::CGFT_OBJFile, "obj",
-                  "Emit a relocatable object ('.o') file"),
-       clEnumValN(mcld::CGFT_DSOFile, "dso",
-                  "Emit an dynamic shared object ('.so') file"),
-       clEnumValN(mcld::CGFT_EXEFile, "exe",
-                  "Emit a executable ('.exe') file"),
-       clEnumValN(mcld::CGFT_NULLFile, "null",
-                  "Emit nothing, for performance testing"),
-       clEnumValEnd));
-
-static cl::opt<bool>
-ArgShared("shared",
-          cl::desc("Create a shared library."),
-          cl::init(false));
-
-static cl::alias
-ArgSharedAlias("Bshareable",
-               cl::desc("alias for -shared"),
-               cl::aliasopt(ArgShared));
-
-static cl::opt<bool>
-ArgPIE("pie",
-       cl::desc("Emit a position-independent executable file"),
-       cl::init(false));
-
-static cl::opt<bool>
-ArgRelocatable("relocatable",
-               cl::desc("Generate relocatable output"),
-               cl::init(false));
-
-static cl::alias
-ArgRelocatableAlias("r",
-                    cl::desc("alias for --relocatable"),
-                    cl::aliasopt(ArgRelocatable));
-
-static cl::opt<Reloc::Model>
-ArgRelocModel("relocation-model",
-             cl::desc("Choose relocation model"),
-             cl::init(Reloc::Default),
-             cl::values(
-               clEnumValN(Reloc::Default, "default",
-                       "Target default relocation model"),
-               clEnumValN(Reloc::Static, "static",
-                       "Non-relocatable code"),
-               clEnumValN(Reloc::PIC_, "pic",
-                       "Fully relocatable, position independent code"),
-               clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic",
-                       "Relocatable external references, non-relocatable code"),
-               clEnumValEnd));
-
-static cl::opt<bool>
-ArgFPIC("fPIC",
-        cl::desc("Set relocation model to pic. The same as -relocation-model=pic."),
-        cl::init(false));
-
-static cl::opt<std::string>
-ArgDyld("dynamic-linker",
-        cl::ZeroOrMore,
-        cl::desc("Set the name of the dynamic linker."),
-        cl::value_desc("Program"));
-
-namespace color {
-enum Color {
-  Never,
-  Always,
-  Auto
-};
-} // namespace of color
-
-static cl::opt<color::Color>
-ArgColor("color",
-  cl::value_desc("WHEN"),
-  cl::desc("Surround the result strings with the marker"),
-  cl::init(color::Auto),
-  cl::values(
-    clEnumValN(color::Never, "never",
-      "do not surround result strings"),
-    clEnumValN(color::Always, "always",
-      "always surround result strings, even the output is a plain file"),
-    clEnumValN(color::Auto, "auto",
-      "surround result strings only if the output is a tty"),
-    clEnumValEnd));
-
-static cl::opt<bool>
-ArgDiscardLocals("discard-locals",
-                 cl::desc("Delete all temporary local symbols."),
-                 cl::init(false));
-
-static cl::alias
-ArgDiscardLocalsAlias("X",
-                      cl::desc("alias for --discard-locals"),
-                      cl::aliasopt(ArgDiscardLocals));
-
-static cl::opt<bool>
-ArgDiscardAll("discard-all",
-              cl::desc("Delete all local symbols."),
-              cl::init(false));
-
-static cl::alias
-ArgDiscardAllAlias("x",
-                   cl::desc("alias for --discard-all"),
-                   cl::aliasopt(ArgDiscardAll));
-
-static cl::opt<bool>
-ArgStripDebug("strip-debug",
-              cl::desc("Omit debugger symbol information from the output file."),
-              cl::init(false));
-
-static cl::alias
-ArgStripDebugAlias("S",
-                   cl::desc("alias for --strip-debug"),
-                   cl::aliasopt(ArgStripDebug));
-
-static cl::opt<bool>
-ArgStripAll("strip-all",
-            cl::desc("Omit all symbol information from the output file."),
-            cl::init(false));
-
-static cl::alias
-ArgStripAllAlias("s",
-                 cl::desc("alias for --strip-all"),
-                 cl::aliasopt(ArgStripAll));
-
-static cl::opt<bool>
-ArgNMagic("nmagic",
-          cl::desc("Do not page align data"),
-          cl::init(false));
-
-static cl::alias
-ArgNMagicAlias("n",
-               cl::desc("alias for --nmagic"),
-               cl::aliasopt(ArgNMagic));
-
-static cl::opt<bool>
-ArgOMagic("omagic",
-          cl::desc("Do not page align data, do not make text readonly"),
-          cl::init(false));
-
-static cl::alias
-ArgOMagicAlias("N",
-               cl::desc("alias for --omagic"),
-               cl::aliasopt(ArgOMagic));
-
-
-static cl::opt<int>
-ArgGPSize("G",
-          cl::desc("Set the maximum size of objects to be optimized using GP"),
-          cl::init(8));
-
-/// @{
-/// @name FIXME: begin of unsupported options
-/// @}
-static cl::opt<bool>
-ArgGCSections("gc-sections",
-              cl::desc("Enable garbage collection of unused input sections."),
-              cl::init(false));
-
-static cl::opt<bool>
-ArgNoGCSections("no-gc-sections",
-              cl::desc("disable garbage collection of unused input sections."),
-              cl::init(false));
-
-namespace icf {
-enum Mode {
-  None,
-  All,
-  Safe
-};
-} // namespace of icf
-
-static cl::opt<icf::Mode>
-ArgICF("icf",
-       cl::ZeroOrMore,
-       cl::desc("Identical Code Folding"),
-       cl::init(icf::None),
-       cl::values(
-         clEnumValN(icf::None, "none",
-           "do not perform cold folding"),
-         clEnumValN(icf::All, "all",
-           "always preform cold folding"),
-         clEnumValN(icf::Safe, "safe",
-           "Folds ctors, dtors and functions whose pointers are definitely not taken."),
-         clEnumValEnd));
-
-// FIXME: add this to target options?
-static cl::opt<bool>
-ArgFIXCA8("fix-cortex-a8",
-          cl::desc("Enable Cortex-A8 Thumb-2 branch erratum fix"),
-          cl::init(false));
-
-static cl::opt<bool>
-ArgExportDynamic("export-dynamic",
-                 cl::desc("Export all dynamic symbols"),
-                 cl::init(false));
-
-static cl::alias
-ArgExportDynamicAlias("E",
-                      cl::desc("alias for --export-dynamic"),
-                      cl::aliasopt(ArgExportDynamic));
-
-static cl::opt<std::string>
-ArgEmulation("m",
-             cl::ZeroOrMore,
-             cl::desc("Set GNU linker emulation"),
-             cl::value_desc("emulation"));
-
-static cl::list<std::string, bool, llvm::cl::SearchDirParser>
-ArgRuntimePathLink("rpath-link",
-                   cl::ZeroOrMore,
-                   cl::desc("Add a directory to the link time library search path"),
-                   cl::value_desc("dir"));
-
-static cl::list<std::string>
-ArgExcludeLIBS("exclude-libs",
-               cl::CommaSeparated,
-               cl::desc("Exclude libraries from automatic export"),
-               cl::value_desc("lib1,lib2,..."));
-
-static cl::opt<std::string>
-ArgBuildID("build-id",
-           cl::desc("Request creation of \".note.gnu.build-id\" ELF note section."),
-           cl::value_desc("style"),
-           cl::ValueOptional);
-
-static cl::opt<std::string>
-ArgForceUndefined("u",
-                  cl::desc("Force symbol to be undefined in the output file"),
-                  cl::value_desc("symbol"));
-
-static cl::alias
-ArgForceUndefinedAlias("undefined",
-                       cl::desc("alias for -u"),
-                       cl::aliasopt(ArgForceUndefined));
-
-static cl::opt<std::string>
-ArgVersionScript("version-script",
-                 cl::desc("Version script."),
-                 cl::value_desc("Version script"));
-
-static cl::opt<bool>
-ArgWarnCommon("warn-common",
-              cl::desc("warn common symbol"),
-              cl::init(false));
-
-static cl::opt<mcld::GeneralOptions::HashStyle>
-ArgHashStyle("hash-style", cl::init(mcld::GeneralOptions::SystemV),
-  cl::desc("Set the type of linker's hash table(s)."),
-  cl::values(
-       clEnumValN(mcld::GeneralOptions::SystemV, "sysv",
-                 "classic ELF .hash section"),
-       clEnumValN(mcld::GeneralOptions::GNU, "gnu",
-                 "new style GNU .gnu.hash section"),
-       clEnumValN(mcld::GeneralOptions::Both, "both",
-                 "both the classic ELF and new style GNU hash tables"),
-       clEnumValEnd));
-
-static cl::opt<std::string>
-ArgFilter("F",
-          cl::desc("Filter for shared object symbol table"),
-          cl::value_desc("name"));
-
-static cl::alias
-ArgFilterAlias("filter",
-               cl::desc("alias for -F"),
-               cl::aliasopt(ArgFilterAlias));
-
-static cl::list<std::string>
-ArgAuxiliary("f",
-             cl::ZeroOrMore,
-             cl::desc("Auxiliary filter for shared object symbol table"),
-             cl::value_desc("name"));
-
-static cl::alias
-ArgAuxiliaryAlias("auxiliary",
-                  cl::desc("alias for -f"),
-                  cl::aliasopt(ArgAuxiliary));
-
-static cl::opt<bool>
-ArgUseGold("use-gold",
-          cl::desc("GCC/collect2 compatibility: uses ld.gold.  Ignored"),
-          cl::init(false));
-
-static cl::opt<bool>
-ArgUseMCLD("use-mcld",
-          cl::desc("GCC/collect2 compatibility: uses ld.mcld.  Ignored"),
-          cl::init(false));
-
-static cl::opt<bool>
-ArgUseLD("use-ld",
-          cl::desc("GCC/collect2 compatibility: uses ld.bfd.  Ignored"),
-          cl::init(false));
-
-static cl::opt<bool>
-ArgEB("EB",
-      cl::desc("Link big-endian objects. This affects the default output format."),
-      cl::init(false));
-
-static cl::opt<bool>
-ArgEL("EL",
-      cl::desc("Link little-endian objects. This affects the default output format."),
-      cl::init(false));
-
-static cl::list<std::string>
-ArgPlugin("plugin",
-          cl::desc("Load a plugin library."),
-          cl::value_desc("plugin"));
-
-static cl::list<std::string>
-ArgPluginOpt("plugin-opt",
-             cl::desc("	Pass an option to the plugin."),
-             cl::value_desc("option"));
-
-static cl::opt<bool>
-ArgSVR4Compatibility("Qy",
-                    cl::desc("This option is ignored for SVR4 compatibility"),
-                    cl::init(false));
-
-static cl::list<std::string>
-ArgY("Y",
-     cl::desc("Add path to the default library search path"),
-     cl::value_desc("default-search-path"));
-
-/// @{
-/// @name FIXME: end of unsupported options
-/// @}
-
-static cl::opt<bool>
-ArgNoStdlib("nostdlib",
-            cl::desc("Only search lib dirs explicitly specified on cmdline"),
-            cl::init(false));
-
-static cl::list<std::string, bool, llvm::cl::SearchDirParser>
-ArgRuntimePath("rpath",
-               cl::ZeroOrMore,
-               cl::desc("Add a directory to the runtime library search path"),
-               cl::value_desc("dir"));
-
-static cl::alias
-ArgRuntimePathAlias("R",
-                    cl::desc("alias for --rpath"),
-                    cl::aliasopt(ArgRuntimePath), cl::Prefix);
-
-static cl::opt<bool>
-ArgEnableNewDTags("enable-new-dtags",
-                  cl::desc("Enable use of DT_RUNPATH and DT_FLAGS"),
-                  cl::init(false));
-
-static cl::opt<bool>
-ArgPrintMap("M",
-            cl::desc("Print a link map to the standard output."),
-            cl::init(false));
-
-static cl::alias
-ArgPrintMapAlias("print-map",
-                 cl::desc("alias for -M"),
-                 cl::aliasopt(ArgPrintMap));
-
-static bool ArgFatalWarnings;
-
-static cl::opt<bool, true, cl::FalseParser>
-ArgNoFatalWarnings("no-fatal-warnings",
-              cl::location(ArgFatalWarnings),
-              cl::desc("do not turn warnings into errors"),
-              cl::init(false),
-              cl::ValueDisallowed);
-
-static cl::opt<bool, true>
-ArgFatalWarningsFlag("fatal-warnings",
-              cl::location(ArgFatalWarnings),
-              cl::desc("turn all warnings into errors"),
-              cl::init(false),
-              cl::ValueDisallowed);
-
-static cl::opt<bool>
-ArgWarnSharedTextrel("warn-shared-textrel",
-                     cl::desc("Warn if adding DT_TEXTREL in a shared object."),
-                     cl::init(false));
-
-namespace format {
-enum Format {
-  Binary,
-  Unknown // decided by triple
-};
-} // namespace of format
-
-static cl::opt<format::Format>
-ArgFormat("b",
-  cl::value_desc("Format"),
-  cl::desc("set input format"),
-  cl::init(format::Unknown),
-  cl::values(
-    clEnumValN(format::Binary, "binary",
-      "read in binary machine code."),
-    clEnumValEnd));
-
-static cl::alias
-ArgFormatAlias("format",
-               cl::desc("alias for -b"),
-               cl::aliasopt(ArgFormat));
-
-static cl::opt<format::Format>
-ArgOFormat("oformat",
-  cl::value_desc("Format"),
-  cl::desc("set output format"),
-  cl::init(format::Unknown),
-  cl::values(
-    clEnumValN(format::Binary, "binary",
-      "generate binary machine code."),
-    clEnumValEnd));
-
-static cl::opt<bool>
-ArgDefineCommon("d",
-                cl::ZeroOrMore,
-                cl::desc("Define common symbol"),
-                cl::init(false));
-
-static cl::alias
-ArgDefineCommonAlias1("dc",
-                      cl::ZeroOrMore,
-                      cl::desc("alias for -d"),
-                      cl::aliasopt(ArgDefineCommon));
-
-static cl::alias
-ArgDefineCommonAlias2("dp",
-                      cl::ZeroOrMore,
-                      cl::desc("alias for -d"),
-                      cl::aliasopt(ArgDefineCommon));
-
-//===----------------------------------------------------------------------===//
-// Scripting Options
-//===----------------------------------------------------------------------===//
-static cl::list<std::string>
-ArgWrapList("wrap",
-            cl::ZeroOrMore,
-            cl::desc("Use a wrap function fo symbol."),
-            cl::value_desc("symbol"));
-
-static cl::list<std::string>
-ArgPortList("portable",
-            cl::ZeroOrMore,
-            cl::desc("Use a portable function fo symbol."),
-            cl::value_desc("symbol"));
-
-static cl::list<std::string>
-ArgAddressMapList("section-start",
-                  cl::ZeroOrMore,
-                  cl::desc("Locate a output section at the given absolute address"),
-                  cl::value_desc("Set address of section"),
-                  cl::Prefix);
-
-static cl::list<std::string>
-ArgDefSymList("defsym",
-              cl::ZeroOrMore,
-              cl::desc("Define a symbol"),
-              cl::value_desc("symbol=expression"));
-
-static cl::opt<unsigned long long>
-ArgBssSegAddr("Tbss",
-              cl::desc("Set the address of the bss segment"),
-              cl::init(-1U));
-
-static cl::opt<unsigned long long>
-ArgDataSegAddr("Tdata",
-               cl::desc("Set the address of the data segment"),
-               cl::init(-1U));
-
-static cl::opt<unsigned long long>
-ArgTextSegAddr("Ttext",
-               cl::desc("Set the address of the text segment"),
-               cl::init(-1U));
-
-//===----------------------------------------------------------------------===//
-// non-member functions
-//===----------------------------------------------------------------------===//
-/// GetOutputStream - get the output stream.
-static mcld::ToolOutputFile *GetOutputStream(const char* pTargetName,
-                                             Triple::OSType pOSType,
-                                             mcld::CodeGenFileType pFileType,
-                                             const mcld::sys::fs::Path& pInputFilename,
-                                             mcld::sys::fs::Path& pOutputFilename)
-{
-  if (pOutputFilename.empty()) {
-    if (0 == pInputFilename.native().compare("-"))
-      pOutputFilename.assign("-");
-    else {
-      switch(pFileType) {
-      case mcld::CGFT_ASMFile: {
-        if (0 == pInputFilename.native().compare("-"))
-          pOutputFilename.assign("_out");
-        else
-          pOutputFilename.assign(pInputFilename.stem().native());
-
-        if (0 == strcmp(pTargetName, "c"))
-          pOutputFilename.native() += ".cbe.c";
-        else if (0 == strcmp(pTargetName, "cpp"))
-          pOutputFilename.native() += ".cpp";
-        else
-          pOutputFilename.native() += ".s";
-      }
-      break;
-
-      case mcld::CGFT_OBJFile: {
-        if (0 == pInputFilename.native().compare("-"))
-          pOutputFilename.assign("_out");
-        else
-          pOutputFilename.assign(pInputFilename.stem().native());
-
-        if (pOSType == Triple::Win32)
-          pOutputFilename.native() += ".obj";
-        else
-          pOutputFilename.native() += ".o";
-      }
-      break;
-
-      case mcld::CGFT_PARTIAL: {
-        if (Triple::Win32 == pOSType) {
-          if (0 == pInputFilename.native().compare("-"))
-            pOutputFilename.assign("_out");
-          else
-            pOutputFilename.assign(pInputFilename.stem().native());
-          pOutputFilename.native() += ".obj";
-        }
-        else
-          pOutputFilename.assign("a.out");
-      }
-      break;
-
-      case mcld::CGFT_DSOFile: {
-        if (Triple::Win32 == pOSType) {
-          if (0 == pInputFilename.native().compare("-"))
-            pOutputFilename.assign("_out");
-          else
-            pOutputFilename.assign(pInputFilename.stem().native());
-          pOutputFilename.native() += ".dll";
-        }
-        else
-          pOutputFilename.assign("a.out");
-      }
-      break;
-
-      case mcld::CGFT_EXEFile: {
-        if (Triple::Win32 == pOSType) {
-          if (0 == pInputFilename.native().compare("-"))
-            pOutputFilename.assign("_out");
-          else
-            pOutputFilename.assign(pInputFilename.stem().native());
-          pOutputFilename.native() += ".exe";
-        }
-        else
-          pOutputFilename.assign("a.out");
-      }
-      break;
-
-      case mcld::CGFT_NULLFile:
-        break;
-      default:
-        llvm::report_fatal_error("Unknown output file type.\n");
-      } // end of switch
-    } // end of ! pInputFilename == "-"
-  } // end of if empty pOutputFilename
-
-  mcld::FileHandle::Permission permission;
-  switch (pFileType) {
-  default: assert(0 && "Unknown file type");
-  case mcld::CGFT_ASMFile:
-  case mcld::CGFT_OBJFile:
-  case mcld::CGFT_PARTIAL:
-    permission = mcld::FileHandle::Permission(0x644);
-    break;
-  case mcld::CGFT_DSOFile:
-  case mcld::CGFT_EXEFile:
-  case mcld::CGFT_BINARY:
-  case mcld::CGFT_NULLFile:
-    permission = mcld::FileHandle::Permission(0x755);
-    break;
-  }
-
-  // Open the file.
-  mcld::ToolOutputFile* result_output =
-                      new mcld::ToolOutputFile(pOutputFilename,
-                                                 mcld::FileHandle::ReadWrite |
-                                                 mcld::FileHandle::Create |
-                                                 mcld::FileHandle::Truncate,
-                                               permission);
-
-  return result_output;
-}
-
-/// ParseProgName - Parse program name
-/// This function simplifies cross-compiling by reading triple from the program
-/// name. For example, if the program name is `arm-linux-eabi-ld.mcld', we can
-/// get the triple is arm-linux-eabi by the program name.
-static std::string ParseProgName(const char *progname)
-{
-  static const char *suffixes[] = {
-    "ld",
-    "ld.mcld",
-  };
-
-  std::string ProgName(mcld::sys::fs::Path(progname).stem().native());
-
-  for (size_t i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
-    if (ProgName == suffixes[i])
-      return std::string();
-  }
-
-  StringRef ProgNameRef(ProgName);
-  StringRef Prefix;
-
-  for (size_t i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
-    if (!ProgNameRef.endswith(suffixes[i]))
-      continue;
-
-    StringRef::size_type LastComponent = ProgNameRef.rfind('-',
-      ProgNameRef.size() - strlen(suffixes[i]));
-    if (LastComponent == StringRef::npos)
-      continue;
-    StringRef Prefix = ProgNameRef.slice(0, LastComponent);
-    std::string IgnoredError;
-    if (!llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError))
-      continue;
-    return Prefix.str();
-  }
-  return std::string();
-}
-
-static Triple ParseEmulation(const std::string& pEmulation)
-{
-  Triple result = StringSwitch<Triple>(pEmulation)
-    .Case("armelf_linux_eabi", Triple("arm", "", "linux", "gnueabi"))
-    .Case("elf_i386",          Triple("i386", "", "", "gnu"))
-    .Case("elf_x86_64",        Triple("x86_64", "", "", "gnu"))
-    .Case("elf32_x86_64",      Triple("x86_64", "", "", "gnux32"))
-    .Case("elf_i386_fbsd",     Triple("i386", "", "freebsd", "gnu"))
-    .Case("elf_x86_64_fbsd",   Triple("x86_64", "", "freebsd", "gnu"))
-    .Case("elf32ltsmip",       Triple("mipsel", "", "", "gnu"))
-    .Default(Triple());
-
-  if (result.getArch()        == Triple::UnknownArch &&
-      result.getOS()          == Triple::UnknownOS &&
-      result.getEnvironment() == Triple::UnknownEnvironment)
-    mcld::error(mcld::diag::err_invalid_emulation) << pEmulation << "\n";
-
-  return result;
-}
-
-static bool ShouldColorize()
-{
-   const char* term = getenv("TERM");
-   return term && (0 != strcmp(term, "dumb"));
-}
-
-static bool ProcessLinkerOptionsFromCommand(mcld::LinkerScript& pScript,
-                                            mcld::LinkerConfig& pConfig)
-{
-  // -----  Set up General Options  ----- //
-  // set up colorize
-  switch (ArgColor) {
-    case color::Never:
-      pConfig.options().setColor(false);
-    break;
-    case color::Always:
-      pConfig.options().setColor(true);
-    break;
-    case color::Auto:
-      bool color_option = ShouldColorize() &&
-                 llvm::sys::Process::FileDescriptorIsDisplayed(STDOUT_FILENO);
-      pConfig.options().setColor(color_option);
-    break;
-  }
-
-  mcld::outs().setColor(pConfig.options().color());
-  mcld::errs().setColor(pConfig.options().color());
-
-  // set up soname
-  pConfig.options().setSOName(ArgSOName);
-
-  // add all rpath entries
-  cl::list<std::string>::iterator rp;
-  cl::list<std::string>::iterator rpEnd = ArgRuntimePath.end();
-  for (rp = ArgRuntimePath.begin(); rp != rpEnd; ++rp) {
-    pConfig.options().getRpathList().push_back(*rp);
-  }
-
-  // --fatal-warnings
-  // pConfig.options().setFatalWarnings(ArgFatalWarnings);
-
-  // -shared or -pie
-  if (true == ArgShared || true == ArgPIE) {
-    ArgFileType = mcld::CGFT_DSOFile;
-  }
-  else if (true == ArgRelocatable) {
-    ArgFileType = mcld::CGFT_PARTIAL;
-  }
-  else if (format::Binary == ArgOFormat) {
-    ArgFileType = mcld::CGFT_BINARY;
-  }
-
-  // -b [input-format], --format=[input-format]
-  if (format::Binary == ArgFormat)
-    pConfig.options().setBinaryInput();
-
-  // -V
-  if (ArgVersion) {
-    mcld::outs() << "MCLinker - "
-                 << mcld::LinkerConfig::version()
-                 << "\n";
-  }
-
-  // set up sysroot
-  if (!ArgSysRoot.empty()) {
-    if (exists(ArgSysRoot) && is_directory(ArgSysRoot))
-      pScript.setSysroot(ArgSysRoot);
-  }
-
-  // add all search directories
-  cl::list<std::string>::iterator sd;
-  cl::list<std::string>::iterator sdEnd = ArgSearchDirList.end();
-  for (sd=ArgSearchDirList.begin(); sd!=sdEnd; ++sd) {
-    if (!pScript.directories().insert(*sd)) {
-      // FIXME: need a warning function
-      errs() << "WARNING: can not open search directory `-L"
-             << *sd
-             << "'.\n";
-    }
-  }
-
-  pConfig.options().setPIE(ArgPIE);
-  pConfig.options().setTrace(ArgTrace);
-  pConfig.options().setVerbose(ArgVerbose);
-  pConfig.options().setMaxErrorNum(ArgMaxErrorNum);
-  pConfig.options().setMaxWarnNum(ArgMaxWarnNum);
-  pConfig.options().setEntry(ArgEntry);
-  pConfig.options().setBsymbolic(ArgBsymbolic);
-  pConfig.options().setBgroup(ArgBgroup);
-  pConfig.options().setDyld(ArgDyld);
-  pConfig.options().setNoUndefined(ArgNoUndefined);
-  pConfig.options().setMulDefs(ArgAllowMulDefs);
-  pConfig.options().setEhFrameHdr(ArgEhFrameHdr);
-  pConfig.options().setNMagic(ArgNMagic);
-  pConfig.options().setOMagic(ArgOMagic);
-  pConfig.options().setStripDebug(ArgStripDebug || ArgStripAll);
-  pConfig.options().setExportDynamic(ArgExportDynamic);
-  pConfig.options().setWarnSharedTextrel(ArgWarnSharedTextrel);
-  pConfig.options().setDefineCommon(ArgDefineCommon);
-  pConfig.options().setNewDTags(ArgEnableNewDTags);
-  pConfig.options().setHashStyle(ArgHashStyle);
-  pConfig.options().setNoStdlib(ArgNoStdlib);
-  pConfig.options().setPrintMap(ArgPrintMap);
-  pConfig.options().setGPSize(ArgGPSize);
-
-  if (ArgStripAll)
-    pConfig.options().setStripSymbols(mcld::GeneralOptions::StripAllSymbols);
-  else if (ArgDiscardAll)
-    pConfig.options().setStripSymbols(mcld::GeneralOptions::StripLocals);
-  else if (ArgDiscardLocals)
-    pConfig.options().setStripSymbols(mcld::GeneralOptions::StripTemporaries);
-  else
-    pConfig.options().setStripSymbols(mcld::GeneralOptions::KeepAllSymbols);
-
-  // set up rename map, for --wrap
-  cl::list<std::string>::iterator wname;
-  cl::list<std::string>::iterator wnameEnd = ArgWrapList.end();
-  for (wname = ArgWrapList.begin(); wname != wnameEnd; ++wname) {
-    bool exist = false;
-
-    // add wname -> __wrap_wname
-    mcld::StringEntry<llvm::StringRef>* to_wrap =
-                                     pScript.renameMap().insert(*wname, exist);
-
-    std::string to_wrap_str = "__wrap_" + *wname;
-    to_wrap->setValue(to_wrap_str);
-
-    if (exist)
-      mcld::warning(mcld::diag::rewrap) << *wname << to_wrap_str;
-
-    // add __real_wname -> wname
-    std::string from_real_str = "__real_" + *wname;
-    mcld::StringEntry<llvm::StringRef>* from_real =
-                              pScript.renameMap().insert(from_real_str, exist);
-    from_real->setValue(*wname);
-    if (exist)
-      mcld::warning(mcld::diag::rewrap) << *wname << from_real_str;
-  } // end of for
-
-  // set up rename map, for --portable
-  cl::list<std::string>::iterator pname;
-  cl::list<std::string>::iterator pnameEnd = ArgPortList.end();
-  for (pname = ArgPortList.begin(); pname != pnameEnd; ++pname) {
-    bool exist = false;
-
-    // add pname -> pname_portable
-    mcld::StringEntry<llvm::StringRef>* to_port =
-                                     pScript.renameMap().insert(*pname, exist);
-
-    std::string to_port_str = *pname + "_portable";
-    to_port->setValue(to_port_str);
-
-    if (exist)
-      mcld::warning(mcld::diag::rewrap) << *pname << to_port_str;
-
-    // add __real_pname -> pname
-    std::string from_real_str = "__real_" + *pname;
-    mcld::StringEntry<llvm::StringRef>* from_real =
-                              pScript.renameMap().insert(from_real_str, exist);
-
-    from_real->setValue(*pname);
-    if (exist)
-      mcld::warning(mcld::diag::rewrap) << *pname << from_real_str;
-  } // end of for
-
-  // add -z options
-  cl::list<mcld::ZOption>::iterator zOpt;
-  cl::list<mcld::ZOption>::iterator zOptEnd = ArgZOptionList.end();
-  for (zOpt = ArgZOptionList.begin(); zOpt != zOptEnd; ++zOpt) {
-    pConfig.options().addZOption(*zOpt);
-  }
-
-  if (ArgGCSections) {
-    mcld::warning(mcld::diag::warn_unsupported_option) << ArgGCSections.ArgStr;
-  }
-
-  // set up icf mode
-  switch (ArgICF) {
-    case icf::None:
-      break;
-    case icf::All:
-    case icf::Safe:
-    default:
-      mcld::warning(mcld::diag::warn_unsupported_option) << ArgICF.ArgStr;
-      break;
-  }
-
-  if (ArgFIXCA8) {
-    mcld::warning(mcld::diag::warn_unsupported_option) << ArgFIXCA8.ArgStr;
-  }
-
-  // add address mappings
-  // -Ttext
-  if (-1U != ArgTextSegAddr) {
-    bool exist = false;
-    mcld::StringEntry<uint64_t>* text_mapping =
-                                   pScript.addressMap().insert(".text", exist);
-    text_mapping->setValue(ArgTextSegAddr);
-  }
-  // -Tdata
-  if (-1U != ArgDataSegAddr) {
-    bool exist = false;
-    mcld::StringEntry<uint64_t>* data_mapping =
-                                   pScript.addressMap().insert(".data", exist);
-    data_mapping->setValue(ArgDataSegAddr);
-  }
-  // -Tbss
-  if (-1U != ArgBssSegAddr) {
-    bool exist = false;
-    mcld::StringEntry<uint64_t>* bss_mapping =
-                                    pScript.addressMap().insert(".bss", exist);
-    bss_mapping->setValue(ArgBssSegAddr);
-  }
-  // --section-start SECTION=ADDRESS
-  for (cl::list<std::string>::iterator
-         it = ArgAddressMapList.begin(), ie = ArgAddressMapList.end();
-       it != ie; ++it) {
-    // FIXME: Add a cl::parser
-    size_t pos = (*it).find_last_of('=');
-    llvm::StringRef script(*it);
-    uint64_t address = 0x0;
-    script.substr(pos + 1).getAsInteger(0, address);
-    bool exist = false;
-    mcld::StringEntry<uint64_t>* addr_mapping =
-                     pScript.addressMap().insert(script.substr(0, pos), exist);
-    addr_mapping->setValue(address);
-  }
-
-  // --defsym symbols
-  for (cl::list<std::string>::iterator
-       it = ArgDefSymList.begin(), ie = ArgDefSymList.end();
-       it != ie ; ++it) {
-    llvm::StringRef expression(*it);
-    size_t pos = expression.find_last_of('=');
-    if (pos == expression.size() - 1) {
-      errs() << "defsym option: expression must not end with '='\n";
-      return false;
-    }
-    if (llvm::StringRef::npos == pos) {
-      errs() << "syntax : --defsym symbol=expression\n";
-      return false;
-    }
-    bool exist = false;
-    // FIXME: This will not work with multiple destinations such as
-    // --defsym abc=pqr=expression
-
-    mcld::StringEntry<llvm::StringRef> *defsyms =
-                    pScript.defSymMap().insert(expression.substr(0,pos),exist);
-    defsyms->setValue(expression.substr(pos + 1));
-  }
-
-  // set up filter/aux filter for shared object
-  pConfig.options().setFilter(ArgFilter);
-
-  cl::list<std::string>::iterator aux;
-  cl::list<std::string>::iterator auxEnd = ArgAuxiliary.end();
-  for (aux = ArgAuxiliary.begin(); aux != auxEnd; ++aux)
-    pConfig.options().getAuxiliaryList().push_back(*aux);
-
-  return true;
-}
-
-int main(int argc, char* argv[])
-{
-  sys::PrintStackTraceOnErrorSignal();
-
-  LLVMContext &Context = getGlobalContext();
-  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
-
-  // Initialize targets first, so that --version shows registered targets.
-  InitializeAllTargets();
-  InitializeAllAsmPrinters();
-  InitializeAllAsmParsers();
-  InitializeAllTargetMCs();
-  mcld::InitializeAllTargets();
-  mcld::InitializeAllLinkers();
-  mcld::InitializeAllEmulations();
-  mcld::InitializeAllDiagnostics();
-
-  cl::ParseCommandLineOptions(argc, argv, "MCLinker\n");
-
-#ifdef ENABLE_UNITTEST
-  if (UnitTest) {
-    return unit_test( argc, argv );
-  }
-#endif
-
-  // Load the module to be compiled...
-  std::auto_ptr<llvm::Module> M;
-
-  // Load the module to be linked...
-  mcld::LinkerScript LDScript;
-  mcld::Module LDIRModule(LDScript);
-  mcld::LinkerConfig LDConfig;
-
-  // Process the linker input from the command line
-  if (!ProcessLinkerOptionsFromCommand(LDScript, LDConfig)) {
-    errs() << argv[0] << ": failed to process linker options from command line!\n";
-    return 1;
-  }
-
-  if (ArgBitcodeFilename.empty() &&
-      (mcld::CGFT_DSOFile != ArgFileType &&
-       mcld::CGFT_EXEFile != ArgFileType &&
-       mcld::CGFT_PARTIAL != ArgFileType &&
-       mcld::CGFT_BINARY  != ArgFileType)) {
-    // If the file is not given, forcefully read from stdin
-    if (ArgVerbose >= 0) {
-      errs() << "** The bitcode/llvm asm file is not given. Read from stdin.\n"
-             << "** Specify input bitcode/llvm asm file by\n\n"
-             << "          llvm-mcld -dB [the bitcode/llvm asm]\n\n";
-    }
-
-    ArgBitcodeFilename.assign("-");
-  }
-
-  if (!ArgBitcodeFilename.empty()) {
-    SMDiagnostic Err;
-    M.reset(ParseIRFile(ArgBitcodeFilename.native(), Err, Context));
-
-    if (M.get() == 0) {
-      Err.print(argv[0], errs());
-      errs() << "** Failed to to the given bitcode/llvm asm file '"
-             << ArgBitcodeFilename.native() << "'. **\n";
-      return 1;
-    }
-  }
-  else {
-    // If here, output must be dynamic shared object (mcld::CGFT_DSOFile) and
-    // executable file (mcld::CGFT_EXEFile).
-    M.reset(new Module("Empty Module", Context));
-  }
-  Module &mod = *M.get();
-
-  // If we are supposed to override the target triple, do so now.
-  Triple TheTriple;
-  if (!TargetTriple.empty()) {
-    // 1. Use the triple from command.
-    TheTriple.setTriple(TargetTriple);
-    mod.setTargetTriple(TargetTriple);
-  } else if (!mod.getTargetTriple().empty()) {
-    // 2. Use the triple in the input Module.
-    TheTriple.setTriple(mod.getTargetTriple());
-  } else {
-    std::string ProgNameTriple = ParseProgName(argv[0]);
-    if (!ProgNameTriple.empty()) {
-      // 3. Use the triple from the program name prefix.
-      TheTriple.setTriple(ProgNameTriple);
-      mod.setTargetTriple(ProgNameTriple);
-    } else {
-      // 4. Use the default target triple.
-      TheTriple.setTriple(mcld::sys::getDefaultTargetTriple());
-      if (!ArgEmulation.empty()) {
-        // Process target emulation.
-        Triple EmulationTriple = ParseEmulation(ArgEmulation);
-        if (EmulationTriple.getArch() != Triple::UnknownArch)
-          TheTriple.setArch(EmulationTriple.getArch());
-        if (EmulationTriple.getOS() != Triple::UnknownOS)
-          TheTriple.setOS(EmulationTriple.getOS());
-        if (EmulationTriple.getEnvironment() != Triple::UnknownEnvironment)
-          TheTriple.setEnvironment(EmulationTriple.getEnvironment());
-      }
-    }
-  }
-
-  // Allocate target machine.  First, check whether the user has explicitly
-  // specified an architecture to compile for. If so we have to look it up by
-  // name, because it might be a backend that has no mapping to a target triple.
-  const mcld::Target *TheTarget = 0;
-  if (!MArch.empty()) {
-    for (mcld::TargetRegistry::iterator it = mcld::TargetRegistry::begin(),
-           ie = mcld::TargetRegistry::end(); it != ie; ++it) {
-      if (MArch == (*it)->get()->getName()) {
-        TheTarget = *it;
-        break;
-      }
-    }
-
-    if (!TheTarget) {
-      errs() << argv[0] << ": error: invalid target '" << MArch << "'.\n";
-      return 1;
-    }
-
-    // Adjust the triple to match (if known), otherwise stick with the
-    // module/host triple.
-    Triple::ArchType Type = Triple::getArchTypeForLLVMName(MArch);
-    if (Type != Triple::UnknownArch)
-      TheTriple.setArch(Type);
-  }
-  else {
-    std::string Err;
-    TheTarget = mcld::TargetRegistry::lookupTarget(TheTriple.getTriple(), Err);
-    if (TheTarget == 0) {
-      errs() << "error: auto-selecting target `" << TheTriple.getTriple()
-             << "'\n"
-             << "Please use the -march option to explicitly select a target.\n"
-             << "Example:\n"
-             << "  $ " << argv[0] << " -march=arm\n";
-      return 1;
-    }
-  }
-  // Set up mcld::LinkerConfig
-  LDConfig.targets().setTriple(TheTriple);
-
-  // Package up features to be passed to target/subtarget
-  std::string FeaturesStr;
-  if (MAttrs.size()) {
-    SubtargetFeatures Features;
-    for (unsigned i = 0; i != MAttrs.size(); ++i)
-      Features.AddFeature(MAttrs[i]);
-    FeaturesStr = Features.getString();
-  }
-
-  CodeGenOpt::Level OLvl = CodeGenOpt::Default;
-  switch (OptLevel) {
-  default:
-    errs() << argv[0] << ": invalid optimization level.\n";
-    return 1;
-  case ' ': break;
-  case '0': OLvl = CodeGenOpt::None; break;
-  case '1': OLvl = CodeGenOpt::Less; break;
-  case '2': OLvl = CodeGenOpt::Default; break;
-  case '3': OLvl = CodeGenOpt::Aggressive; break;
-  }
-
-  // set -fPIC
-  if (ArgFPIC)
-    ArgRelocModel = Reloc::PIC_;
-
-  TargetOptions Options;
-  Options.LessPreciseFPMADOption = EnableFPMAD;
-  Options.NoFramePointerElim = DisableFPElim;
-  Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf;
-  Options.AllowFPOpFusion = FuseFPOps;
-  Options.UnsafeFPMath = EnableUnsafeFPMath;
-  Options.NoInfsFPMath = EnableNoInfsFPMath;
-  Options.NoNaNsFPMath = EnableNoNaNsFPMath;
-  Options.HonorSignDependentRoundingFPMathOption =
-      EnableHonorSignDependentRoundingFPMath;
-  Options.UseSoftFloat = GenerateSoftFloatCalls;
-  if (FloatABIForCalls != FloatABI::Default)
-    Options.FloatABIType = FloatABIForCalls;
-  Options.NoZerosInBSS = DontPlaceZerosInBSS;
-  Options.JITExceptionHandling = EnableJITExceptionHandling;
-  Options.JITEmitDebugInfo = EmitJitDebugInfo;
-  Options.JITEmitDebugInfoToDisk = EmitJitDebugInfoToDisk;
-  Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt;
-  Options.StackAlignmentOverride = OverrideStackAlignment;
-  Options.RealignStack = EnableRealignStack;
-  Options.TrapFuncName = TrapFuncName;
-  Options.EnableSegmentedStacks = SegmentedStacks;
-
-  std::auto_ptr<mcld::MCLDTargetMachine> target_machine(
-          TheTarget->createTargetMachine(TheTriple.getTriple(),
-                                         MCPU, FeaturesStr, Options,
-                                         ArgRelocModel, CMModel, OLvl));
-  assert(target_machine.get() && "Could not allocate target machine!");
-  mcld::MCLDTargetMachine &TheTargetMachine = *target_machine.get();
-
-  LDConfig.targets().setTargetCPU(MCPU);
-  LDConfig.targets().setTargetFeatureString(FeaturesStr);
-
-  TheTargetMachine.getTM().setMCUseLoc(false);
-  TheTargetMachine.getTM().setMCUseCFI(false);
-
-  // FIXME: Move the initialization of LineInfo to mcld::Linker when we
-  // finish LineInfo's implementation.
-  OwningPtr<mcld::DiagnosticLineInfo>
-    diag_line_info(TheTarget->createDiagnosticLineInfo(*TheTarget,
-                                                       TheTriple.getTriple()));
-
-  mcld::getDiagnosticEngine().setLineInfo(*diag_line_info.take());
-
-  // Figure out where we are going to send the output...
-  OwningPtr<mcld::ToolOutputFile>
-  Out(GetOutputStream(TheTarget->get()->getName(),
-                      TheTriple.getOS(),
-                      ArgFileType,
-                      ArgBitcodeFilename,
-                      ArgOutputFilename));
-  if (!Out) {
-    // FIXME: show some error message pls.
-    return 1;
-  }
-
-  // Build up all of the passes that we want to do to the module.
-  PassManager PM;
-
-  // Add the data layout from the target machine, if it exists, or the module.
-  if (const DataLayout *DL = TheTargetMachine.getTM().getDataLayout())
-    PM.add(new DataLayout(*DL));
-   else
-    PM.add(new DataLayout(&mod));
-
-  // Override default to generate verbose assembly.
-  TheTargetMachine.getTM().setAsmVerbosityDefault(true);
-
-  {
-    // Ask the target to add backend passes as necessary.
-    if( TheTargetMachine.addPassesToEmitFile(PM,
-                                             *Out,
-                                             ArgFileType,
-                                             OLvl,
-                                             LDIRModule,
-                                             LDConfig,
-                                             NoVerify)) {
-      errs() << argv[0] << ": target does not support generation of this"
-             << " file type!\n";
-      return 1;
-    }
-
-    // Before executing passes, print the final values of the LLVM options.
-    cl::PrintOptionValues();
-
-    PM.run(mod);
-  }
-
-  if (mcld::getDiagnosticEngine().getPrinter()->getNumErrors())
-    return 1;
-
-  // Declare success.
-  Out->keep();
-  return 0;
-}
diff --git a/tools/mcld/include/mcld/OptimizationOptions.h b/tools/mcld/include/mcld/OptimizationOptions.h
index 485e732..5385f91 100644
--- a/tools/mcld/include/mcld/OptimizationOptions.h
+++ b/tools/mcld/include/mcld/OptimizationOptions.h
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 #ifndef MCLD_LDLITE_OPTIMIZATION_OPTIONS_H
 #define MCLD_LDLITE_OPTIMIZATION_OPTIONS_H
+#include <mcld/GeneralOptions.h>
 #include <llvm/Support/CommandLine.h>
 #include <string>
 
@@ -18,21 +19,17 @@
 class OptimizationOptions
 {
 public:
-  enum ICF {
-    ICF_None,
-    ICF_All,
-    ICF_Safe
-  };
-
-public:
   OptimizationOptions();
 
   bool parse(LinkerConfig& pConfig);
 
 private:
   bool& m_GCSections;
+  bool& m_PrintGCSections;
   bool& m_GenUnwindInfo;
-  llvm::cl::opt<ICF>& m_ICF;
+  llvm::cl::opt<mcld::GeneralOptions::ICF>& m_ICF;
+  llvm::cl::opt<unsigned>& m_ICFIterations;
+  llvm::cl::opt<bool>& m_PrintICFSections;
   llvm::cl::opt<char>& m_OptLevel;
   llvm::cl::list<std::string>& m_Plugin;
   llvm::cl::list<std::string>& m_PluginOpt;
diff --git a/tools/mcld/include/mcld/SymbolOptions.h b/tools/mcld/include/mcld/SymbolOptions.h
index b7c16f7..60f5e06 100644
--- a/tools/mcld/include/mcld/SymbolOptions.h
+++ b/tools/mcld/include/mcld/SymbolOptions.h
@@ -24,7 +24,7 @@
 
 private:
   // not supported yet
-  llvm::cl::opt<std::string>& m_ForceUndefined;
+  llvm::cl::list<std::string>& m_ForceUndefined;
   llvm::cl::opt<std::string>& m_VersionScript;
   llvm::cl::opt<bool>& m_WarnCommon;
   llvm::cl::opt<bool>& m_DefineCommon;
diff --git a/tools/mcld/lib/DynamicSectionOptions.cpp b/tools/mcld/lib/DynamicSectionOptions.cpp
index 415bdc8..5ceeaef 100644
--- a/tools/mcld/lib/DynamicSectionOptions.cpp
+++ b/tools/mcld/lib/DynamicSectionOptions.cpp
@@ -75,7 +75,7 @@
 
 llvm::cl::alias ArgFilterAlias("filter",
   llvm::cl::desc("alias for -F"),
-  llvm::cl::aliasopt(ArgFilterAlias));
+  llvm::cl::aliasopt(ArgFilter));
 
 // } Not supported yet
 
diff --git a/tools/mcld/lib/OptimizationOptions.cpp b/tools/mcld/lib/OptimizationOptions.cpp
index 7eca773..9de70f4 100644
--- a/tools/mcld/lib/OptimizationOptions.cpp
+++ b/tools/mcld/lib/OptimizationOptions.cpp
@@ -13,7 +13,6 @@
 
 namespace {
 
-// Not supported yet
 bool ArgGCSections;
 
 llvm::cl::opt<bool, true> ArgGCSectionsFlag("gc-sections",
@@ -28,6 +27,20 @@
   llvm::cl::desc("disable garbage collection of unused input sections."),
   llvm::cl::init(false));
 
+bool ArgPrintGCSections;
+
+llvm::cl::opt<bool, true> ArgPrintGCSectionsFlag("print-gc-sections",
+  llvm::cl::ZeroOrMore,
+  llvm::cl::location(ArgPrintGCSections),
+  llvm::cl::desc("List all sections removed by garbage collection."),
+  llvm::cl::init(false));
+
+llvm::cl::opt<bool, true, llvm::cl::FalseParser> ArgNoPrintGCSectionsFlag("no-print-gc-sections",
+  llvm::cl::ZeroOrMore,
+  llvm::cl::location(ArgPrintGCSections),
+  llvm::cl::desc("disable --print-gc-sections"),
+  llvm::cl::init(false));
+
 bool ArgGenUnwindInfo;
 
 llvm::cl::opt<bool, true, llvm::cl::FalseParser>
@@ -47,19 +60,27 @@
                      llvm::cl::init(true),
                      llvm::cl::ValueDisallowed);
 
-llvm::cl::opt<mcld::OptimizationOptions::ICF> ArgICF("icf",
+llvm::cl::opt<mcld::GeneralOptions::ICF> ArgICF("icf",
   llvm::cl::ZeroOrMore,
   llvm::cl::desc("Identical Code Folding"),
-  llvm::cl::init(mcld::OptimizationOptions::ICF_None),
+  llvm::cl::init(mcld::GeneralOptions::ICF_None),
   llvm::cl::values(
-    clEnumValN(mcld::OptimizationOptions::ICF_None, "none",
+    clEnumValN(mcld::GeneralOptions::ICF_None, "none",
       "do not perform cold folding"),
-    clEnumValN(mcld::OptimizationOptions::ICF_All, "all",
+    clEnumValN(mcld::GeneralOptions::ICF_All, "all",
       "always preform cold folding"),
-    clEnumValN(mcld::OptimizationOptions::ICF_Safe, "safe",
+    clEnumValN(mcld::GeneralOptions::ICF_Safe, "safe",
       "Folds those whose pointers are definitely not taken."),
     clEnumValEnd));
 
+llvm::cl::opt<unsigned> ArgICFIterations("icf-iterations",
+  llvm::cl::desc("Number of iterations to do ICF."),
+  llvm::cl::init(2));
+
+llvm::cl::opt<bool> ArgPrintICFSections("print-icf-sections",
+  llvm::cl::desc("Print the folded identical sections."),
+  llvm::cl::init(false));
+
 llvm::cl::opt<char> ArgOptLevel("O",
   llvm::cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
                  "(default = '-O2')"),
@@ -84,8 +105,11 @@
 //===----------------------------------------------------------------------===//
 OptimizationOptions::OptimizationOptions()
   : m_GCSections(ArgGCSections),
+    m_PrintGCSections(ArgPrintGCSections),
     m_GenUnwindInfo(ArgGenUnwindInfo),
     m_ICF(ArgICF),
+    m_ICFIterations(ArgICFIterations),
+    m_PrintICFSections(ArgPrintICFSections),
     m_OptLevel(ArgOptLevel),
     m_Plugin(ArgPlugin),
     m_PluginOpt(ArgPluginOpt) {
@@ -97,19 +121,17 @@
   if (m_GCSections)
     pConfig.options().setGCSections();
 
+  // set --print-gc-sections
+  if (m_PrintGCSections)
+    pConfig.options().setPrintGCSections();
+
   // set --ld-generated-unwind-info (or not)
   pConfig.options().setGenUnwindInfo(m_GenUnwindInfo);
 
   // set --icf [mode]
-  switch (m_ICF) {
-    case ICF_None:
-      break;
-    case ICF_All:
-    case ICF_Safe:
-    default:
-      warning(mcld::diag::warn_unsupported_option) << m_ICF.ArgStr;
-      break;
-  }
+  pConfig.options().setICFMode(m_ICF);
+  pConfig.options().setICFIterations(m_ICFIterations);
+  pConfig.options().setPrintICFSections(m_PrintICFSections);
 
   return true;
 }
diff --git a/tools/mcld/lib/OutputFormatOptions.cpp b/tools/mcld/lib/OutputFormatOptions.cpp
index 5a148ee..87a3638 100644
--- a/tools/mcld/lib/OutputFormatOptions.cpp
+++ b/tools/mcld/lib/OutputFormatOptions.cpp
@@ -228,6 +228,14 @@
   pConfig.options().setOMagic(m_OMagic);
   pConfig.options().setHashStyle(m_HashStyle);
   pConfig.options().setExportDynamic(m_ExportDynamic);
+
+  // --exclude-libs
+  llvm::cl::list<std::string>::iterator exclude,
+                                        excludeEnd = m_ExcludeLIBS.end();
+  for (exclude = m_ExcludeLIBS.begin(); exclude != excludeEnd; ++exclude) {
+    pConfig.options().excludeLIBS().insert(*exclude);
+  }
+
   if (m_NoWarnMismatch)
     pConfig.options().setWarnMismatch(false);
   else
@@ -299,5 +307,3 @@
   pModule.setName(output_filename);
   return true;
 }
-
-
diff --git a/tools/mcld/lib/PreferenceOptions.cpp b/tools/mcld/lib/PreferenceOptions.cpp
index 4fc6445..e5fa3df 100644
--- a/tools/mcld/lib/PreferenceOptions.cpp
+++ b/tools/mcld/lib/PreferenceOptions.cpp
@@ -91,17 +91,13 @@
   llvm::cl::init(false),
   llvm::cl::ValueDisallowed);
 
-llvm::cl::opt<bool> ArgUseGold("use-gold",
-  llvm::cl::desc("GCC/collect2 compatibility: uses ld.gold.  Ignored"),
-  llvm::cl::init(false));
+llvm::cl::opt<std::string> ArgUseLD("fuse-ld",
+  llvm::cl::desc("Ignored for GCC/collect2 linker compatibility."),
+  llvm::cl::init("mcld"));
 
-llvm::cl::opt<bool> ArgUseMCLD("use-mcld",
-  llvm::cl::desc("GCC/collect2 compatibility: uses ld.mcld.  Ignored"),
-  llvm::cl::init(false));
-
-llvm::cl::opt<bool> ArgUseLD("use-ld",
-  llvm::cl::desc("GCC/collect2 compatibility: uses ld.bfd.  Ignored"),
-  llvm::cl::init(false));
+llvm::cl::opt<std::string> ArgUseMCLD("use-mcld",
+  llvm::cl::desc("Ignored for GCC/collect2 linker compatibility."),
+  llvm::cl::init("mcld"));
 
 //===----------------------------------------------------------------------===//
 // Non-member functions
diff --git a/tools/mcld/lib/SymbolOptions.cpp b/tools/mcld/lib/SymbolOptions.cpp
index 66b52f6..4de764a 100644
--- a/tools/mcld/lib/SymbolOptions.cpp
+++ b/tools/mcld/lib/SymbolOptions.cpp
@@ -12,11 +12,13 @@
 namespace {
 
 // Not supprted yet {
-llvm::cl::opt<std::string> ArgForceUndefined("u",
+llvm::cl::list<std::string> ArgForceUndefined("u",
+  llvm::cl::ZeroOrMore,
   llvm::cl::desc("Force symbol to be undefined in the output file"),
   llvm::cl::value_desc("symbol"));
 
 llvm::cl::alias ArgForceUndefinedAlias("undefined",
+  llvm::cl::ZeroOrMore,
   llvm::cl::desc("alias for -u"),
   llvm::cl::aliasopt(ArgForceUndefined));
 
@@ -64,6 +66,11 @@
   // set -d
   pConfig.options().setDefineCommon(m_DefineCommon);
 
+  // set -u/--undefined symbols
+  llvm::cl::list<std::string>::iterator usym, usymEnd = m_ForceUndefined.end();
+  for (usym = m_ForceUndefined.begin(); usym != usymEnd; ++usym)
+    pConfig.options().getUndefSymList().push_back(*usym);
+
   return true;
 }