Linkloader improvement: mclinker.

Change-Id: I8805e39ccbc2ee204234fb3e71c70c906f3990bb
diff --git a/lib/Target/Mips/MipsLDBackend.cpp b/lib/Target/Mips/MipsLDBackend.cpp
new file mode 100644
index 0000000..c7a6b23
--- /dev/null
+++ b/lib/Target/Mips/MipsLDBackend.cpp
@@ -0,0 +1,894 @@
+//===- MipsLDBackend.cpp --------------------------------------------------===//
+//
+//                     The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <llvm/ADT/Triple.h>
+#include <llvm/Support/ELF.h>
+
+#include <mcld/LD/SectionMap.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/Target/OutputRelocSection.h>
+
+#include "Mips.h"
+#include "MipsELFDynamic.h"
+#include "MipsLDBackend.h"
+#include "MipsRelocationFactory.h"
+
+enum {
+  // The original o32 abi.
+  E_MIPS_ABI_O32    = 0x00001000,
+  // O32 extended to work on 64 bit architectures.
+  E_MIPS_ABI_O64    = 0x00002000,
+  // EABI in 32 bit mode.
+  E_MIPS_ABI_EABI32 = 0x00003000,
+  // EABI in 64 bit mode.
+  E_MIPS_ABI_EABI64 = 0x00004000
+};
+
+namespace mcld {
+
+MipsGNULDBackend::MipsGNULDBackend()
+  : m_pRelocFactory(NULL),
+    m_pGOT(NULL),
+    m_pRelDyn(NULL),
+    m_pDynamic(NULL),
+    m_pGOTSymbol(NULL),
+    m_pGpDispSymbol(NULL)
+{
+}
+
+MipsGNULDBackend::~MipsGNULDBackend()
+{
+  if (NULL != m_pRelocFactory)
+    delete m_pRelocFactory;
+  if (NULL != m_pGOT)
+    delete m_pGOT;
+  if (NULL != m_pRelDyn)
+    delete m_pRelDyn;
+  if (NULL != m_pDynamic)
+    delete m_pDynamic;
+}
+
+bool MipsGNULDBackend::initTargetSectionMap(SectionMap& pSectionMap)
+{
+  // Nothing to do because we do not support
+  // any MIPS specific sections now.
+  return true;
+}
+
+void MipsGNULDBackend::initTargetSections(MCLinker& pLinker)
+{
+  // Nothing to do because we do not support
+  // any MIPS specific sections now.
+}
+
+void MipsGNULDBackend::initTargetSymbols(MCLinker& pLinker)
+{
+  // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
+  // same name in input
+  m_pGOTSymbol = pLinker.defineSymbol<MCLinker::AsRefered, MCLinker::Resolve>(
+                   "_GLOBAL_OFFSET_TABLE_",
+                   false,
+                   ResolveInfo::Object,
+                   ResolveInfo::Define,
+                   ResolveInfo::Local,
+                   0x0,  // size
+                   0x0,  // value
+                   NULL, // FragRef
+                   ResolveInfo::Hidden);
+
+  m_pGpDispSymbol = pLinker.defineSymbol<MCLinker::AsRefered, MCLinker::Resolve>(
+                   "_gp_disp",
+                   false,
+                   ResolveInfo::Section,
+                   ResolveInfo::Define,
+                   ResolveInfo::Absolute,
+                   0x0,  // size
+                   0x0,  // value
+                   NULL, // FragRef
+                   ResolveInfo::Default);
+
+  if (NULL != m_pGpDispSymbol) {
+    m_pGpDispSymbol->resolveInfo()->setReserved(ReserveGpDisp);
+  }
+}
+
+bool MipsGNULDBackend::initRelocFactory(const MCLinker& pLinker)
+{
+  if (NULL == m_pRelocFactory) {
+    m_pRelocFactory = new MipsRelocationFactory(1024, *this);
+    m_pRelocFactory->setLayout(pLinker.getLayout());
+  }
+  return true;
+}
+
+RelocationFactory* MipsGNULDBackend::getRelocFactory()
+{
+  assert(NULL != m_pRelocFactory);
+  return m_pRelocFactory;
+}
+
+void MipsGNULDBackend::scanRelocation(Relocation& pReloc,
+                                      const LDSymbol& pInputSym,
+                                      MCLinker& pLinker,
+                                      const MCLDInfo& pLDInfo,
+                                      const Output& pOutput)
+{
+  // rsym - The relocation target symbol
+  ResolveInfo* rsym = pReloc.symInfo();
+  assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
+
+  // A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies
+  // that a .got section is needed.
+  if (NULL == m_pGOT && NULL != m_pGOTSymbol) {
+    if (rsym == m_pGOTSymbol->resolveInfo()) {
+      createGOT(pLinker, pOutput);
+    }
+  }
+
+  if (rsym->isLocal())
+    scanLocalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
+  else
+    scanGlobalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
+}
+
+uint32_t MipsGNULDBackend::machine() const
+{
+  return llvm::ELF::EM_MIPS;
+}
+
+uint8_t MipsGNULDBackend::OSABI() const
+{
+  return llvm::ELF::ELFOSABI_NONE;
+}
+
+uint8_t MipsGNULDBackend::ABIVersion() const
+{
+  return 0;
+}
+
+uint64_t MipsGNULDBackend::flags() const
+{
+  // TODO: (simon) The correct flag's set depend on command line
+  // arguments and flags from input .o files.
+  return llvm::ELF::EF_MIPS_ARCH_32R2 |
+         llvm::ELF::EF_MIPS_NOREORDER |
+         llvm::ELF::EF_MIPS_PIC |
+         llvm::ELF::EF_MIPS_CPIC |
+         E_MIPS_ABI_O32;
+}
+
+bool MipsGNULDBackend::isLittleEndian() const
+{
+  // Now we support little endian (mipsel) target only.
+  return true;
+}
+
+unsigned int MipsGNULDBackend::bitclass() const
+{
+  return 32;
+}
+
+void MipsGNULDBackend::doPreLayout(const Output& pOutput,
+                                   const MCLDInfo& pInfo,
+                                   MCLinker& pLinker)
+{
+  // when building shared object, the .got section is must.
+  if (pOutput.type() == Output::DynObj && NULL == m_pGOT) {
+      createGOT(pLinker, pOutput);
+  }
+}
+
+void MipsGNULDBackend::doPostLayout(const Output& pOutput,
+                                    const MCLDInfo& pInfo,
+                                    MCLinker& pLinker)
+{
+  // emit program headers
+  if (pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec)
+    emitProgramHdrs(pLinker.getLDInfo().output());
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+MipsELFDynamic& MipsGNULDBackend::dynamic()
+{
+  if (NULL == m_pDynamic)
+    m_pDynamic = new MipsELFDynamic(*this);
+
+  return *m_pDynamic;
+}
+
+/// dynamic - the dynamic section of the target machine.
+/// Use co-variant return type to return its own dynamic section.
+const MipsELFDynamic& MipsGNULDBackend::dynamic() const
+{
+  assert( NULL != m_pDynamic);
+  return *m_pDynamic;
+}
+
+uint64_t MipsGNULDBackend::emitSectionData(const Output& pOutput,
+                                           const LDSection& pSection,
+                                           const MCLDInfo& pInfo,
+                                           MemoryRegion& pRegion) const
+{
+  assert(pRegion.size() && "Size of MemoryRegion is zero!");
+
+  ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+  if (&pSection == &(file_format->getGOT())) {
+    assert(NULL != m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
+    uint64_t result = m_pGOT->emit(pRegion);
+    return result;
+  }
+
+  llvm::report_fatal_error(llvm::Twine("Unable to emit section `") +
+                           pSection.name() +
+                           llvm::Twine("'.\n"));
+  return 0;
+}
+/// isGOTSymbol - return true if the symbol is the GOT entry.
+bool MipsGNULDBackend::isGOTSymbol(const LDSymbol& pSymbol) const
+{
+  return std::find(m_LocalGOTSyms.begin(),
+                   m_LocalGOTSyms.end(), &pSymbol) != m_LocalGOTSyms.end() ||
+         std::find(m_GlobalGOTSyms.begin(),
+                   m_GlobalGOTSyms.end(), &pSymbol) != m_GlobalGOTSyms.end();
+}
+
+/// emitDynamicSymbol - emit dynamic symbol.
+void MipsGNULDBackend::emitDynamicSymbol(llvm::ELF::Elf32_Sym& sym32,
+                                         Output& pOutput,
+                                         LDSymbol& pSymbol,
+                                         const Layout& pLayout,
+                                         char* strtab,
+                                         size_t strtabsize,
+                                         size_t symtabIdx)
+{
+  // maintain output's symbol and index map
+  bool sym_exist = false;
+  HashTableType::entry_type* entry = 0;
+  entry = m_pSymIndexMap->insert(&pSymbol, sym_exist);
+  entry->setValue(symtabIdx);
+
+  // FIXME: check the endian between host and target
+  // write out symbol
+  sym32.st_name  = strtabsize;
+  sym32.st_value = pSymbol.value();
+  sym32.st_size  = getSymbolSize(pSymbol);
+  sym32.st_info  = getSymbolInfo(pSymbol);
+  sym32.st_other = pSymbol.visibility();
+  sym32.st_shndx = getSymbolShndx(pSymbol, pLayout);
+  // write out string
+  strcpy((strtab + strtabsize), pSymbol.name());
+}
+
+/// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
+///
+/// the size of these tables should be computed before layout
+/// layout should computes the start offset of these tables
+void MipsGNULDBackend::emitDynNamePools(Output& pOutput,
+                                        SymbolCategory& pSymbols,
+                                        const Layout& pLayout,
+                                        const MCLDInfo& pLDInfo)
+{
+  assert(pOutput.hasMemArea());
+  ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+  LDSection& symtab_sect = file_format->getDynSymTab();
+  LDSection& strtab_sect = file_format->getDynStrTab();
+  LDSection& hash_sect   = file_format->getHashTab();
+  LDSection& dyn_sect    = file_format->getDynamic();
+
+  MemoryRegion* symtab_region = pOutput.memArea()->request(symtab_sect.offset(),
+                                                           symtab_sect.size());
+  MemoryRegion* strtab_region = pOutput.memArea()->request(strtab_sect.offset(),
+                                                           strtab_sect.size());
+  MemoryRegion* hash_region = pOutput.memArea()->request(hash_sect.offset(),
+                                                         hash_sect.size());
+  MemoryRegion* dyn_region = pOutput.memArea()->request(dyn_sect.offset(),
+                                                        dyn_sect.size());
+  // set up symtab_region
+  llvm::ELF::Elf32_Sym* symtab32 = NULL;
+  symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region->start();
+
+  symtab32[0].st_name  = 0;
+  symtab32[0].st_value = 0;
+  symtab32[0].st_size  = 0;
+  symtab32[0].st_info  = 0;
+  symtab32[0].st_other = 0;
+  symtab32[0].st_shndx = 0;
+
+  // set up strtab_region
+  char* strtab = (char*)strtab_region->start();
+  strtab[0] = '\0';
+
+  bool sym_exist = false;
+  HashTableType::entry_type* entry = 0;
+
+  // add index 0 symbol into SymIndexMap
+  entry = m_pSymIndexMap->insert(NULL, sym_exist);
+  entry->setValue(0);
+
+  size_t symtabIdx = 1;
+  size_t strtabsize = 1;
+
+  // emit of .dynsym, and .dynstr except GOT entries
+  for (SymbolCategory::iterator symbol = pSymbols.begin(),
+       sym_end = pSymbols.end(); symbol != sym_end; ++symbol) {
+    if (!isDynamicSymbol(**symbol, pOutput))
+      continue;
+
+    if (isGOTSymbol(**symbol))
+      continue;
+
+    emitDynamicSymbol(symtab32[symtabIdx], pOutput, **symbol, pLayout, strtab,
+                      strtabsize, symtabIdx);
+
+    // sum up counters
+    ++symtabIdx;
+    strtabsize += (*symbol)->nameSize() + 1;
+  }
+
+  // emit global GOT
+  for (std::vector<LDSymbol*>::const_iterator symbol = m_GlobalGOTSyms.begin(),
+       symbol_end = m_GlobalGOTSyms.end();
+       symbol != symbol_end; ++symbol) {
+
+    emitDynamicSymbol(symtab32[symtabIdx], pOutput, **symbol, pLayout, strtab,
+                      strtabsize, symtabIdx);
+
+    // sum up counters
+    ++symtabIdx;
+    strtabsize += (*symbol)->nameSize() + 1;
+  }
+
+  // emit DT_NEED
+  // add DT_NEED strings into .dynstr
+  // Rules:
+  //   1. ignore --no-add-needed
+  //   2. force count in --no-as-needed
+  //   3. judge --as-needed
+  ELFDynamic::iterator dt_need = dynamic().needBegin();
+  InputTree::const_bfs_iterator input, inputEnd = pLDInfo.inputs().bfs_end();
+  for (input = pLDInfo.inputs().bfs_begin(); input != inputEnd; ++input) {
+    if (Input::DynObj == (*input)->type()) {
+      // --add-needed
+      if ((*input)->attribute()->isAddNeeded()) {
+        // --no-as-needed
+        if (!(*input)->attribute()->isAsNeeded()) {
+          strcpy((strtab + strtabsize), (*input)->name().c_str());
+          (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
+          strtabsize += (*input)->name().size() + 1;
+          ++dt_need;
+        }
+        // --as-needed
+        else if ((*input)->isNeeded()) {
+          strcpy((strtab + strtabsize), (*input)->name().c_str());
+          (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
+          strtabsize += (*input)->name().size() + 1;
+          ++dt_need;
+        }
+      }
+    }
+  } // for
+
+  // emit soname
+  // initialize value of ELF .dynamic section
+  dynamic().applySoname(strtabsize);
+  dynamic().applyEntries(pLDInfo, *file_format);
+  dynamic().emit(dyn_sect, *dyn_region);
+
+  strcpy((strtab + strtabsize), pOutput.name().c_str());
+  strtabsize += pOutput.name().size() + 1;
+
+  // emit hash table
+  // FIXME: this verion only emit SVR4 hash section.
+  //        Please add GNU new hash section
+
+  // both 32 and 64 bits hash table use 32-bit entry
+  // set up hash_region
+  uint32_t* word_array = (uint32_t*)hash_region->start();
+  uint32_t& nbucket = word_array[0];
+  uint32_t& nchain  = word_array[1];
+
+  nbucket = getHashBucketCount(symtabIdx, false);
+  nchain  = symtabIdx;
+
+  uint32_t* bucket = (word_array + 2);
+  uint32_t* chain  = (bucket + nbucket);
+
+  // initialize bucket
+  bzero((void*)bucket, nbucket);
+
+  StringHash<ELF> hash_func;
+
+  for (size_t sym_idx=0; sym_idx < symtabIdx; ++sym_idx) {
+    llvm::StringRef name(strtab + symtab32[sym_idx].st_name);
+    size_t bucket_pos = hash_func(name) % nbucket;
+    chain[sym_idx] = bucket[bucket_pos];
+    bucket[bucket_pos] = sym_idx;
+  }
+
+}
+
+MipsGOT& MipsGNULDBackend::getGOT()
+{
+  assert(NULL != m_pGOT);
+  return *m_pGOT;
+}
+
+const MipsGOT& MipsGNULDBackend::getGOT() const
+{
+  assert(NULL != m_pGOT);
+  return *m_pGOT;
+}
+
+OutputRelocSection& MipsGNULDBackend::getRelDyn()
+{
+  assert(NULL != m_pRelDyn);
+  return *m_pRelDyn;
+}
+
+const OutputRelocSection& MipsGNULDBackend::getRelDyn() const
+{
+  assert(NULL != m_pRelDyn);
+  return *m_pRelDyn;
+}
+
+unsigned int
+MipsGNULDBackend::getTargetSectionOrder(const Output& pOutput,
+                                        const LDSection& pSectHdr) const
+{
+  ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+  if (&pSectHdr == &file_format->getGOT())
+    return SHO_DATA;
+
+  return SHO_UNDEFINED;
+}
+
+/// finalizeSymbol - finalize the symbol value
+/// If the symbol's reserved field is not zero, MCLinker will call back this
+/// function to ask the final value of the symbol
+bool MipsGNULDBackend::finalizeSymbol(LDSymbol& pSymbol) const
+{
+  if (&pSymbol == m_pGpDispSymbol) {
+    m_pGpDispSymbol->setValue(m_pGOT->getSection().addr() + 0x7FF0);
+    return true;
+  }
+  return false;
+}
+
+/// allocateCommonSymbols - allocate common symbols in the corresponding
+/// sections.
+/// @refer Google gold linker: common.cc: 214
+/// FIXME: Mips needs to allocate small common symbol
+bool
+MipsGNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
+{
+  // SymbolCategory contains all symbols that must emit to the output files.
+  // We are not like Google gold linker, we don't remember symbols before symbol
+  // resolution. All symbols in SymbolCategory are already resolved. Therefore, we
+  // don't need to care about some symbols may be changed its category due to symbol
+  // resolution.
+  SymbolCategory& symbol_list = pLinker.getOutputSymbols();
+
+  if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
+    return true;
+
+  // addralign := max value of all common symbols
+  uint64_t addralign = 0x0;
+
+  // Due to the visibility, some common symbols may be forcefully local.
+  SymbolCategory::iterator com_sym, com_end = symbol_list.localEnd();
+  for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+    if (ResolveInfo::Common == (*com_sym)->desc()) {
+      if ((*com_sym)->value() > addralign)
+        addralign = (*com_sym)->value();
+    }
+  }
+
+  // global common symbols.
+  com_end = symbol_list.commonEnd();
+  for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+    if ((*com_sym)->value() > addralign)
+      addralign = (*com_sym)->value();
+  }
+
+  // FIXME: If the order of common symbols is defined, then sort common symbols
+  // com_sym = symbol_list.commonBegin();
+  // std::sort(com_sym, com_end, some kind of order);
+
+  // get or create corresponding BSS LDSection
+  LDSection* bss_sect_hdr = NULL;
+  if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+    bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
+                                   ".tbss",
+                                   LDFileFormat::BSS,
+                                   llvm::ELF::SHT_NOBITS,
+                                   llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+  }
+  else {
+    bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
+                                   LDFileFormat::BSS,
+                                   llvm::ELF::SHT_NOBITS,
+                                   llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+  }
+
+  // get or create corresponding BSS MCSectionData
+  assert(NULL != bss_sect_hdr);
+  llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(*bss_sect_hdr);
+
+  // allocate all common symbols
+  uint64_t offset = bss_sect_hdr->size();
+
+  // allocate all local common symbols
+  com_end = symbol_list.localEnd();
+  for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+    if (ResolveInfo::Common == (*com_sym)->desc()) {
+      alignAddress(offset, (*com_sym)->value());
+      // We have to reset the description of the symbol here. When doing
+      // incremental linking, the output relocatable object may have common
+      // symbols. Therefore, we can not treat common symbols as normal symbols
+      // when emitting the regular name pools. We must change the symbols'
+      // description here.
+      (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+      llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size(), &bss_section);
+      (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+      offset += (*com_sym)->size();
+    }
+  }
+
+  // allocate all global common symbols
+  com_end = symbol_list.commonEnd();
+  for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+    alignAddress(offset, (*com_sym)->value());
+
+    // We have to reset the description of the symbol here. When doing
+    // incremental linking, the output relocatable object may have common
+    // symbols. Therefore, we can not treat common symbols as normal symbols
+    // when emitting the regular name pools. We must change the symbols'
+    // description here.
+    (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+    llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size(), &bss_section);
+    (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+    offset += (*com_sym)->size();
+  }
+
+  bss_sect_hdr->setSize(offset);
+  symbol_list.changeCommonsToGlobal();
+  return true;
+}
+
+void MipsGNULDBackend::updateAddend(Relocation& pReloc,
+                                   const LDSymbol& pInputSym,
+                                   const Layout& pLayout) const
+{
+  // Update value keep in addend if we meet a section symbol
+  if(pReloc.symInfo()->type() == ResolveInfo::Section) {
+    pReloc.setAddend(pLayout.getOutputOffset(
+                     *pInputSym.fragRef()) + pReloc.addend());
+  }
+}
+
+void MipsGNULDBackend::scanLocalReloc(Relocation& pReloc,
+                                      const LDSymbol& pInputSym,
+                                      MCLinker& pLinker,
+                                      const MCLDInfo& pLDInfo,
+                                      const Output& pOutput)
+{
+  ResolveInfo* rsym = pReloc.symInfo();
+
+  updateAddend(pReloc, pInputSym, pLinker.getLayout());
+
+  switch (pReloc.type()){
+    case llvm::ELF::R_MIPS_NONE:
+    case llvm::ELF::R_MIPS_16:
+      break;
+    case llvm::ELF::R_MIPS_32:
+      if (Output::DynObj == pOutput.type()) {
+        // TODO: (simon) The gold linker does not create an entry in .rel.dyn
+        // section if the symbol section flags contains SHF_EXECINSTR.
+        // 1. Find the reason of this condition.
+        // 2. Check this condition here.
+        if (NULL == m_pRelDyn)
+          createRelDyn(pLinker, pOutput);
+
+        m_pRelDyn->reserveEntry(*m_pRelocFactory);
+        rsym->setReserved(rsym->reserved() | ReserveRel);
+      }
+      break;
+    case llvm::ELF::R_MIPS_REL32:
+    case llvm::ELF::R_MIPS_26:
+    case llvm::ELF::R_MIPS_HI16:
+    case llvm::ELF::R_MIPS_LO16:
+    case llvm::ELF::R_MIPS_PC16:
+    case llvm::ELF::R_MIPS_SHIFT5:
+    case llvm::ELF::R_MIPS_SHIFT6:
+    case llvm::ELF::R_MIPS_64:
+    case llvm::ELF::R_MIPS_GOT_PAGE:
+    case llvm::ELF::R_MIPS_GOT_OFST:
+    case llvm::ELF::R_MIPS_SUB:
+    case llvm::ELF::R_MIPS_INSERT_A:
+    case llvm::ELF::R_MIPS_INSERT_B:
+    case llvm::ELF::R_MIPS_DELETE:
+    case llvm::ELF::R_MIPS_HIGHER:
+    case llvm::ELF::R_MIPS_HIGHEST:
+    case llvm::ELF::R_MIPS_SCN_DISP:
+    case llvm::ELF::R_MIPS_REL16:
+    case llvm::ELF::R_MIPS_ADD_IMMEDIATE:
+    case llvm::ELF::R_MIPS_PJUMP:
+    case llvm::ELF::R_MIPS_RELGOT:
+    case llvm::ELF::R_MIPS_JALR:
+    case llvm::ELF::R_MIPS_GLOB_DAT:
+    case llvm::ELF::R_MIPS_COPY:
+    case llvm::ELF::R_MIPS_JUMP_SLOT:
+      break;
+    case llvm::ELF::R_MIPS_GOT16:
+    case llvm::ELF::R_MIPS_CALL16:
+      if (NULL == m_pGOT)
+        createGOT(pLinker, pOutput);
+
+      if (!(rsym->reserved() & MipsGNULDBackend::ReserveGot)) {
+        m_pGOT->reserveLocalEntry();
+        rsym->setReserved(rsym->reserved() | ReserveGot);
+        m_LocalGOTSyms.push_back(rsym->outSymbol());
+      }
+      break;
+    case llvm::ELF::R_MIPS_GPREL32:
+    case llvm::ELF::R_MIPS_GPREL16:
+    case llvm::ELF::R_MIPS_LITERAL:
+      break;
+    case llvm::ELF::R_MIPS_GOT_DISP:
+    case llvm::ELF::R_MIPS_GOT_HI16:
+    case llvm::ELF::R_MIPS_CALL_HI16:
+    case llvm::ELF::R_MIPS_GOT_LO16:
+    case llvm::ELF::R_MIPS_CALL_LO16:
+      break;
+    case llvm::ELF::R_MIPS_TLS_DTPMOD32:
+    case llvm::ELF::R_MIPS_TLS_DTPREL32:
+    case llvm::ELF::R_MIPS_TLS_DTPMOD64:
+    case llvm::ELF::R_MIPS_TLS_DTPREL64:
+    case llvm::ELF::R_MIPS_TLS_GD:
+    case llvm::ELF::R_MIPS_TLS_LDM:
+    case llvm::ELF::R_MIPS_TLS_DTPREL_HI16:
+    case llvm::ELF::R_MIPS_TLS_DTPREL_LO16:
+    case llvm::ELF::R_MIPS_TLS_GOTTPREL:
+    case llvm::ELF::R_MIPS_TLS_TPREL32:
+    case llvm::ELF::R_MIPS_TLS_TPREL64:
+    case llvm::ELF::R_MIPS_TLS_TPREL_HI16:
+    case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
+      break;
+    default:
+      llvm::report_fatal_error(llvm::Twine("Unknown relocation ") +
+                               llvm::Twine(pReloc.type()) +
+                               llvm::Twine("for the local symbol `") +
+                               pReloc.symInfo()->name() +
+                               llvm::Twine("'."));
+  }
+}
+
+void MipsGNULDBackend::scanGlobalReloc(Relocation& pReloc,
+                                       const LDSymbol& pInputSym,
+                                       MCLinker& pLinker,
+                                       const MCLDInfo& pLDInfo,
+                                       const Output& pOutput)
+{
+  ResolveInfo* rsym = pReloc.symInfo();
+
+  switch (pReloc.type()){
+    case llvm::ELF::R_MIPS_NONE:
+    case llvm::ELF::R_MIPS_INSERT_A:
+    case llvm::ELF::R_MIPS_INSERT_B:
+    case llvm::ELF::R_MIPS_DELETE:
+    case llvm::ELF::R_MIPS_TLS_DTPMOD64:
+    case llvm::ELF::R_MIPS_TLS_DTPREL64:
+    case llvm::ELF::R_MIPS_REL16:
+    case llvm::ELF::R_MIPS_ADD_IMMEDIATE:
+    case llvm::ELF::R_MIPS_PJUMP:
+    case llvm::ELF::R_MIPS_RELGOT:
+    case llvm::ELF::R_MIPS_TLS_TPREL64:
+      break;
+    case llvm::ELF::R_MIPS_32:
+    case llvm::ELF::R_MIPS_64:
+    case llvm::ELF::R_MIPS_HI16:
+    case llvm::ELF::R_MIPS_LO16:
+      if (isSymbolNeedsDynRel(*rsym, pOutput)) {
+        if (NULL == m_pRelDyn)
+          createRelDyn(pLinker, pOutput);
+
+        m_pRelDyn->reserveEntry(*m_pRelocFactory);
+        rsym->setReserved(rsym->reserved() | ReserveRel);
+      }
+      break;
+    case llvm::ELF::R_MIPS_GOT16:
+    case llvm::ELF::R_MIPS_CALL16:
+    case llvm::ELF::R_MIPS_GOT_DISP:
+    case llvm::ELF::R_MIPS_GOT_HI16:
+    case llvm::ELF::R_MIPS_CALL_HI16:
+    case llvm::ELF::R_MIPS_GOT_LO16:
+    case llvm::ELF::R_MIPS_CALL_LO16:
+    case llvm::ELF::R_MIPS_GOT_PAGE:
+    case llvm::ELF::R_MIPS_GOT_OFST:
+      if (NULL == m_pGOT)
+        createGOT(pLinker, pOutput);
+
+      if (!(rsym->reserved() & MipsGNULDBackend::ReserveGot)) {
+        m_pGOT->reserveGlobalEntry();
+        rsym->setReserved(rsym->reserved() | ReserveGot);
+        m_GlobalGOTSyms.push_back(rsym->outSymbol());
+      }
+      break;
+    case llvm::ELF::R_MIPS_LITERAL:
+    case llvm::ELF::R_MIPS_GPREL32:
+      llvm::report_fatal_error(llvm::Twine("Relocation ") +
+                               llvm::Twine(pReloc.type()) +
+                               llvm::Twine(" is not defined for the "
+                                           "global symbol `") +
+                               pReloc.symInfo()->name() +
+                               llvm::Twine("'."));
+      break;
+    case llvm::ELF::R_MIPS_GPREL16:
+      break;
+    case llvm::ELF::R_MIPS_26:
+    case llvm::ELF::R_MIPS_PC16:
+      break;
+    case llvm::ELF::R_MIPS_16:
+    case llvm::ELF::R_MIPS_SHIFT5:
+    case llvm::ELF::R_MIPS_SHIFT6:
+    case llvm::ELF::R_MIPS_SUB:
+    case llvm::ELF::R_MIPS_HIGHER:
+    case llvm::ELF::R_MIPS_HIGHEST:
+    case llvm::ELF::R_MIPS_SCN_DISP:
+      break;
+    case llvm::ELF::R_MIPS_TLS_DTPREL32:
+    case llvm::ELF::R_MIPS_TLS_GD:
+    case llvm::ELF::R_MIPS_TLS_LDM:
+    case llvm::ELF::R_MIPS_TLS_DTPREL_HI16:
+    case llvm::ELF::R_MIPS_TLS_DTPREL_LO16:
+    case llvm::ELF::R_MIPS_TLS_GOTTPREL:
+    case llvm::ELF::R_MIPS_TLS_TPREL32:
+    case llvm::ELF::R_MIPS_TLS_TPREL_HI16:
+    case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
+      break;
+    case llvm::ELF::R_MIPS_REL32:
+      break;
+    case llvm::ELF::R_MIPS_JALR:
+      break;
+    case llvm::ELF::R_MIPS_COPY:
+    case llvm::ELF::R_MIPS_GLOB_DAT:
+    case llvm::ELF::R_MIPS_JUMP_SLOT:
+      llvm::report_fatal_error(llvm::Twine("Relocation ") +
+                               llvm::Twine(pReloc.type()) +
+                               llvm::Twine("for the global symbol `") +
+                               pReloc.symInfo()->name() +
+                               llvm::Twine("' should only be seen "
+                                           "by the dynamic linker"));
+      break;
+    default:
+      llvm::report_fatal_error(llvm::Twine("Unknown relocation ") +
+                               llvm::Twine(pReloc.type()) +
+                               llvm::Twine("for the global symbol `") +
+                               pReloc.symInfo()->name() +
+                               llvm::Twine("'."));
+  }
+}
+
+bool MipsGNULDBackend::isSymbolNeedsPLT(ResolveInfo& pSym,
+                                        const Output& pOutput) const
+{
+  return (Output::DynObj == pOutput.type() &&
+         ResolveInfo::Function == pSym.type() &&
+         (pSym.isDyn() || pSym.isUndef()));
+}
+
+bool MipsGNULDBackend::isSymbolNeedsDynRel(ResolveInfo& pSym,
+                                           const Output& pOutput) const
+{
+  if(pSym.isUndef() && Output::Exec == pOutput.type())
+    return false;
+  if(pSym.isAbsolute())
+    return false;
+  if(Output::DynObj == pOutput.type())
+    return true;
+  if(pSym.isDyn() || pSym.isUndef())
+    return true;
+
+  return false;
+}
+
+void MipsGNULDBackend::createGOT(MCLinker& pLinker, const Output& pOutput)
+{
+  ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+  LDSection& got = file_format->getGOT();
+  m_pGOT = new MipsGOT(got, pLinker.getOrCreateSectData(got));
+
+  // define symbol _GLOBAL_OFFSET_TABLE_ when .got create
+  if( m_pGOTSymbol != NULL ) {
+    pLinker.defineSymbol<MCLinker::Force, MCLinker::Unresolve>(
+                     "_GLOBAL_OFFSET_TABLE_",
+                     false,
+                     ResolveInfo::Object,
+                     ResolveInfo::Define,
+                     ResolveInfo::Local,
+                     0x0, // size
+                     0x0, // value
+                     pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+                     ResolveInfo::Hidden);
+  }
+  else {
+    m_pGOTSymbol = pLinker.defineSymbol<MCLinker::Force, MCLinker::Resolve>(
+                     "_GLOBAL_OFFSET_TABLE_",
+                     false,
+                     ResolveInfo::Object,
+                     ResolveInfo::Define,
+                     ResolveInfo::Local,
+                     0x0, // size
+                     0x0, // value
+                     pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+                     ResolveInfo::Hidden);
+  }
+}
+
+void MipsGNULDBackend::createRelDyn(MCLinker& pLinker, const Output& pOutput)
+{
+  ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+  // get .rel.dyn LDSection and create MCSectionData
+  LDSection& reldyn = file_format->getRelDyn();
+  // create MCSectionData and ARMRelDynSection
+  m_pRelDyn = new OutputRelocSection(reldyn,
+                                     pLinker.getOrCreateSectData(reldyn),
+                                     8);
+}
+
+ELFFileFormat* MipsGNULDBackend::getOutputFormat(const Output& pOutput) const
+{
+  switch (pOutput.type()) {
+    case Output::DynObj:
+      return getDynObjFileFormat();
+    case Output::Exec:
+      return getExecFileFormat();
+    case Output::Object:
+      return NULL;
+    default:
+      llvm::report_fatal_error(llvm::Twine("Unsupported output file format: ") +
+                               llvm::Twine(pOutput.type()));
+      return NULL;
+  }
+}
+
+//===----------------------------------------------------------------------===//
+/// createMipsLDBackend - the help funtion to create corresponding MipsLDBackend
+///
+static TargetLDBackend* createMipsLDBackend(const llvm::Target& pTarget,
+                                            const std::string& pTriple)
+{
+  llvm::Triple theTriple(pTriple);
+  if (theTriple.isOSDarwin()) {
+    assert(0 && "MachO linker is not supported yet");
+  }
+  if (theTriple.isOSWindows()) {
+    assert(0 && "COFF linker is not supported yet");
+  }
+  return new MipsGNULDBackend();
+}
+
+} // namespace of mcld
+
+//=============================
+// Force static initialization.
+extern "C" void LLVMInitializeMipsLDBackend() {
+  // Register the linker backend
+  mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheMipselTarget,
+                                                mcld::createMipsLDBackend);
+}