Relocator::Result relocPCREL(Relocation& pReloc, HexagonRelocator& pParent) {
  ResolveInfo* rsym = pReloc.symInfo();
  int64_t result;

  Relocator::Address S = pReloc.symValue();
  Relocator::DWord A = pReloc.addend();
  Relocator::DWord P = pReloc.place();

  FragmentRef& target_fragref = pReloc.targetRef();
  Fragment* target_frag = target_fragref.frag();
  LDSection& target_sect = target_frag->getParent()->getSection();

  result = (int64_t)(S + A - P);

  // for relocs inside non ALLOC, just apply
  if ((llvm::ELF::SHF_ALLOC & target_sect.flag()) == 0) {
    return applyRel(pReloc, result);
  }

  if (!rsym->isLocal()) {
    if (rsym->reserved() & HexagonRelocator::ReservePLT) {
      S = helper_get_PLT_address(*rsym, pParent);
      result = (int64_t)(S + A - P);
      applyRel(pReloc, result);
      return Relocator::OK;
    }
  }

  return applyRel(pReloc, result);
}
// R_386_32: S + A
X86RelocationFactory::Result abs32(Relocation& pReloc,
                                   const MCLDInfo& pLDInfo,
                                   X86RelocationFactory& pParent)
{
  ResolveInfo* rsym = pReloc.symInfo();
  RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
  RelocationFactory::DWord S = pReloc.symValue();

  if(rsym->isLocal() && (rsym->reserved() & X86GNULDBackend::ReserveRel)) {
    helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
    pReloc.target() = S + A;
    return X86RelocationFactory::OK;
  }
  else if(!rsym->isLocal()) {
    if(rsym->reserved() & X86GNULDBackend::ReservePLT) {
      S = helper_PLT(pReloc, pParent);
      pReloc.target() = S + A;
    }
    if(rsym->reserved() & X86GNULDBackend::ReserveRel) {
      if(helper_use_relative_reloc(*rsym, pLDInfo, pParent) ) {
        helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
      }
      else {
        helper_DynRel(pReloc, pReloc.type(), pParent);
        return X86RelocationFactory::OK;
      }
    }
  }

  // perform static relocation
  pReloc.target() = S + A;
  return X86RelocationFactory::OK;
}
uint32_t NyuziRelocator::getDebugStringOffset(Relocation& pReloc) const {
  if (pReloc.type() != llvm::ELF::R_NYUZI_ABS32)
    error(diag::unsupport_reloc_for_debug_string) << getName(pReloc.type());

  return pReloc.symInfo()->outSymbol()->fragRef()->offset() +
         pReloc.target() + pReloc.addend();
}
/// addStub - add a stub into the island
bool BranchIsland::addStub(const Stub* pPrototype,
                           const Relocation& pReloc,
                           Stub& pStub)
{
  bool exist = false;
  Key key(pPrototype, pReloc.symInfo()->outSymbol(), pReloc.addend());
  StubEntryType* entry = m_StubMap.insert(key, exist);
  if (!exist) {
    entry->setValue(&pStub);
    m_pRear = &pStub;
    SectionData* sd = m_Entry.getParent();

    // insert alignment fragment
    // TODO: check if we can reduce this alignment fragment for some cases
    AlignFragment* align_frag = new AlignFragment(pStub.alignment(),
                                                  0x0,
                                                  1u,
                                                  pStub.alignment() - 1);
    align_frag->setParent(sd);
    sd->getFragmentList().insert(end(), align_frag);
    align_frag->setOffset(align_frag->getPrevNode()->getOffset() +
                          align_frag->getPrevNode()->size());

    // insert stub fragment
    pStub.setParent(sd);
    sd->getFragmentList().insert(end(), &pStub);
    pStub.setOffset(pStub.getPrevNode()->getOffset() +
                    pStub.getPrevNode()->size());
  }
  return !exist;
}
Relocator::Result abs(Relocation& pReloc, NyuziRelocator& pParent)
{
  Relocator::DWord A = pReloc.addend();
  Relocator::DWord S = pReloc.symValue();
  pReloc.target() = S + A;

  return Relocator::OK;
}
// R_386_PC32: S + A - P
X86RelocationFactory::Result rel32(Relocation& pReloc,
                                   const MCLDInfo& pLDInfo,
                                   X86RelocationFactory& pParent)
{
  // perform static relocation
  RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
  pReloc.target() = pReloc.symValue() + A
      - pReloc.place(pParent.getLayout());
  return X86RelocationFactory::OK;
}
// R_386_GOTPC: GOT_ORG + A - P
X86RelocationFactory::Result gotpc32(Relocation& pReloc,
                                     const MCLDInfo& pLDInfo,
                                     X86RelocationFactory& pParent)
{
  RelocationFactory::DWord   A       = pReloc.target() + pReloc.addend();
  X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
  // Apply relocation.
  pReloc.target() = GOT_ORG + A - pReloc.place(pParent.getLayout());
  return X86RelocationFactory::OK;
}
void ARMGNULDBackend::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());
  }
}
// R_386_GOTOFF: S + A - GOT_ORG
X86RelocationFactory::Result gotoff32(Relocation& pReloc,
                                      const MCLDInfo& pLDInfo,
                                      X86RelocationFactory& pParent)
{
  RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
  X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
  X86RelocationFactory::Address S = pReloc.symValue();

  pReloc.target() = S + A - GOT_ORG;
  return X86RelocationFactory::OK;
}
// R_386_32: S + A
X86RelocationFactory::Result abs32(Relocation& pReloc,
                                   const MCLDInfo& pLDInfo,
                                   X86RelocationFactory& pParent)
{
  ResolveInfo* rsym = pReloc.symInfo();
  RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
  RelocationFactory::DWord S = pReloc.symValue();
  bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel(
                       *rsym, (rsym->reserved() & X86GNULDBackend::ReservePLT),
                       pLDInfo, pLDInfo.output(), true);

  const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
                                                  *(pReloc.targetRef().frag()));
  assert(NULL != target_sect);
  // If the flag of target section is not ALLOC, we will not scan this relocation
  // but perform static relocation. (e.g., applying .debug section)
  if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect->flag())) {
    pReloc.target() = S + A;
    return X86RelocationFactory::OK;
  }

  // A local symbol may need REL Type dynamic relocation
  if (rsym->isLocal() && has_dyn_rel) {
    helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
    pReloc.target() = S + A;
    return X86RelocationFactory::OK;
  }

  // An external symbol may need PLT and dynamic relocation
  if (!rsym->isLocal()) {
    if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
      S = helper_PLT(pReloc, pParent);
      pReloc.target() = S + A;
    }
    // If we generate a dynamic relocation (except R_386_RELATIVE)
    // for a place, we should not perform static relocation on it
    // in order to keep the addend store in the place correct.
    if (has_dyn_rel) {
      if (helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
        helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
      }
      else {
        helper_DynRel(pReloc, pReloc.type(), pParent);
        return X86RelocationFactory::OK;
      }
    }
  }

  // perform static relocation
  pReloc.target() = S + A;
  return X86RelocationFactory::OK;
}
// R_HEX_PLT_B22_PCREL: PLT(S) + A - P
Relocator::Result relocPLTB22PCREL(Relocation& pReloc,
                                   HexagonRelocator& pParent) {
  // PLT_S depends on if there is a PLT entry.
  Relocator::Address PLT_S;
  if ((pReloc.symInfo()->reserved() & HexagonRelocator::ReservePLT))
    PLT_S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
  else
    PLT_S = pReloc.symValue();
  Relocator::Address P = pReloc.place();
  uint32_t bitMask = FINDBITMASK(pReloc.target());
  uint32_t result = (PLT_S + pReloc.addend() - P) >> 2;
  pReloc.target() = pReloc.target() | ApplyMask<uint32_t>(bitMask, result);
  return Relocator::OK;
}
Relocator::Result memext(Relocation& pReloc, NyuziRelocator& pParent)
{
  Relocator::Address S = pReloc.symValue();
  Relocator::Address P = pReloc.place();
  Relocator::Address A = pReloc.addend();
  int offset = (S + A) - (P + 4);

  if (helper_check_signed_overflow(offset, 15))
    return Relocator::Overflow;

  pReloc.target() = helper_replace_field(pReloc.target(), offset, 10, 15);

  return Relocator::OK;
}
// R_HEX_GOTREL_LO16: and its class of relocs
// (S + A - GOT) : Signed Truncate
Relocator::Result relocGOTREL(Relocation& pReloc, HexagonRelocator& pParent) {
  Relocator::Address S = pReloc.symValue();
  Relocator::DWord A = pReloc.addend();
  Relocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();

  uint32_t bitMask = 0;
  uint32_t alignment = 1;
  uint32_t shift = 0;

  uint32_t result = (uint32_t)(S + A - GOT);

  switch (pReloc.type()) {
    case llvm::ELF::R_HEX_GOTREL_LO16:
      bitMask = 0x00c03fff;
      break;

    case llvm::ELF::R_HEX_GOTREL_HI16:
      bitMask = 0x00c03fff;
      shift = 16;
      alignment = 4;
      break;

    case llvm::ELF::R_HEX_GOTREL_32:
      bitMask = 0xffffffff;
      break;

    case llvm::ELF::R_HEX_GOTREL_32_6_X:
      bitMask = 0x0fff3fff;
      shift = 6;
      break;

    case llvm::ELF::R_HEX_GOTREL_16_X:
    case llvm::ELF::R_HEX_GOTREL_11_X:
      bitMask = FINDBITMASK(pReloc.target());
      break;

    default:
      // show proper error
      fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type())
                                          << "*****@*****.**";
  }

  if (result % alignment != 0)
    return Relocator::BadReloc;

  result >>= shift;

  pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
  return Relocator::OK;
}
// R_386_GOT32: GOT(S) + A - GOT_ORG
X86RelocationFactory::Result got32(Relocation& pReloc,
                                   const MCLDInfo& pLDInfo,
                                   X86RelocationFactory& pParent)
{
  if(!(pReloc.symInfo()->reserved()
       & (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) {
    return X86RelocationFactory::BadReloc;
  }
  X86RelocationFactory::Address GOT_S   = helper_GOT(pReloc, pLDInfo, pParent);
  RelocationFactory::DWord   A       = pReloc.target() + pReloc.addend();
  X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
  // Apply relocation.
  pReloc.target() = GOT_S + A - GOT_ORG;
  return X86RelocationFactory::OK;
}
// R_386_PLT32: PLT(S) + A - P
X86RelocationFactory::Result plt32(Relocation& pReloc,
                                   const MCLDInfo& pLDInfo,
                                   X86RelocationFactory& pParent)
{
  // PLT_S depends on if there is a PLT entry.
  X86RelocationFactory::Address PLT_S;
  if((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT))
    PLT_S = helper_PLT(pReloc, pParent);
  else
    PLT_S = pReloc.symValue();
  RelocationFactory::DWord   A       = pReloc.target() + pReloc.addend();
  X86RelocationFactory::Address P = pReloc.place(pParent.getLayout());
  pReloc.target() = PLT_S + A - P;
  return X86RelocationFactory::OK;
}
// R_HEX_GPREL16_0 and its class : Unsigned Verify
Relocator::Result relocGPREL(Relocation& pReloc, HexagonRelocator& pParent) {
  Relocator::Address S = pReloc.symValue();
  Relocator::DWord A = pReloc.addend();
  Relocator::DWord GP = pParent.getTarget().getGP();

  uint32_t result = (uint32_t)(S + A - GP);
  uint32_t shift = 0;
  uint32_t alignment = 1;

  switch (pReloc.type()) {
    case llvm::ELF::R_HEX_GPREL16_0:
      break;

    case llvm::ELF::R_HEX_GPREL16_1:
      shift = 1;
      alignment = 2;
      break;

    case llvm::ELF::R_HEX_GPREL16_2:
      shift = 2;
      alignment = 4;
      break;

    case llvm::ELF::R_HEX_GPREL16_3:
      shift = 3;
      alignment = 8;
      break;

    default:
      // show proper error
      fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type())
                                          << "*****@*****.**";
  }

  uint32_t range = 1 << 16;
  uint32_t bitMask = FINDBITMASK(pReloc.target());

  if ((shift != 0) && (result % alignment != 0))
    return Relocator::BadReloc;

  result >>= shift;

  if (result < range - 1) {
    pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
    return Relocator::OK;
  }
  return Relocator::Overflow;
}
// R_386_PC32: S + A - P
X86RelocationFactory::Result rel32(Relocation& pReloc,
                                   const MCLDInfo& pLDInfo,
                                   X86RelocationFactory& pParent)
{
  ResolveInfo* rsym = pReloc.symInfo();
  RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
  RelocationFactory::DWord S = pReloc.symValue();
  RelocationFactory::DWord P = pReloc.place(pParent.getLayout());

  const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
                                                  *(pReloc.targetRef().frag()));
  assert(NULL != target_sect);
  // If the flag of target section is not ALLOC, we will not scan this relocation
  // but perform static relocation. (e.g., applying .debug section)
  if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect->flag())) {
    pReloc.target() = S + A - P;
    return X86RelocationFactory::OK;
  }

  // An external symbol may need PLT and dynamic relocation
  if (!rsym->isLocal()) {
    if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
       S = helper_PLT(pReloc, pParent);
       pReloc.target() = S + A - P;
    }
    if (pParent.getTarget().symbolNeedsDynRel(
          *rsym, (rsym->reserved() & X86GNULDBackend::ReservePLT), pLDInfo,
                  pLDInfo.output(), false)) {
      if (helper_use_relative_reloc(*rsym, pLDInfo, pParent) ) {
        helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
      }
      else {
        helper_DynRel(pReloc, pReloc.type(), pParent);
          return X86RelocationFactory::OK;
      }
    }
  }

   // perform static relocation
  pReloc.target() = S + A - P;
  return X86RelocationFactory::OK;
}
Relocator::Result relocAbs(Relocation& pReloc, HexagonRelocator& pParent) {
  ResolveInfo* rsym = pReloc.symInfo();
  Relocator::Address S = pReloc.symValue();
  Relocator::DWord A = pReloc.addend();

  Relocation* rel_entry = pParent.getRelRelMap().lookUp(pReloc);
  bool has_dyn_rel = (rel_entry != NULL);

  // if the flag of target section is not ALLOC, we eprform only static
  // relocation.
  if (0 == (llvm::ELF::SHF_ALLOC &
            pReloc.targetRef().frag()->getParent()->getSection().flag())) {
    return applyAbs(pReloc);
  }

  // a local symbol with .rela type relocation
  if (rsym->isLocal() && has_dyn_rel) {
    rel_entry->setAddend(S + A);
    return Relocator::OK;
  }

  if (!rsym->isLocal()) {
    if (rsym->reserved() & HexagonRelocator::ReservePLT) {
      S = helper_get_PLT_address(*rsym, pParent);
    }

    if (has_dyn_rel) {
      if (llvm::ELF::R_HEX_32 == pReloc.type() &&
          helper_use_relative_reloc(*rsym, pParent)) {
        rel_entry->setAddend(S + A);
      } else {
        rel_entry->setAddend(A);
        return Relocator::OK;
      }
    }
  }

  return applyAbs(pReloc);
}
// R_HEX_32 and its class of relocations use only addend and symbol value
// S + A : result is unsigned truncate.
// Exception: R_HEX_32_6_X : unsigned verify
Relocator::Result applyAbs(Relocation& pReloc) {
  Relocator::Address S = pReloc.symValue();
  Relocator::DWord A = pReloc.addend();
  uint32_t result = (uint32_t)(S + A);
  uint32_t bitMask = 0;
  uint32_t effectiveBits = 0;
  uint32_t alignment = 1;
  uint32_t shift = 0;

  switch (pReloc.type()) {
    case llvm::ELF::R_HEX_LO16:
      bitMask = 0x00c03fff;
      break;

    case llvm::ELF::R_HEX_HI16:
      shift = 16;
      bitMask = 0x00c03fff;
      break;

    case llvm::ELF::R_HEX_32:
      bitMask = 0xffffffff;
      break;

    case llvm::ELF::R_HEX_16:
      bitMask = 0x0000ffff;
      alignment = 2;
      break;

    case llvm::ELF::R_HEX_8:
      bitMask = 0x000000ff;
      alignment = 1;
      break;

    case llvm::ELF::R_HEX_12_X:
      bitMask = 0x000007e0;
      break;

    case llvm::ELF::R_HEX_32_6_X:
      bitMask = 0xfff3fff;
      shift = 6;
      effectiveBits = 26;
      break;

    case llvm::ELF::R_HEX_16_X:
    case llvm::ELF::R_HEX_11_X:
    case llvm::ELF::R_HEX_10_X:
    case llvm::ELF::R_HEX_9_X:
    case llvm::ELF::R_HEX_8_X:
    case llvm::ELF::R_HEX_7_X:
    case llvm::ELF::R_HEX_6_X:
      bitMask = FINDBITMASK(pReloc.target());
      break;

    default:
      // show proper error
      fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type())
                                          << "*****@*****.**";
  }

  if ((shift != 0) && (result % alignment != 0))
    return Relocator::BadReloc;

  result >>= shift;

  if (effectiveBits) {
    uint32_t range = 1 << effectiveBits;
    if (result > (range - 1))
      return Relocator::Overflow;
  }

  pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
  return Relocator::OK;
}
// R_HEX_B22_PCREL and its class of relocations, use
// S + A - P : result is signed verify.
// Exception: R_HEX_B32_PCREL_X : signed truncate
// Another Exception: R_HEX_6_PCREL_X is unsigned truncate
Relocator::Result applyRel(Relocation& pReloc, int64_t pResult) {
  uint32_t bitMask = 0;
  uint32_t effectiveBits = 0;
  uint32_t alignment = 1;
  uint32_t result;
  uint32_t shift = 0;

  switch (pReloc.type()) {
    case llvm::ELF::R_HEX_B22_PCREL:
      bitMask = 0x01ff3ffe;
      effectiveBits = 22;
      alignment = 4;
      shift = 2;
      break;

    case llvm::ELF::R_HEX_B15_PCREL:
      bitMask = 0x00df20fe;
      effectiveBits = 15;
      alignment = 4;
      shift = 2;
      break;

    case llvm::ELF::R_HEX_B7_PCREL:
      bitMask = 0x00001f18;
      effectiveBits = 7;
      alignment = 4;
      shift = 2;
      break;

    case llvm::ELF::R_HEX_B13_PCREL:
      bitMask = 0x00202ffe;
      effectiveBits = 13;
      alignment = 4;
      shift = 2;
      break;

    case llvm::ELF::R_HEX_B9_PCREL:
      bitMask = 0x003000fe;
      effectiveBits = 9;
      alignment = 4;
      shift = 2;
      break;

    case llvm::ELF::R_HEX_B32_PCREL_X:
      bitMask = 0xfff3fff;
      shift = 6;
      break;

    case llvm::ELF::R_HEX_B22_PCREL_X:
      bitMask = 0x01ff3ffe;
      effectiveBits = 22;
      pResult &= 0x3f;
      break;

    case llvm::ELF::R_HEX_B15_PCREL_X:
      bitMask = 0x00df20fe;
      effectiveBits = 15;
      pResult &= 0x3f;
      break;

    case llvm::ELF::R_HEX_B13_PCREL_X:
      bitMask = 0x00202ffe;
      effectiveBits = 13;
      pResult &= 0x3f;
      break;

    case llvm::ELF::R_HEX_B9_PCREL_X:
      bitMask = 0x003000fe;
      effectiveBits = 9;
      pResult &= 0x3f;
      break;

    case llvm::ELF::R_HEX_B7_PCREL_X:
      bitMask = 0x00001f18;
      effectiveBits = 7;
      pResult &= 0x3f;
      break;

    case llvm::ELF::R_HEX_32_PCREL:
      bitMask = 0xffffffff;
      effectiveBits = 32;
      break;

    case llvm::ELF::R_HEX_6_PCREL_X:
      // This is unique since it has a unsigned operand and its truncated
      bitMask = FINDBITMASK(pReloc.target());
      result = pReloc.addend() + pReloc.symValue() - pReloc.place();
      pReloc.target() |= ApplyMask<uint32_t>(bitMask, result);
      return Relocator::OK;

    default:
      // show proper error
      fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type())
                                          << "*****@*****.**";
  }

  if ((shift != 0) && (pResult % alignment != 0))
    return Relocator::BadReloc;

  pResult >>= shift;

  if (effectiveBits) {
    int64_t range = 1LL << (effectiveBits - 1);
    if ((pResult > (range - 1)) || (pResult < -range))
      return Relocator::Overflow;
  }

  pReloc.target() |= (uint32_t)ApplyMask<int32_t>(bitMask, pResult);
  return Relocator::OK;
}