text: //===- MipsLDBackend.cpp --------------------------------------------------===//
  //
  //                     The MCLinker Project
  //
  // This file is distributed under the University of Illinois Open Source
  // License. See LICENSE.TXT for details.
  //
  //===----------------------------------------------------------------------===//
  #include "Mips.h"
  #include "MipsGNUInfo.h"
  #include "MipsELFDynamic.h"
  #include "MipsLA25Stub.h"
  #include "MipsLDBackend.h"
  #include "MipsRelocator.h"
  
  #include "mcld/IRBuilder.h"
  #include "mcld/LinkerConfig.h"
  #include "mcld/Module.h"
  #include "mcld/Fragment/AlignFragment.h"
  #include "mcld/Fragment/FillFragment.h"
  #include "mcld/LD/BranchIslandFactory.h"
  #include "mcld/LD/LDContext.h"
  #include "mcld/LD/StubFactory.h"
  #include "mcld/LD/ELFFileFormat.h"
  #include "mcld/LD/ELFSegment.h"
  #include "mcld/LD/ELFSegmentFactory.h"
  #include "mcld/MC/Attribute.h"
  #include "mcld/Object/ObjectBuilder.h"
  #include "mcld/Support/MemoryRegion.h"
  #include "mcld/Support/MemoryArea.h"
  #include "mcld/Support/MsgHandling.h"
  #include "mcld/Support/TargetRegistry.h"
  #include "mcld/Target/OutputRelocSection.h"
  
  #include <llvm/ADT/Triple.h>
  #include <llvm/Object/ELFTypes.h>
  #include <llvm/Support/Casting.h>
  #include <llvm/Support/ELF.h>
  #include <llvm/Support/Host.h>
  #include <llvm/Support/MipsABIFlags.h>
  
  #include <vector>
  
  namespace mcld {
  
  //===----------------------------------------------------------------------===//
  // MipsGNULDBackend
  //===----------------------------------------------------------------------===//
  MipsGNULDBackend::MipsGNULDBackend(const LinkerConfig& pConfig,
                                     MipsGNUInfo* pInfo)
      : GNULDBackend(pConfig, pInfo),
        m_pRelocator(NULL),
        m_pGOT(NULL),
        m_pPLT(NULL),
        m_pGOTPLT(NULL),
        m_pInfo(*pInfo),
        m_pRelPlt(NULL),
        m_pRelDyn(NULL),
        m_pDynamic(NULL),
        m_pAbiFlags(NULL),
        m_pGOTSymbol(NULL),
        m_pPLTSymbol(NULL),
        m_pGpDispSymbol(NULL) {
  }
  
  MipsGNULDBackend::~MipsGNULDBackend() {
    delete m_pRelocator;
    delete m_pPLT;
    delete m_pRelPlt;
    delete m_pRelDyn;
    delete m_pDynamic;
  }
  
  bool MipsGNULDBackend::needsLA25Stub(Relocation::Type pType,
                                       const mcld::ResolveInfo* pSym) {
    if (config().isCodeIndep())
      return false;
  
    if (llvm::ELF::R_MIPS_26 != pType)
      return false;
  
    if (pSym->isLocal())
      return false;
  
    return true;
  }
  
  void MipsGNULDBackend::addNonPICBranchSym(ResolveInfo* rsym) {
    m_HasNonPICBranchSyms.insert(rsym);
  }
  
  bool MipsGNULDBackend::hasNonPICBranch(const ResolveInfo* rsym) const {
    return m_HasNonPICBranchSyms.count(rsym);
  }
  
  void MipsGNULDBackend::initTargetSections(Module& pModule,
                                            ObjectBuilder& pBuilder) {
    if (LinkerConfig::Object == config().codeGenType())
      return;
  
    ELFFileFormat* file_format = getOutputFormat();
  
    // initialize .rel.plt
    LDSection& relplt = file_format->getRelPlt();
    m_pRelPlt = new OutputRelocSection(pModule, relplt);
  
    // initialize .rel.dyn
    LDSection& reldyn = file_format->getRelDyn();
    m_pRelDyn = new OutputRelocSection(pModule, reldyn);
  
    // initialize .sdata
    m_psdata = pBuilder.CreateSection(
        ".sdata", LDFileFormat::Target, llvm::ELF::SHT_PROGBITS,
        llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE | llvm::ELF::SHF_MIPS_GPREL,
        4);
  
    // initialize .MIPS.abiflags
    m_pAbiFlags = pBuilder.CreateSection(".MIPS.abiflags", LDFileFormat::Target,
                                         llvm::ELF::SHT_MIPS_ABIFLAGS,
                                         llvm::ELF::SHF_ALLOC, 4);
  }
  
  void MipsGNULDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule) {
    // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
    // same name in input
    m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
        "_GLOBAL_OFFSET_TABLE_",
        ResolveInfo::Object,
        ResolveInfo::Define,
        ResolveInfo::Local,
        0x0,                  // size
        0x0,                  // value
        FragmentRef::Null(),  // FragRef
        ResolveInfo::Hidden);
  
    // Define the symbol _PROCEDURE_LINKAGE_TABLE_ if there is a symbol with the
    // same name in input
    m_pPLTSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
        "_PROCEDURE_LINKAGE_TABLE_",
        ResolveInfo::Object,
        ResolveInfo::Define,
        ResolveInfo::Local,
        0x0,                  // size
        0x0,                  // value
        FragmentRef::Null(),  // FragRef
        ResolveInfo::Hidden);
  
    m_pGpDispSymbol =
        pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
            "_gp_disp",
            ResolveInfo::Section,
            ResolveInfo::Define,
            ResolveInfo::Absolute,
            0x0,                  // size
            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(m_pRelocator != NULL);
    return m_pRelocator;
  }
  
  Relocator* MipsGNULDBackend::getRelocator() {
    assert(m_pRelocator != NULL);
    return m_pRelocator;
  }
  
  void MipsGNULDBackend::doPreLayout(IRBuilder& pBuilder) {
    // initialize .dynamic data
    if (!config().isCodeStatic() && m_pDynamic == NULL)
      m_pDynamic = new MipsELFDynamic(*this, config());
  
    if (m_pAbiInfo.hasValue())
      m_pAbiFlags->setSize(m_pAbiInfo->size());
  
    // set .got size
    // when building shared object, the .got section is must.
    if (LinkerConfig::Object != config().codeGenType()) {
      if (LinkerConfig::DynObj == config().codeGenType() || m_pGOT->hasGOT1() ||
          m_pGOTSymbol != NULL) {
        m_pGOT->finalizeScanning(*m_pRelDyn);
        m_pGOT->finalizeSectionSize();
  
        defineGOTSymbol(pBuilder);
      }
  
      if (m_pGOTPLT->hasGOT1()) {
        m_pGOTPLT->finalizeSectionSize();
  
        defineGOTPLTSymbol(pBuilder);
      }
  
      if (m_pPLT->hasPLT1())
        m_pPLT->finalizeSectionSize();
  
      ELFFileFormat* file_format = getOutputFormat();
  
      // set .rel.plt size
      if (!m_pRelPlt->empty()) {
        assert(
            !config().isCodeStatic() &&
            "static linkage should not result in a dynamic relocation section");
        file_format->getRelPlt().setSize(m_pRelPlt->numOfRelocs() *
                                         getRelEntrySize());
      }
  
      // set .rel.dyn size
      if (!m_pRelDyn->empty()) {
        assert(
            !config().isCodeStatic() &&
            "static linkage should not result in a dynamic relocation section");
        file_format->getRelDyn().setSize(m_pRelDyn->numOfRelocs() *
                                         getRelEntrySize());
      }
    }
  }
  
  void MipsGNULDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder) {
    const ELFFileFormat* format = getOutputFormat();
  
    if (format->hasGOTPLT()) {
      assert(m_pGOTPLT != NULL && "doPostLayout failed, m_pGOTPLT is NULL!");
      m_pGOTPLT->applyAllGOTPLT(m_pPLT->addr());
    }
  
    if (format->hasPLT()) {
      assert(m_pPLT != NULL && "doPostLayout failed, m_pPLT is NULL!");
      m_pPLT->applyAllPLT(*m_pGOTPLT);
    }
  
    m_pInfo.setABIVersion(m_pPLT && m_pPLT->hasPLT1() ? 1 : 0);
  }
  
  /// dynamic - the dynamic section of the target machine.
  /// Use co-variant return type to return its own dynamic section.
  MipsELFDynamic& MipsGNULDBackend::dynamic() {
    assert(m_pDynamic != NULL);
    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(m_pDynamic != NULL);
    return *m_pDynamic;
  }
  
  uint64_t MipsGNULDBackend::emitSectionData(const LDSection& pSection,
                                             MemoryRegion& pRegion) const {
    assert(pRegion.size() && "Size of MemoryRegion is zero!");
  
    const ELFFileFormat* file_format = getOutputFormat();
  
    if (file_format->hasGOT() && (&pSection == &(file_format->getGOT()))) {
      return m_pGOT->emit(pRegion);
    }
  
    if (file_format->hasPLT() && (&pSection == &(file_format->getPLT()))) {
      return m_pPLT->emit(pRegion);
    }
  
    if (file_format->hasGOTPLT() && (&pSection == &(file_format->getGOTPLT()))) {
      return m_pGOTPLT->emit(pRegion);
    }
  
    if (&pSection == m_pAbiFlags && m_pAbiInfo.hasValue())
      return MipsAbiFlags::emit(*m_pAbiInfo, pRegion);
  
    if (&pSection == m_psdata && m_psdata->hasSectionData()) {
      const SectionData* sect_data = pSection.getSectionData();
      SectionData::const_iterator frag_iter, frag_end = sect_data->end();
      uint8_t* out_offset = pRegion.begin();
      for (frag_iter = sect_data->begin(); frag_iter != frag_end; ++frag_iter) {
        size_t size = frag_iter->size();
        switch (frag_iter->getKind()) {
          case Fragment::Fillment: {
            const FillFragment& fill_frag = llvm::cast<FillFragment>(*frag_iter);
            if (fill_frag.getValueSize() == 0) {
              // virtual fillment, ignore it.
              break;
            }
            memset(out_offset, fill_frag.getValue(), fill_frag.size());
            break;
          }
          case Fragment::Region: {
            const RegionFragment& region_frag =
                llvm::cast<RegionFragment>(*frag_iter);
            const char* start = region_frag.getRegion().begin();
            memcpy(out_offset, start, size);
            break;
          }
          case Fragment::Alignment: {
            const AlignFragment& align_frag =
                llvm::cast<AlignFragment>(*frag_iter);
            uint64_t count = size / align_frag.getValueSize();
            switch (align_frag.getValueSize()) {
              case 1u:
                std::memset(out_offset, align_frag.getValue(), count);
                break;
              default:
                llvm::report_fatal_error(
                    "unsupported value size for align fragment emission yet.\n");
                break;
            }  // end switch
            break;
          }
          case Fragment::Null: {
            assert(0x0 == size);
            break;
          }
          default:
            llvm::report_fatal_error("unsupported fragment type.\n");
            break;
        }  // end switch
        out_offset += size;
      }
      return pRegion.size();
    }
  
    fatal(diag::unrecognized_output_sectoin) << pSection.name()
                                             << "mclinker@googlegroups.com";
    return 0;
  }
  
  bool MipsGNULDBackend::hasEntryInStrTab(const LDSymbol& pSym) const {
    return ResolveInfo::Section != pSym.type() || m_pGpDispSymbol == &pSym;
  }
  
  namespace {
  struct DynsymGOTCompare {
    const MipsGOT& m_pGOT;
  
    explicit DynsymGOTCompare(const MipsGOT& pGOT) : m_pGOT(pGOT) {}
  
    bool operator()(const LDSymbol* X, const LDSymbol* Y) const {
      return m_pGOT.dynSymOrderCompare(X, Y);
    }
  };
  }  // anonymous namespace
  
  void MipsGNULDBackend::orderSymbolTable(Module& pModule) {
    if (config().options().hasGNUHash()) {
      // The MIPS ABI and .gnu.hash require .dynsym to be sorted
      // in different ways. The MIPS ABI requires a mapping between
      // the GOT and the symbol table. At the same time .gnu.hash
      // needs symbols to be grouped by hash code.
      llvm::errs() << ".gnu.hash is incompatible with the MIPS ABI\n";
    }
  
    Module::SymbolTable& symbols = pModule.getSymbolTable();
  
    std::stable_sort(
        symbols.dynamicBegin(), symbols.dynamicEnd(), DynsymGOTCompare(*m_pGOT));
  }
  
  }  // namespace mcld
  
  namespace llvm {
  namespace ELF {
  // SHT_MIPS_OPTIONS section's block descriptor.
  struct Elf_Options {
    unsigned char kind;  // Determines interpretation of variable
                         // part of descriptor. See ODK_xxx enumeration.
    unsigned char size;  // Byte size of descriptor, including this header.
    Elf64_Half section;  // Section header index of section affected,
                         // or 0 for global options.
    Elf64_Word info;     // Kind-speciﬁc information.
  };
  
  // Content of ODK_REGINFO block in SHT_MIPS_OPTIONS section on 32 bit ABI.
  struct Elf32_RegInfo {
    Elf32_Word ri_gprmask;     // Mask of general purpose registers used.
    Elf32_Word ri_cprmask[4];  // Mask of co-processor registers used.
    Elf32_Addr ri_gp_value;    // GP register value for this object file.
  };
  
  // Content of ODK_REGINFO block in SHT_MIPS_OPTIONS section on 64 bit ABI.
  struct Elf64_RegInfo {
    Elf32_Word ri_gprmask;     // Mask of general purpose registers used.
    Elf32_Word ri_pad;         // Padding.
    Elf32_Word ri_cprmask[4];  // Mask of co-processor registers used.
    Elf64_Addr ri_gp_value;    // GP register value for this object file.
  };
  
  }  // namespace ELF
  }  // namespace llvm
  
  namespace mcld {
  
  static const char* ArchName(uint64_t flagBits) {
    switch (flagBits) {
      case llvm::ELF::EF_MIPS_ARCH_1:
        return "mips1";
      case llvm::ELF::EF_MIPS_ARCH_2:
        return "mips2";
      case llvm::ELF::EF_MIPS_ARCH_3:
        return "mips3";
      case llvm::ELF::EF_MIPS_ARCH_4:
        return "mips4";
      case llvm::ELF::EF_MIPS_ARCH_5:
        return "mips5";
      case llvm::ELF::EF_MIPS_ARCH_32:
        return "mips32";
      case llvm::ELF::EF_MIPS_ARCH_64:
        return "mips64";
      case llvm::ELF::EF_MIPS_ARCH_32R2:
        return "mips32r2";
      case llvm::ELF::EF_MIPS_ARCH_64R2:
        return "mips64r2";
      case llvm::ELF::EF_MIPS_ARCH_32R6:
        return "mips32r6";
      case llvm::ELF::EF_MIPS_ARCH_64R6:
        return "mips64r6";
      default:
        return "Unknown Arch";
    }
  }
  
  void MipsGNULDBackend::mergeFlags(Input& pInput, const char* ELF_hdr) {
    bool isTarget64Bit = config().targets().triple().isArch64Bit();
    bool isInput64Bit = ELF_hdr[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS64;
  
    if (isTarget64Bit != isInput64Bit) {
      fatal(diag::error_Mips_incompatible_class)
          << (isTarget64Bit ? "ELFCLASS64" : "ELFCLASS32")
          << (isInput64Bit ? "ELFCLASS64" : "ELFCLASS32") << pInput.name();
      return;
    }
  
    m_ElfFlagsMap[&pInput] =
        isInput64Bit ?
            reinterpret_cast<const llvm::ELF::Elf64_Ehdr*>(ELF_hdr)->e_flags :
            reinterpret_cast<const llvm::ELF::Elf32_Ehdr*>(ELF_hdr)->e_flags;
  }
  
  bool MipsGNULDBackend::readSection(Input& pInput, SectionData& pSD) {
    if ((pSD.getSection().flag() & llvm::ELF::SHF_MIPS_GPREL) ||
        (pSD.getSection().type() == llvm::ELF::SHT_MIPS_ABIFLAGS)) {
      uint64_t offset = pInput.fileOffset() + pSD.getSection().offset();
      uint64_t size = pSD.getSection().size();
  
      Fragment* frag = IRBuilder::CreateRegion(pInput, offset, size);
      ObjectBuilder::AppendFragment(*frag, pSD);
      return true;
    }
  
    if (pSD.getSection().type() == llvm::ELF::SHT_MIPS_OPTIONS) {
      uint32_t offset = pInput.fileOffset() + pSD.getSection().offset();
      uint32_t size = pSD.getSection().size();
  
      llvm::StringRef region = pInput.memArea()->request(offset, size);
      if (region.size() > 0) {
        const llvm::ELF::Elf_Options* optb =
            reinterpret_cast<const llvm::ELF::Elf_Options*>(region.begin());
        const llvm::ELF::Elf_Options* opte =
            reinterpret_cast<const llvm::ELF::Elf_Options*>(region.begin() +
                                                            size);
  
        for (const llvm::ELF::Elf_Options* opt = optb; opt < opte;
             opt += opt->size) {
          switch (opt->kind) {
            default:
              // Nothing to do.
              break;
            case llvm::ELF::ODK_REGINFO:
              if (config().targets().triple().isArch32Bit()) {
                const llvm::ELF::Elf32_RegInfo* reg =
                    reinterpret_cast<const llvm::ELF::Elf32_RegInfo*>(opt + 1);
                m_GP0Map[&pInput] = reg->ri_gp_value;
              } else {
                const llvm::ELF::Elf64_RegInfo* reg =
                    reinterpret_cast<const llvm::ELF::Elf64_RegInfo*>(opt + 1);
                m_GP0Map[&pInput] = reg->ri_gp_value;
              }
              break;
          }
        }
      }
  
      return true;
    }
  
    return GNULDBackend::readSection(pInput, pSD);
  }
  
  MipsGOT& MipsGNULDBackend::getGOT() {
    assert(m_pGOT != NULL);
    return *m_pGOT;
  }
  
  const MipsGOT& MipsGNULDBackend::getGOT() const {
    assert(m_pGOT != NULL);
    return *m_pGOT;
  }
  
  MipsPLT& MipsGNULDBackend::getPLT() {
    assert(m_pPLT != NULL);
    return *m_pPLT;
  }
  
  const MipsPLT& MipsGNULDBackend::getPLT() const {
    assert(m_pPLT != NULL);
    return *m_pPLT;
  }
  
  MipsGOTPLT& MipsGNULDBackend::getGOTPLT() {
    assert(m_pGOTPLT != NULL);
    return *m_pGOTPLT;
  }
  
  const MipsGOTPLT& MipsGNULDBackend::getGOTPLT() const {
    assert(m_pGOTPLT != NULL);
    return *m_pGOTPLT;
  }
  
  OutputRelocSection& MipsGNULDBackend::getRelPLT() {
    assert(m_pRelPlt != NULL);
    return *m_pRelPlt;
  }
  
  const OutputRelocSection& MipsGNULDBackend::getRelPLT() const {
    assert(m_pRelPlt != NULL);
    return *m_pRelPlt;
  }
  
  OutputRelocSection& MipsGNULDBackend::getRelDyn() {
    assert(m_pRelDyn != NULL);
    return *m_pRelDyn;
  }
  
  const OutputRelocSection& MipsGNULDBackend::getRelDyn() const {
    assert(m_pRelDyn != NULL);
    return *m_pRelDyn;
  }
  
  unsigned int MipsGNULDBackend::getTargetSectionOrder(
      const LDSection& pSectHdr) const {
    const ELFFileFormat* file_format = getOutputFormat();
  
    if (file_format->hasGOT() && (&pSectHdr == &file_format->getGOT()))
      return SHO_DATA;
  
    if (file_format->hasGOTPLT() && (&pSectHdr == &file_format->getGOTPLT()))
      return SHO_DATA;
  
    if (file_format->hasPLT() && (&pSectHdr == &file_format->getPLT()))
      return SHO_PLT;
  
    if (&pSectHdr == m_psdata)
      return SHO_SMALL_DATA;
  
    if (&pSectHdr == m_pAbiFlags)
      return SHO_RO_NOTE;
  
    return SHO_UNDEFINED;
  }
  
  /// finalizeSymbol - finalize the symbol value
  bool MipsGNULDBackend::finalizeTargetSymbols() {
    if (m_pGpDispSymbol != NULL)
      m_pGpDispSymbol->setValue(m_pGOT->getGPDispAddress());
  
    return true;
  }
  
  /// allocateCommonSymbols - allocate common symbols in the corresponding
  /// sections. This is called at pre-layout stage.
  /// FIXME: Mips needs to allocate small common symbol
  bool MipsGNULDBackend::allocateCommonSymbols(Module& pModule) {
    SymbolCategory& symbol_list = pModule.getSymbolTable();
  
    if (symbol_list.emptyCommons() && symbol_list.emptyFiles() &&
        symbol_list.emptyLocals() && symbol_list.emptyLocalDyns())
      return true;
  
    SymbolCategory::iterator com_sym, com_end;
  
    // FIXME: If the order of common symbols is defined, then sort common symbols
    // std::sort(com_sym, com_end, some kind of order);
  
    // get corresponding BSS LDSection
    ELFFileFormat* file_format = getOutputFormat();
    LDSection& bss_sect = file_format->getBSS();
    LDSection& tbss_sect = file_format->getTBSS();
  
    // get or create corresponding BSS SectionData
    SectionData* bss_sect_data = NULL;
    if (bss_sect.hasSectionData())
      bss_sect_data = bss_sect.getSectionData();
    else
      bss_sect_data = IRBuilder::CreateSectionData(bss_sect);
  
    SectionData* tbss_sect_data = NULL;
    if (tbss_sect.hasSectionData())
      tbss_sect_data = tbss_sect.getSectionData();
    else
      tbss_sect_data = IRBuilder::CreateSectionData(tbss_sect);
  
    // remember original BSS size
    uint64_t bss_offset = bss_sect.size();
    uint64_t tbss_offset = tbss_sect.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()) {
        // 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);
        Fragment* frag = new FillFragment(0x0, 1, (*com_sym)->size());
  
        if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
          // allocate TLS common symbol in tbss section
          tbss_offset += ObjectBuilder::AppendFragment(
              *frag, *tbss_sect_data, (*com_sym)->value());
          ObjectBuilder::UpdateSectionAlign(tbss_sect, (*com_sym)->value());
          (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
        } else {
          // FIXME: how to identify small and large common symbols?
          bss_offset += ObjectBuilder::AppendFragment(
              *frag, *bss_sect_data, (*com_sym)->value());
          ObjectBuilder::UpdateSectionAlign(bss_sect, (*com_sym)->value());
          (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
        }
      }
    }
  
    // allocate all global common symbols
    com_end = symbol_list.commonEnd();
    for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
      // 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);
      Fragment* frag = new FillFragment(0x0, 1, (*com_sym)->size());
  
      if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
        // allocate TLS common symbol in tbss section
        tbss_offset += ObjectBuilder::AppendFragment(
            *frag, *tbss_sect_data, (*com_sym)->value());
        ObjectBuilder::UpdateSectionAlign(tbss_sect, (*com_sym)->value());
        (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
      } else {
        // FIXME: how to identify small and large common symbols?
        bss_offset += ObjectBuilder::AppendFragment(
            *frag, *bss_sect_data, (*com_sym)->value());
        ObjectBuilder::UpdateSectionAlign(bss_sect, (*com_sym)->value());
        (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
      }
    }
  
    bss_sect.setSize(bss_offset);
    tbss_sect.setSize(tbss_offset);
    symbol_list.changeCommonsToGlobal();
    return true;
  }
  
  uint64_t MipsGNULDBackend::getTPOffset(const Input& pInput) const {
    return m_TpOffsetMap.lookup(&pInput);
  }
  
  uint64_t MipsGNULDBackend::getDTPOffset(const Input& pInput) const {
    return m_DtpOffsetMap.lookup(&pInput);
  }
  
  uint64_t MipsGNULDBackend::getGP0(const Input& pInput) const {
    return m_GP0Map.lookup(&pInput);
  }
  
  void MipsGNULDBackend::defineGOTSymbol(IRBuilder& pBuilder) {
    // If we do not reserve any GOT entries, we do not need to re-define GOT
    // symbol.
    if (!m_pGOT->hasGOT1())
      return;
  
    // define symbol _GLOBAL_OFFSET_TABLE_
    if (m_pGOTSymbol != NULL) {
      pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
          "_GLOBAL_OFFSET_TABLE_",
          ResolveInfo::Object,
          ResolveInfo::Define,
          ResolveInfo::Local,
          0x0,  // size
          0x0,  // value
          FragmentRef::Create(*(m_pGOT->begin()), 0x0),
          ResolveInfo::Hidden);
    } else {
      m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
          "_GLOBAL_OFFSET_TABLE_",
          ResolveInfo::Object,
          ResolveInfo::Define,
          ResolveInfo::Local,
          0x0,  // size
          0x0,  // value
          FragmentRef::Create(*(m_pGOT->begin()), 0x0),
          ResolveInfo::Hidden);
    }
  }
  
  void MipsGNULDBackend::defineGOTPLTSymbol(IRBuilder& pBuilder) {
    // define symbol _PROCEDURE_LINKAGE_TABLE_
    if (m_pPLTSymbol != NULL) {
      pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
          "_PROCEDURE_LINKAGE_TABLE_",
          ResolveInfo::Object,
          ResolveInfo::Define,
          ResolveInfo::Local,
          0x0,  // size
          0x0,  // value
          FragmentRef::Create(*(m_pPLT->begin()), 0x0),
          ResolveInfo::Hidden);
    } else {
      m_pPLTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
          "_PROCEDURE_LINKAGE_TABLE_",
          ResolveInfo::Object,
          ResolveInfo::Define,
          ResolveInfo::Local,
          0x0,  // size
          0x0,  // value
          FragmentRef::Create(*(m_pPLT->begin()), 0x0),
          ResolveInfo::Hidden);
    }
  }
  
  /// doCreateProgramHdrs - backend can implement this function to create the
  /// target-dependent segments
  void MipsGNULDBackend::doCreateProgramHdrs(Module& pModule) {
    if (!m_pAbiFlags || m_pAbiFlags->size() == 0)
      return;
  
    // create PT_MIPS_ABIFLAGS segment
    ELFSegmentFactory::iterator sit =
        elfSegmentTable().find(llvm::ELF::PT_INTERP, 0x0, 0x0);
    if (sit == elfSegmentTable().end())
      sit = elfSegmentTable().find(llvm::ELF::PT_PHDR, 0x0, 0x0);
    if (sit == elfSegmentTable().end())
      sit = elfSegmentTable().begin();
    else
      ++sit;
  
    ELFSegment* abiSeg = elfSegmentTable().insert(sit,
                                                  llvm::ELF::PT_MIPS_ABIFLAGS,
                                                  llvm::ELF::PF_R);
    abiSeg->setAlign(8);
    abiSeg->append(m_pAbiFlags);
  }
  
  bool MipsGNULDBackend::relaxRelocation(IRBuilder& pBuilder, Relocation& pRel) {
    uint64_t sym_value = 0x0;
  
    LDSymbol* symbol = pRel.symInfo()->outSymbol();
    if (symbol->hasFragRef()) {
      uint64_t value = symbol->fragRef()->getOutputOffset();
      uint64_t addr = symbol->fragRef()->frag()->getParent()->getSection().addr();
      sym_value = addr + value;
    }
  
    Stub* stub = getStubFactory()->create(
        pRel, sym_value, pBuilder, *getBRIslandFactory());
  
    if (stub == NULL)
      return false;
  
    assert(stub->symInfo() != NULL);
    // reset the branch target of the reloc to this stub instead
    pRel.setSymInfo(stub->symInfo());
  
    // increase the size of .symtab and .strtab
    LDSection& symtab = getOutputFormat()->getSymTab();
    LDSection& strtab = getOutputFormat()->getStrTab();
    symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf32_Sym));
    strtab.setSize(strtab.size() + stub->symInfo()->nameSize() + 1);
  
    return true;
  }
  
  bool MipsGNULDBackend::doRelax(Module& pModule,
                                 IRBuilder& pBuilder,
                                 bool& pFinished) {
    assert(getStubFactory() != NULL && getBRIslandFactory() != NULL);
  
    bool isRelaxed = false;
  
    for (Module::obj_iterator input = pModule.obj_begin();
         input != pModule.obj_end();
         ++input) {
      LDContext* context = (*input)->context();
  
      for (LDContext::sect_iterator rs = context->relocSectBegin();
           rs != context->relocSectEnd();
           ++rs) {
        LDSection* sec = *rs;
  
        if (LDFileFormat::Ignore == sec->kind() || !sec->hasRelocData())
          continue;
  
        for (RelocData::iterator reloc = sec->getRelocData()->begin();
             reloc != sec->getRelocData()->end();
             ++reloc) {
          if (llvm::ELF::R_MIPS_26 != reloc->type())
            continue;
  
          if (relaxRelocation(pBuilder, *llvm::cast<Relocation>(reloc)))
            isRelaxed = true;
        }
      }
    }
  
    // find the first fragment w/ invalid offset due to stub insertion
    std::vector<Fragment*> invalid_frags;
    pFinished = true;
    for (BranchIslandFactory::iterator ii = getBRIslandFactory()->begin(),
                                       ie = getBRIslandFactory()->end();
         ii != ie;
         ++ii) {
      BranchIsland& island = *ii;
      if (island.size() > stubGroupSize()) {
        error(diag::err_no_space_to_place_stubs) << stubGroupSize();
        return false;
      }
  
      if (island.numOfStubs() == 0) {
        continue;
      }
  
      Fragment* exit = &*island.end();
      if (exit == island.begin()->getParent()->end()) {
        continue;
      }
  
      if ((island.offset() + island.size()) > exit->getOffset()) {
        if (invalid_frags.empty() ||
            (invalid_frags.back()->getParent() != island.getParent())) {
          invalid_frags.push_back(exit);
          pFinished = false;
        }
        continue;
      }
    }
  
    // reset the offset of invalid fragments
    for (auto it = invalid_frags.begin(), ie = invalid_frags.end(); it != ie;
         ++it) {
      Fragment* invalid = *it;
      while (invalid != NULL) {
        invalid->setOffset(invalid->getPrevNode()->getOffset() +
                           invalid->getPrevNode()->size());
        invalid = invalid->getNextNode();
      }
    }
  
    // reset the size of section that has stubs inserted.
    if (isRelaxed) {
      SectionData* prev = NULL;
      for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(),
                                         island_end = getBRIslandFactory()->end();
           island != island_end;
           ++island) {
        SectionData* sd = (*island).begin()->getParent();
        if ((*island).numOfStubs() != 0) {
          if (sd != prev) {
            sd->getSection().setSize(sd->back().getOffset() + sd->back().size());
          }
        }
        prev = sd;
      }
    }
  
    return isRelaxed;
  }
  
  bool MipsGNULDBackend::initTargetStubs() {
    if (getStubFactory() == NULL)
      return false;
  
    getStubFactory()->addPrototype(new MipsLA25Stub(*this));
    return true;
  }
  
  bool MipsGNULDBackend::readRelocation(const llvm::ELF::Elf32_Rel& pRel,
                                        Relocation::Type& pType,
                                        uint32_t& pSymIdx,
                                        uint32_t& pOffset) const {
    return GNULDBackend::readRelocation(pRel, pType, pSymIdx, pOffset);
  }
  
  bool MipsGNULDBackend::readRelocation(const llvm::ELF::Elf32_Rela& pRel,
                                        Relocation::Type& pType,
                                        uint32_t& pSymIdx,
                                        uint32_t& pOffset,
                                        int32_t& pAddend) const {
    return GNULDBackend::readRelocation(pRel, pType, pSymIdx, pOffset, pAddend);
  }
  
  bool MipsGNULDBackend::readRelocation(const llvm::ELF::Elf64_Rel& pRel,
                                        Relocation::Type& pType,
                                        uint32_t& pSymIdx,
                                        uint64_t& pOffset) const {
    uint64_t r_info = 0x0;
    if (llvm::sys::IsLittleEndianHost) {
      pOffset = pRel.r_offset;
      r_info = pRel.r_info;
    } else {
      pOffset = mcld::bswap64(pRel.r_offset);
      r_info = mcld::bswap64(pRel.r_info);
    }
  
    // MIPS 64 little endian (we do not support big endian now)
    // has a "special" encoding of r_info relocation
    // field. Instead of one 64 bit little endian number, it is a little
    // endian 32 bit number followed by a 32 bit big endian number.
    pType = mcld::bswap32(r_info >> 32);
    pSymIdx = r_info & 0xffffffff;
    return true;
  }
  
  bool MipsGNULDBackend::readRelocation(const llvm::ELF::Elf64_Rela& pRel,
                                        Relocation::Type& pType,
                                        uint32_t& pSymIdx,
                                        uint64_t& pOffset,
                                        int64_t& pAddend) const {
    uint64_t r_info = 0x0;
    if (llvm::sys::IsLittleEndianHost) {
      pOffset = pRel.r_offset;
      r_info = pRel.r_info;
      pAddend = pRel.r_addend;
    } else {
      pOffset = mcld::bswap64(pRel.r_offset);
      r_info = mcld::bswap64(pRel.r_info);
      pAddend = mcld::bswap64(pRel.r_addend);
    }
  
    pType = mcld::bswap32(r_info >> 32);
    pSymIdx = r_info & 0xffffffff;
    return true;
  }
  
  void MipsGNULDBackend::emitRelocation(llvm::ELF::Elf32_Rel& pRel,
                                        Relocation::Type pType,
                                        uint32_t pSymIdx,
                                        uint32_t pOffset) const {
    GNULDBackend::emitRelocation(pRel, pType, pSymIdx, pOffset);
  }
  
  void MipsGNULDBackend::emitRelocation(llvm::ELF::Elf32_Rela& pRel,
                                        Relocation::Type pType,
                                        uint32_t pSymIdx,
                                        uint32_t pOffset,
                                        int32_t pAddend) const {
    GNULDBackend::emitRelocation(pRel, pType, pSymIdx, pOffset, pAddend);
  }
  
  void MipsGNULDBackend::emitRelocation(llvm::ELF::Elf64_Rel& pRel,
                                        Relocation::Type pType,
                                        uint32_t pSymIdx,
                                        uint64_t pOffset) const {
    uint64_t r_info = mcld::bswap32(pType);
    r_info <<= 32;
    r_info |= pSymIdx;
  
    pRel.r_info = r_info;
    pRel.r_offset = pOffset;
  }
  
  void MipsGNULDBackend::emitRelocation(llvm::ELF::Elf64_Rela& pRel,
                                        Relocation::Type pType,
                                        uint32_t pSymIdx,
                                        uint64_t pOffset,
                                        int64_t pAddend) const {
    uint64_t r_info = mcld::bswap32(pType);
    r_info <<= 32;
    r_info |= pSymIdx;
  
    pRel.r_info = r_info;
    pRel.r_offset = pOffset;
    pRel.r_addend = pAddend;
  }
  
  namespace {
  struct ISATreeEdge {
    unsigned child;
    unsigned parent;
  };
  }
  
  static ISATreeEdge isaTree[] = {
      // MIPS32R6 and MIPS64R6 are not compatible with other extensions
  
      // MIPS64 extensions.
      {llvm::ELF::EF_MIPS_ARCH_64R2, llvm::ELF::EF_MIPS_ARCH_64},
      // MIPS V extensions.
      {llvm::ELF::EF_MIPS_ARCH_64, llvm::ELF::EF_MIPS_ARCH_5},
      // MIPS IV extensions.
      {llvm::ELF::EF_MIPS_ARCH_5, llvm::ELF::EF_MIPS_ARCH_4},
      // MIPS III extensions.
      {llvm::ELF::EF_MIPS_ARCH_4, llvm::ELF::EF_MIPS_ARCH_3},
      // MIPS32 extensions.
      {llvm::ELF::EF_MIPS_ARCH_32R2, llvm::ELF::EF_MIPS_ARCH_32},
      // MIPS II extensions.
      {llvm::ELF::EF_MIPS_ARCH_3, llvm::ELF::EF_MIPS_ARCH_2},
      {llvm::ELF::EF_MIPS_ARCH_32, llvm::ELF::EF_MIPS_ARCH_2},
      // MIPS I extensions.
      {llvm::ELF::EF_MIPS_ARCH_2, llvm::ELF::EF_MIPS_ARCH_1},
  };
  
  static bool isIsaMatched(uint32_t base, uint32_t ext) {
    if (base == ext)
      return true;
    if (base == llvm::ELF::EF_MIPS_ARCH_32 &&
        isIsaMatched(llvm::ELF::EF_MIPS_ARCH_64, ext))
      return true;
    if (base == llvm::ELF::EF_MIPS_ARCH_32R2 &&
        isIsaMatched(llvm::ELF::EF_MIPS_ARCH_64R2, ext))
      return true;
    for (const auto &edge : isaTree) {
      if (ext == edge.child) {
        ext = edge.parent;
        if (ext == base)
          return true;
      }
    }
    return false;
  }
  
  static bool getAbiFlags(const Input& pInput, uint64_t elfFlags, bool& hasFlags,
                          MipsAbiFlags& pFlags) {
    MipsAbiFlags pElfFlags = {};
    if (!MipsAbiFlags::fillByElfFlags(pInput, elfFlags, pElfFlags))
      return false;
  
    const LDContext* ctx = pInput.context();
    for (auto it = ctx->sectBegin(), ie = ctx->sectEnd(); it != ie; ++it)
      if ((*it)->type() == llvm::ELF::SHT_MIPS_ABIFLAGS) {
        if (!MipsAbiFlags::fillBySection(pInput, **it, pFlags))
          return false;
        if (!MipsAbiFlags::isCompatible(pInput, pElfFlags, pFlags))
          return false;
        hasFlags = true;
        return true;
      }
  
    pFlags = pElfFlags;
    return true;
  }
  
  static const char* getNanName(uint64_t flags) {
    return flags & llvm::ELF::EF_MIPS_NAN2008 ? "2008" : "legacy";
  }
  
  static bool mergeElfFlags(const Input& pInput, uint64_t& oldElfFlags,
                            uint64_t newElfFlags) {
    // PIC code is inherently CPIC and may not set CPIC flag explicitly.
    // Ensure that this flag will exist in the linked file.
    if (newElfFlags & llvm::ELF::EF_MIPS_PIC)
      newElfFlags |= llvm::ELF::EF_MIPS_CPIC;
  
    if (newElfFlags & llvm::ELF::EF_MIPS_ARCH_ASE_M16) {
      error(diag::error_Mips_m16_unsupported) << pInput.name();
      return false;
    }
  
    if (!oldElfFlags) {
      oldElfFlags = newElfFlags;
      return true;
    }
  
    uint64_t newPic =
        newElfFlags & (llvm::ELF::EF_MIPS_PIC | llvm::ELF::EF_MIPS_CPIC);
    uint64_t oldPic =
        oldElfFlags & (llvm::ELF::EF_MIPS_PIC | llvm::ELF::EF_MIPS_CPIC);
  
    // Check PIC / CPIC flags compatibility.
    if ((newPic != 0) != (oldPic != 0))
      warning(diag::warn_Mips_abicalls_linking) << pInput.name();
  
    if (!(newPic & llvm::ELF::EF_MIPS_PIC))
      oldElfFlags &= ~llvm::ELF::EF_MIPS_PIC;
    if (newPic)
      oldElfFlags |= llvm::ELF::EF_MIPS_CPIC;
  
    // Check ISA compatibility.
    uint64_t newArch = newElfFlags & llvm::ELF::EF_MIPS_ARCH;
    uint64_t oldArch = oldElfFlags & llvm::ELF::EF_MIPS_ARCH;
    if (!isIsaMatched(newArch, oldArch)) {
      if (!isIsaMatched(oldArch, newArch)) {
        error(diag::error_Mips_inconsistent_arch)
            << ArchName(oldArch) << ArchName(newArch) << pInput.name();
        return false;
      }
      oldElfFlags &= ~llvm::ELF::EF_MIPS_ARCH;
      oldElfFlags |= newArch;
    }
  
    // Check ABI compatibility.
    uint32_t newAbi = newElfFlags & llvm::ELF::EF_MIPS_ABI;
    uint32_t oldAbi = oldElfFlags & llvm::ELF::EF_MIPS_ABI;
    if (newAbi != oldAbi && newAbi && oldAbi) {
      error(diag::error_Mips_inconsistent_abi) << pInput.name();
      return false;
    }
  
    // Check -mnan flags compatibility.
    if ((newElfFlags & llvm::ELF::EF_MIPS_NAN2008) !=
        (oldElfFlags & llvm::ELF::EF_MIPS_NAN2008)) {
      // Linking -mnan=2008 and -mnan=legacy modules
      error(diag::error_Mips_inconsistent_mnan)
          << getNanName(oldElfFlags) << getNanName(newElfFlags) << pInput.name();
      return false;
    }
  
    // Check ASE compatibility.
    uint64_t newAse = newElfFlags & llvm::ELF::EF_MIPS_ARCH_ASE;
    uint64_t oldAse = oldElfFlags & llvm::ELF::EF_MIPS_ARCH_ASE;
    if (newAse != oldAse)
      oldElfFlags |= newAse;
  
    // Check FP64 compatibility.
    if ((newElfFlags & llvm::ELF::EF_MIPS_FP64) !=
        (oldElfFlags & llvm::ELF::EF_MIPS_FP64)) {
      // Linking -mnan=2008 and -mnan=legacy modules
      error(diag::error_Mips_inconsistent_fp64) << pInput.name();
      return false;
    }
  
    oldElfFlags |= newElfFlags & llvm::ELF::EF_MIPS_NOREORDER;
    oldElfFlags |= newElfFlags & llvm::ELF::EF_MIPS_MICROMIPS;
    oldElfFlags |= newElfFlags & llvm::ELF::EF_MIPS_NAN2008;
    oldElfFlags |= newElfFlags & llvm::ELF::EF_MIPS_32BITMODE;
  
    return true;
  }
  
  void MipsGNULDBackend::saveTPOffset(const Input& pInput) {
    const LDContext* ctx = pInput.context();
    for (auto it = ctx->sectBegin(), ie = ctx->sectEnd(); it != ie; ++it) {
      LDSection* sect = *it;
      if (sect->flag() & llvm::ELF::SHF_TLS) {
        m_TpOffsetMap[&pInput] = sect->addr() + 0x7000;
        m_DtpOffsetMap[&pInput] = sect->addr() + 0x8000;
        break;
      }
    }
  }
  
  void MipsGNULDBackend::preMergeSections(Module& pModule) {
    uint64_t elfFlags = 0;
    bool hasAbiFlags = false;
    MipsAbiFlags abiFlags = {};
    for (const Input *input : pModule.getObjectList()) {
      if (input->type() != Input::Object)
        continue;
  
      uint64_t newElfFlags = m_ElfFlagsMap[input];
  
      MipsAbiFlags newAbiFlags = {};
      if (!getAbiFlags(*input, newElfFlags, hasAbiFlags, newAbiFlags))
        continue;
  
      if (!mergeElfFlags(*input, elfFlags, newElfFlags))
        continue;
  
      if (!MipsAbiFlags::merge(*input, abiFlags, newAbiFlags))
        continue;
  
      saveTPOffset(*input);
    }
  
    m_pInfo.setElfFlags(elfFlags);
    if (hasAbiFlags)
      m_pAbiInfo = abiFlags;
  }
  
  bool MipsGNULDBackend::mergeSection(Module& pModule, const Input& pInput,
                                      LDSection& pSection) {
    if (pSection.flag() & llvm::ELF::SHF_MIPS_GPREL) {
      SectionData* sd = NULL;
      if (!m_psdata->hasSectionData()) {
        sd = IRBuilder::CreateSectionData(*m_psdata);
        m_psdata->setSectionData(sd);
      }
      sd = m_psdata->getSectionData();
      moveSectionData(*pSection.getSectionData(), *sd);
    } else if (pSection.type() == llvm::ELF::SHT_MIPS_ABIFLAGS) {
      // Nothing to do because we handle all .MIPS.abiflags sections
      // in the preMergeSections method.
    } else {
      ObjectBuilder builder(pModule);
      builder.MergeSection(pInput, pSection);
    }
    return true;
  }
  
  void MipsGNULDBackend::moveSectionData(SectionData& pFrom, SectionData& pTo) {
    assert(&pFrom != &pTo && "Cannot move section data to itself!");
  
    uint64_t offset = pTo.getSection().size();
    AlignFragment* align = NULL;
    if (pFrom.getSection().align() > 1) {
      // if the align constraint is larger than 1, append an alignment
      unsigned int alignment = pFrom.getSection().align();
      align = new AlignFragment(/*alignment*/ alignment,
                                /*the filled value*/ 0x0,
                                /*the size of filled value*/ 1u,
                                /*max bytes to emit*/ alignment - 1);
      align->setOffset(offset);
      align->setParent(&pTo);
      pTo.getFragmentList().push_back(align);
      offset += align->size();
    }
  
    // move fragments from pFrom to pTO
    SectionData::FragmentListType& from_list = pFrom.getFragmentList();
    SectionData::FragmentListType& to_list = pTo.getFragmentList();
    SectionData::FragmentListType::iterator frag, fragEnd = from_list.end();
    for (frag = from_list.begin(); frag != fragEnd; ++frag) {
      frag->setParent(&pTo);
      frag->setOffset(offset);
      offset += frag->size();
    }
    to_list.splice(to_list.end(), from_list);
  
    // set up pTo's header
    pTo.getSection().setSize(offset);
  }
  
  //===----------------------------------------------------------------------===//
  // Mips32GNULDBackend
  //===----------------------------------------------------------------------===//
  Mips32GNULDBackend::Mips32GNULDBackend(const LinkerConfig& pConfig,
                                         MipsGNUInfo* pInfo)
      : MipsGNULDBackend(pConfig, pInfo) {
  }
  
  bool Mips32GNULDBackend::initRelocator() {
    if (m_pRelocator == NULL)
      m_pRelocator = new Mips32Relocator(*this, config());
  
    return true;
  }
  
  void Mips32GNULDBackend::initTargetSections(Module& pModule,
                                              ObjectBuilder& pBuilder) {
    MipsGNULDBackend::initTargetSections(pModule, pBuilder);
  
    if (LinkerConfig::Object == config().codeGenType())
      return;
  
    ELFFileFormat* fileFormat = getOutputFormat();
  
    // initialize .got
    LDSection& got = fileFormat->getGOT();
    m_pGOT = new Mips32GOT(got);
  
    // initialize .got.plt
    LDSection& gotplt = fileFormat->getGOTPLT();
    m_pGOTPLT = new MipsGOTPLT(gotplt);
  
    // initialize .plt
    LDSection& plt = fileFormat->getPLT();
    m_pPLT = new MipsPLT(plt);
  }
  
  size_t Mips32GNULDBackend::getRelEntrySize() {
    return 8;
  }
  
  size_t Mips32GNULDBackend::getRelaEntrySize() {
    return 12;
  }
  
  //===----------------------------------------------------------------------===//
  // Mips64GNULDBackend
  //===----------------------------------------------------------------------===//
  Mips64GNULDBackend::Mips64GNULDBackend(const LinkerConfig& pConfig,
                                         MipsGNUInfo* pInfo)
      : MipsGNULDBackend(pConfig, pInfo) {
  }
  
  bool Mips64GNULDBackend::initRelocator() {
    if (m_pRelocator == NULL)
      m_pRelocator = new Mips64Relocator(*this, config());
  
    return true;
  }
  
  void Mips64GNULDBackend::initTargetSections(Module& pModule,
                                              ObjectBuilder& pBuilder) {
    MipsGNULDBackend::initTargetSections(pModule, pBuilder);
  
    if (LinkerConfig::Object == config().codeGenType())
      return;
  
    ELFFileFormat* fileFormat = getOutputFormat();
  
    // initialize .got
    LDSection& got = fileFormat->getGOT();
    m_pGOT = new Mips64GOT(got);
  
    // initialize .got.plt
    LDSection& gotplt = fileFormat->getGOTPLT();
    m_pGOTPLT = new MipsGOTPLT(gotplt);
  
    // initialize .plt
    LDSection& plt = fileFormat->getPLT();
    m_pPLT = new MipsPLT(plt);
  }
  
  size_t Mips64GNULDBackend::getRelEntrySize() {
    return 16;
  }
  
  size_t Mips64GNULDBackend::getRelaEntrySize() {
    return 24;
  }
  
  //===----------------------------------------------------------------------===//
  /// createMipsLDBackend - the help funtion to create corresponding MipsLDBackend
  ///
  static TargetLDBackend* createMipsLDBackend(const LinkerConfig& pConfig) {
    const llvm::Triple& triple = pConfig.targets().triple();
  
    if (triple.isOSDarwin()) {
      assert(0 && "MachO linker is not supported yet");
    }
    if (triple.isOSWindows()) {
      assert(0 && "COFF linker is not supported yet");
    }
  
    llvm::Triple::ArchType arch = triple.getArch();
  
    if (llvm::Triple::mips64el == arch)
      return new Mips64GNULDBackend(pConfig, new MipsGNUInfo(triple));
  
    assert(arch == llvm::Triple::mipsel);
    return new Mips32GNULDBackend(pConfig, new MipsGNUInfo(triple));
  }
  
  }  // namespace mcld
  
  //===----------------------------------------------------------------------===//
  // Force static initialization.
  //===----------------------------------------------------------------------===//
  extern "C" void MCLDInitializeMipsLDBackend() {
    mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheMipselTarget,
                                                  mcld::createMipsLDBackend);
    mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheMips64elTarget,
                                                  mcld::createMipsLDBackend);
  }
  