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_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;
}
// 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;
}
Relocator::Result lea(Relocation& pReloc, NyuziRelocator& pParent)
{
  Relocator::Address S = pReloc.symValue();
  Relocator::Address P = pReloc.place();
  int offset = S - (P + 4);

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

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

  return Relocator::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;
}
// 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_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;
}
// 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;
}