Beispiel #1
0
void Stub::applyFixup(Relocation& pSrcReloc,
                      IRBuilder& pBuilder,
                      BranchIsland& pIsland) {
  // build a name for stub symbol
  std::string sym_name("__");
  sym_name.append(pSrcReloc.symInfo()->name())
          .append("_")
          .append(name())
          .append("@")
          .append(pIsland.name());

  // create LDSymbol for the stub
  LDSymbol* symbol =
      pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
          sym_name,
          ResolveInfo::Function,
          ResolveInfo::Define,
          ResolveInfo::Local,
          size(),
          initSymValue(),
          FragmentRef::Create(*this, initSymValue()),
          ResolveInfo::Default);
  setSymInfo(symbol->resolveInfo());

  // add relocations of this stub (i.e., set the branch target of the stub)
  for (fixup_iterator it = fixup_begin(), ie = fixup_end(); it != ie; ++it) {
    Relocation* reloc =
        Relocation::Create((*it)->type(),
                           *(FragmentRef::Create(*this, (*it)->offset())),
                           (*it)->addend());
    reloc->setSymInfo(pSrcReloc.symInfo());
    pIsland.addRelocation(*reloc);
  }
}
void X86RelocationFactory::applyRelocation(Relocation& pRelocation,
                                           const MCLDInfo& pLDInfo)
{
  Relocation::Type type = pRelocation.type();

  /// the prototype of applying function
  typedef Result (*ApplyFunctionType)(Relocation& pReloc,
				      const MCLDInfo& pLDInfo,
                                      X86RelocationFactory& pParent);

  // the table entry of applying functions
  struct ApplyFunctionTriple {
    ApplyFunctionType func;
    unsigned int type;
    const char* name;
  };

  // declare the table of applying functions
  static ApplyFunctionTriple apply_functions[] = {
    DECL_X86_APPLY_RELOC_FUNC_PTRS
  };

  if (type >= sizeof (apply_functions) / sizeof (apply_functions[0]) ) {
    llvm::report_fatal_error(llvm::Twine("Unknown relocation type ") +
			     llvm::Twine((int) type) +
			     llvm::Twine(" to symbol `") +
                             pRelocation.symInfo()->name() +
                             llvm::Twine("'."));
    return;
  }

  // apply the relocation
  Result result = apply_functions[type].func(pRelocation, pLDInfo, *this);

  // check result
  if (Overflow == result) {
    llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
                             llvm::Twine(apply_functions[type].name) +
                             llvm::Twine("' causes overflow. on symbol: `") +
                             llvm::Twine(pRelocation.symInfo()->name()) +
                             llvm::Twine("'."));
    return;
  }

  if (BadReloc == result) {
    llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
                             llvm::Twine(apply_functions[type].name) +
                             llvm::Twine("' encounters unexpected opcode. "
                                         "on symbol: `") +
                             llvm::Twine(pRelocation.symInfo()->name()) +
                             llvm::Twine("'."));
    return;
  }
}
// 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;
}
void HexagonRelocator::scanRelocation(Relocation& pReloc,
                                      IRBuilder& pLinker,
                                      Module& pModule,
                                      LDSection& pSection,
                                      Input& pInput) {
  if (LinkerConfig::Object == config().codeGenType())
    return;

  // rsym - The relocation target symbol
  ResolveInfo* rsym = pReloc.symInfo();
  assert(rsym != NULL &&
         "ResolveInfo of relocation not set while scanRelocation");

  if (config().isCodeStatic())
    return;

  assert(pSection.getLink() != NULL);
  if ((pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC) == 0)
    return;

  if (rsym->isLocal())  // rsym is local
    scanLocalReloc(pReloc, pLinker, pModule, pSection);
  else  // rsym is external
    scanGlobalReloc(pReloc, pLinker, pModule, pSection);

  // check if we should issue undefined reference for the relocation target
  // symbol
  if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
    issueUndefRef(pReloc, pSection, pInput);
}
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;
}
Beispiel #7
0
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);
  // 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;
}
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);
}
void GarbageCollection::setUpReachedSections()
{
  // traverse all the input relocations to setup the reached sections
  Module::obj_iterator input, inEnd = m_Module.obj_end();
  for (input = m_Module.obj_begin(); input != inEnd; ++input) {
    LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
    for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
      // bypass the discarded relocation section
      // 1. its section kind is changed to Ignore. (The target section is a
      // discarded group section.)
      // 2. it has no reloc data. (All symbols in the input relocs are in the
      // discarded group sections)
      LDSection* reloc_sect = *rs;
      LDSection* apply_sect = reloc_sect->getLink();
      if ((LDFileFormat::Ignore == reloc_sect->kind()) ||
          (!reloc_sect->hasRelocData()))
        continue;

      // bypass the apply target sections which are not handled by gc (currently
      // we only handle the Regular and BSS sections)
      if (apply_sect->kind() != LDFileFormat::Regular &&
          apply_sect->kind() != LDFileFormat::BSS)
        continue;

      bool add_first = false;
      SectionListTy* reached_sects = NULL;
      RelocData::iterator reloc_it, rEnd = reloc_sect->getRelocData()->end();
      for (reloc_it = reloc_sect->getRelocData()->begin(); reloc_it != rEnd;
                                                                   ++reloc_it) {
        Relocation* reloc = llvm::cast<Relocation>(reloc_it);
        ResolveInfo* sym = reloc->symInfo();
        // only the target symbols defined in the input fragments can make the
        // reference
        if (NULL == sym)
          continue;
        if (!sym->isDefine() || !sym->outSymbol()->hasFragRef())
          continue;

        // only the target symbols defined in the concerned sections can make
        // the reference
        const LDSection* target_sect =
                &sym->outSymbol()->fragRef()->frag()->getParent()->getSection();
        if (target_sect->kind() != LDFileFormat::Regular &&
            target_sect->kind() != LDFileFormat::BSS)
          continue;

        // setup the reached list, if we first add the element to reached list
        // of this section, create an entry in ReachedSections map
        if (!add_first) {
          assert(NULL == reached_sects);
          reached_sects = &m_ReachedSections[apply_sect];
          add_first = true;
        }
        reached_sects->insert(target_sect);
      }
      reached_sects = NULL;
      add_first = false;
    }
  }
}
/// checkValidReloc - When we attempt to generate a dynamic relocation for
/// ouput file, check if the relocation is supported by dynamic linker.
void ARMGNULDBackend::checkValidReloc(Relocation& pReloc,
                                      const MCLDInfo& pLDInfo,
                                      const Output& pOutput) const
{
  // If not building a PIC object, no relocation type is invalid
  if (!isPIC(pLDInfo, pOutput))
    return;

  switch(pReloc.type()) {
    case llvm::ELF::R_ARM_RELATIVE:
    case llvm::ELF::R_ARM_COPY:
    case llvm::ELF::R_ARM_GLOB_DAT:
    case llvm::ELF::R_ARM_JUMP_SLOT:
    case llvm::ELF::R_ARM_ABS32:
    case llvm::ELF::R_ARM_ABS32_NOI:
    case llvm::ELF::R_ARM_PC24:
    case llvm::ELF::R_ARM_TLS_DTPMOD32:
    case llvm::ELF::R_ARM_TLS_DTPOFF32:
    case llvm::ELF::R_ARM_TLS_TPOFF32:
      break;

    default:
      llvm::report_fatal_error(llvm::Twine("Attempt to generate unsupported") +
                               llvm::Twine(" relocation type ") +
                               llvm::Twine((int)pReloc.type()) +
                               llvm::Twine(" for symbol '") +
                               llvm::Twine(pReloc.symInfo()->name()) +
                               llvm::Twine("', recompile with -fPIC")
                              );
      break;
  }
}
// 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;
}
void ARMGNULDBackend::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");

  // Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
  // entries should be created.
  // FIXME: Below judgements concern only .so is generated as output
  // FIXME: Below judgements concern nothing about TLS related relocation

  // 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()) {
      createARMGOT(pLinker, pOutput);
    }
  }

  // rsym is local
  if(rsym->isLocal())
    scanLocalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);

  // rsym is external
  else
    scanGlobalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);

}
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());
  }
}
void HexagonRelocator::partialScanRelocation(Relocation& pReloc,
                                             Module& pModule,
                                             const LDSection& pSection) {
  pReloc.updateAddend();
  // if we meet a section symbol
  if (pReloc.symInfo()->type() == ResolveInfo::Section) {
    LDSymbol* input_sym = pReloc.symInfo()->outSymbol();

    // 1. update the relocation target offset
    assert(input_sym->hasFragRef());
    // 2. get the output LDSection which the symbol defined in
    const LDSection& out_sect =
        input_sym->fragRef()->frag()->getParent()->getSection();
    ResolveInfo* sym_info =
        pModule.getSectionSymbolSet().get(out_sect)->resolveInfo();
    // set relocation target symbol to the output section symbol's resolveInfo
    pReloc.setSymInfo(sym_info);
  }
}
// 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;
}
void HexagonRelocator::scanLocalReloc(Relocation& pReloc,
                                      IRBuilder& pBuilder,
                                      Module& pModule,
                                      LDSection& pSection) {
  // rsym - The relocation target symbol
  ResolveInfo* rsym = pReloc.symInfo();

  switch (pReloc.type()) {
    case llvm::ELF::R_HEX_LO16:
    case llvm::ELF::R_HEX_HI16:
    case llvm::ELF::R_HEX_16:
    case llvm::ELF::R_HEX_8:
    case llvm::ELF::R_HEX_32_6_X:
    case llvm::ELF::R_HEX_16_X:
    case llvm::ELF::R_HEX_12_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:
      assert(!(rsym->reserved() & ReserveRel) &&
             "Cannot apply this relocation for read only section");
      return;

    case llvm::ELF::R_HEX_32:
      // If buiding PIC object (shared library or PIC executable),
      // a dynamic relocations with RELATIVE type to this location is needed.
      // Reserve an entry in .rel.dyn
      if (config().isCodeIndep()) {
        Relocation& reloc = helper_DynRel_init(rsym,
                                               *pReloc.targetRef().frag(),
                                               pReloc.targetRef().offset(),
                                               llvm::ELF::R_HEX_RELATIVE,
                                               *this);
        // we need to set up the relocation addend at apply relocation, record
        // the
        // relocation
        getRelRelMap().record(pReloc, reloc);

        // set Rel bit
        rsym->setReserved(rsym->reserved() | ReserveRel);
        getTarget().checkAndSetHasTextRel(*pSection.getLink());
      }
      return;

    default:
      return;
  }
}
void Relocator::issueUndefRef(Relocation& pReloc,
                              LDSection& pSection,
                              Input& pInput)
{
  FragmentRef::Offset undef_sym_pos = pReloc.targetRef().offset();
  std::string sect_name(pSection.name());
  sect_name = sect_name.substr(sect_name.find('.', /*pos=*/1));  // Drop .rel(a) prefix

  std::string reloc_sym(pReloc.symInfo()->name());
  if (reloc_sym.substr(0, 2) == "_Z")
    reloc_sym = demangleSymbol(reloc_sym);

  std::stringstream ss;
  ss << "0x" << std::hex << undef_sym_pos;
  std::string undef_sym_pos_hex(ss.str());

  if (sect_name.substr(0, 5) != ".text") {
    // Function name is only valid for text section
    fatal(diag::undefined_reference) << reloc_sym
                                     << pInput.path()
                                     << sect_name
                                     << undef_sym_pos_hex;
    return;
  }

  std::string caller_file_name;
  std::string caller_func_name;
  for (LDContext::sym_iterator i = pInput.context()->symTabBegin(),
       e = pInput.context()->symTabEnd(); i != e; ++i) {
    LDSymbol& sym = **i;
    if (sym.resolveInfo()->type() == ResolveInfo::File)
      caller_file_name = sym.resolveInfo()->name();

    if (sym.resolveInfo()->type() == ResolveInfo::Function &&
        sym.value() <= undef_sym_pos &&
        sym.value() + sym.size() > undef_sym_pos) {
      caller_func_name = sym.name();
      break;
    }
  }

  if (caller_func_name.substr(0, 2) == "_Z")
    caller_func_name = demangleSymbol(caller_func_name);

  fatal(diag::undefined_reference_text) << reloc_sym
                                        << pInput.path()
                                        << caller_file_name
                                        << caller_func_name;
}
// 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;
}
RelocationFactory::Result
X86RelocationFactory::applyRelocation(Relocation& pRelocation,
                                           const MCLDInfo& pLDInfo)
{
  Relocation::Type type = pRelocation.type();

  if (type >= sizeof (ApplyFunctions) / sizeof (ApplyFunctions[0]) ) {
    fatal(diag::unknown_relocation) << (int)type <<
                                       pRelocation.symInfo()->name();
    return Unknown;
  }

  // apply the relocation
  return ApplyFunctions[type].func(pRelocation, pLDInfo, *this);
}
// 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;
}
Beispiel #21
0
void DebugString::applyOffset(Relocation& pReloc, TargetLDBackend& pBackend) {
  // get the refered string
  ResolveInfo* info = pReloc.symInfo();
  // the symbol should point to the first region fragment in the debug
  // string section, get the input .debut_str region
  llvm::StringRef d_str;
  if (info->outSymbol()->fragRef()->frag()->getKind() == Fragment::Region) {
    RegionFragment* frag =
        llvm::cast<RegionFragment>(info->outSymbol()->fragRef()->frag());
    d_str = frag->getRegion();
  }
  uint32_t offset = pBackend.getRelocator()->getDebugStringOffset(pReloc);
  const char* str = d_str.data() + offset;

  // apply the relocation
  pBackend.getRelocator()->applyDebugStringOffset(pReloc,
      m_StringTable.getOutputOffset(llvm::StringRef(str, string_length(str))));
}
void NyuziRelocator::scanRelocation(Relocation& pReloc,
                                      IRBuilder& pBuilder,
                                      Module& pModule,
                                      LDSection& pSection,
                                      Input& pInput)
{
  ResolveInfo* rsym = pReloc.symInfo();
  assert(NULL != rsym &&
         "ResolveInfo of relocation not set while scanRelocation");

  assert(NULL != pSection.getLink());
  if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC))
    return;

  // check if we shoule issue undefined reference for the relocation target
  // symbol
  if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
    issueUndefRef(pReloc, pSection, pInput);
}
bool MipsLA25Stub::isMyDuty(const Relocation& pReloc,
                            uint64_t pSource,
                            uint64_t pTargetSymValue) const {
  if (llvm::ELF::R_MIPS_26 != pReloc.type())
    return false;

  const ResolveInfo* rsym = pReloc.symInfo();

  if (!rsym->isDefine())
    return false;

  if (rsym->isDyn() || rsym->isUndef())
    return false;

  if (!m_Target.hasNonPICBranch(rsym))
    return false;

  return true;
}
// 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;
}
// Get an relocation entry in .rel.dyn and set its type to pType,
// its FragmentRef to pReloc->targetFrag() and its ResolveInfo to pReloc->symInfo()
static
void helper_DynRel(Relocation& pReloc,
                   X86RelocationFactory::Type pType,
                   X86RelocationFactory& pParent)
{
  // rsym - The relocation target symbol
  ResolveInfo* rsym = pReloc.symInfo();
  X86GNULDBackend& ld_backend = pParent.getTarget();
  bool exist;

  Relocation& rel_entry =
    *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
  rel_entry.setType(pType);
  rel_entry.targetRef() = pReloc.targetRef();

  if(pType == llvm::ELF::R_386_RELATIVE)
    rel_entry.setSymInfo(0);
  else
    rel_entry.setSymInfo(rsym);
}
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);
}
void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc,
                                      const LDSymbol& pInputSym,
                                      MCLinker& pLinker,
                                      const MCLDInfo& pLDInfo,
                                      const Output& pOutput)
{
  // rsym - The relocation target symbol
  ResolveInfo* rsym = pReloc.symInfo();

  switch(pReloc.type()) {

    // Set R_ARM_TARGET1 to R_ARM_ABS32
    // Ref: GNU gold 1.11 arm.cc, line 9892
    case llvm::ELF::R_ARM_TARGET1:
      pReloc.setType(llvm::ELF::R_ARM_ABS32);
    case llvm::ELF::R_ARM_ABS32:
    case llvm::ELF::R_ARM_ABS16:
    case llvm::ELF::R_ARM_ABS12:
    case llvm::ELF::R_ARM_THM_ABS5:
    case llvm::ELF::R_ARM_ABS8:
    case llvm::ELF::R_ARM_BASE_ABS:
    case llvm::ELF::R_ARM_MOVW_ABS_NC:
    case llvm::ELF::R_ARM_MOVT_ABS:
    case llvm::ELF::R_ARM_THM_MOVW_ABS_NC:
    case llvm::ELF::R_ARM_THM_MOVT_ABS:
    case llvm::ELF::R_ARM_ABS32_NOI: {
      // Absolute relocation type, symbol may needs PLT entry or
      // dynamic relocation entry
      if(isSymbolNeedsPLT(*rsym, pLDInfo, pOutput)) {
        // create plt for this symbol if it does not have one
        if(!(rsym->reserved() & 0x8u)){
          // Create .got section if it doesn't exist
          if(NULL == m_pGOT)
            createARMGOT(pLinker, pOutput);
          // create .plt and .rel.plt if not exist
          if(NULL == m_pPLT)
            createARMPLTandRelPLT(pLinker, pOutput);
          // Symbol needs PLT entry, we need to reserve a PLT entry
          // and the corresponding GOT and dynamic relocation entry
          // in .got and .rel.plt. (GOT entry will be reserved simultaneously
          // when calling ARMPLT->reserveEntry())
          m_pPLT->reserveEntry();
          m_pRelPLT->reserveEntry(*m_pRelocFactory);
          // set PLT bit
          rsym->setReserved(rsym->reserved() | 0x8u);
        }
      }

      if(isSymbolNeedsDynRel(*rsym, pOutput, true)) {
        checkValidReloc(pReloc, pLDInfo, pOutput);
        // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
        // create .rel.dyn section if not exist
        if(NULL == m_pRelDyn)
          createARMRelDyn(pLinker, pOutput);
        m_pRelDyn->reserveEntry(*m_pRelocFactory);
        // set Rel bit
        rsym->setReserved(rsym->reserved() | 0x1u);
      }
      return;
    }

    case llvm::ELF::R_ARM_GOTOFF32:
    case llvm::ELF::R_ARM_GOTOFF12: {
      // A GOT section is needed
      if(NULL == m_pGOT)
        createARMGOT(pLinker, pOutput);
      return;
    }

    case llvm::ELF::R_ARM_BASE_PREL:
      // FIXME: Currently we only support R_ARM_BASE_PREL against
      // symbol _GLOBAL_OFFSET_TABLE_
      if(rsym != m_pGOTSymbol->resolveInfo()) {
        llvm::report_fatal_error(llvm::Twine("Do not support relocation '") +
                                 llvm::Twine("R_ARM_BASE_PREL' against symbol '") +
                                 llvm::Twine(rsym->name()) +
                                 llvm::Twine(".'"));
      }
    case llvm::ELF::R_ARM_REL32:
    case llvm::ELF::R_ARM_LDR_PC_G0:
    case llvm::ELF::R_ARM_SBREL32:
    case llvm::ELF::R_ARM_THM_PC8:
    case llvm::ELF::R_ARM_MOVW_PREL_NC:
    case llvm::ELF::R_ARM_MOVT_PREL:
    case llvm::ELF::R_ARM_THM_MOVW_PREL_NC:
    case llvm::ELF::R_ARM_THM_MOVT_PREL:
    case llvm::ELF::R_ARM_THM_ALU_PREL_11_0:
    case llvm::ELF::R_ARM_THM_PC12:
    case llvm::ELF::R_ARM_REL32_NOI:
    case llvm::ELF::R_ARM_ALU_PC_G0_NC:
    case llvm::ELF::R_ARM_ALU_PC_G0:
    case llvm::ELF::R_ARM_ALU_PC_G1_NC:
    case llvm::ELF::R_ARM_ALU_PC_G1:
    case llvm::ELF::R_ARM_ALU_PC_G2:
    case llvm::ELF::R_ARM_LDR_PC_G1:
    case llvm::ELF::R_ARM_LDR_PC_G2:
    case llvm::ELF::R_ARM_LDRS_PC_G0:
    case llvm::ELF::R_ARM_LDRS_PC_G1:
    case llvm::ELF::R_ARM_LDRS_PC_G2:
    case llvm::ELF::R_ARM_LDC_PC_G0:
    case llvm::ELF::R_ARM_LDC_PC_G1:
    case llvm::ELF::R_ARM_LDC_PC_G2:
    case llvm::ELF::R_ARM_ALU_SB_G0_NC:
    case llvm::ELF::R_ARM_ALU_SB_G0:
    case llvm::ELF::R_ARM_ALU_SB_G1_NC:
    case llvm::ELF::R_ARM_ALU_SB_G1:
    case llvm::ELF::R_ARM_ALU_SB_G2:
    case llvm::ELF::R_ARM_LDR_SB_G0:
    case llvm::ELF::R_ARM_LDR_SB_G1:
    case llvm::ELF::R_ARM_LDR_SB_G2:
    case llvm::ELF::R_ARM_LDRS_SB_G0:
    case llvm::ELF::R_ARM_LDRS_SB_G1:
    case llvm::ELF::R_ARM_LDRS_SB_G2:
    case llvm::ELF::R_ARM_LDC_SB_G0:
    case llvm::ELF::R_ARM_LDC_SB_G1:
    case llvm::ELF::R_ARM_LDC_SB_G2:
    case llvm::ELF::R_ARM_MOVW_BREL_NC:
    case llvm::ELF::R_ARM_MOVT_BREL:
    case llvm::ELF::R_ARM_MOVW_BREL:
    case llvm::ELF::R_ARM_THM_MOVW_BREL_NC:
    case llvm::ELF::R_ARM_THM_MOVT_BREL:
    case llvm::ELF::R_ARM_THM_MOVW_BREL: {
      // Relative addressing relocation, may needs dynamic relocation
      if(isSymbolNeedsDynRel(*rsym, pOutput, false)) {
        checkValidReloc(pReloc, pLDInfo, pOutput);
        // create .rel.dyn section if not exist
        if(NULL == m_pRelDyn)
          createARMRelDyn(pLinker, pOutput);
        m_pRelDyn->reserveEntry(*m_pRelocFactory);
        // set Rel bit
        rsym->setReserved(rsym->reserved() | 0x1u);
      }
      return;
    }

    case llvm::ELF::R_ARM_THM_CALL:
    case llvm::ELF::R_ARM_PLT32:
    case llvm::ELF::R_ARM_CALL:
    case llvm::ELF::R_ARM_JUMP24:
    case llvm::ELF::R_ARM_THM_JUMP24:
    case llvm::ELF::R_ARM_SBREL31:
    case llvm::ELF::R_ARM_PREL31:
    case llvm::ELF::R_ARM_THM_JUMP19:
    case llvm::ELF::R_ARM_THM_JUMP6:
    case llvm::ELF::R_ARM_THM_JUMP11:
    case llvm::ELF::R_ARM_THM_JUMP8: {
      // These are branch relocation (except PREL31)
      // A PLT entry is needed when building shared library

      // return if we already create plt for this symbol
      if(rsym->reserved() & 0x8u)
        return;

      // if symbol is defined in the ouput file and it's not
      // preemptible, no need plt
      if(rsym->isDefine() && !rsym->isDyn() &&
         !isSymbolPreemptible(*rsym, pLDInfo, pOutput)) {
        return;
      }

      // Create .got section if it doesn't exist
      if(NULL == m_pGOT)
        createARMGOT(pLinker, pOutput);

      // create .plt and .rel.plt if not exist
      if(NULL == m_pPLT)
         createARMPLTandRelPLT(pLinker, pOutput);
      // Symbol needs PLT entry, we need to reserve a PLT entry
      // and the corresponding GOT and dynamic relocation entry
      // in .got and .rel.plt. (GOT entry will be reserved simultaneously
      // when calling ARMPLT->reserveEntry())
      m_pPLT->reserveEntry();
      m_pRelPLT->reserveEntry(*m_pRelocFactory);
      // set PLT bit
      rsym->setReserved(rsym->reserved() | 0x8u);
      return;
    }

    // Set R_ARM_TARGET2 to R_ARM_GOT_PREL
    // Ref: GNU gold 1.11 arm.cc, line 9892
    case llvm::ELF::R_ARM_TARGET2:
      pReloc.setType(llvm::ELF::R_ARM_GOT_PREL);
    case llvm::ELF::R_ARM_GOT_BREL:
    case llvm::ELF::R_ARM_GOT_ABS:
    case llvm::ELF::R_ARM_GOT_PREL: {
      // Symbol needs GOT entry, reserve entry in .got
      // return if we already create GOT for this symbol
      if(rsym->reserved() & 0x6u)
        return;
      if(NULL == m_pGOT)
        createARMGOT(pLinker, pOutput);
      m_pGOT->reserveEntry();
      // If building shared object or the symbol is undefined, a dynamic
      // relocation is needed to relocate this GOT entry. Reserve an
      // entry in .rel.dyn
      if(Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) {
        // create .rel.dyn section if not exist
        if(NULL == m_pRelDyn)
          createARMRelDyn(pLinker, pOutput);
        m_pRelDyn->reserveEntry(*m_pRelocFactory);
        // set GOTRel bit
        rsym->setReserved(rsym->reserved() | 0x4u);
        return;
      }
      // set GOT bit
      rsym->setReserved(rsym->reserved() | 0x2u);
      return;
    }

    case llvm::ELF::R_ARM_COPY:
    case llvm::ELF::R_ARM_GLOB_DAT:
    case llvm::ELF::R_ARM_JUMP_SLOT:
    case llvm::ELF::R_ARM_RELATIVE: {
      // These are relocation type for dynamic linker, shold not
      // appear in object file.
      llvm::report_fatal_error(llvm::Twine("Unexpected reloc ") +
                               llvm::Twine((int)pReloc.type()) +
                               llvm::Twine(" in object file"));
      break;
    }
    default: {
      break;
    }
  } // end switch
}
bool AArch64GNULDBackend::doRelax(Module& pModule,
                                  IRBuilder& pBuilder,
                                  bool& pFinished) {
  assert(getStubFactory() != NULL && getBRIslandFactory() != NULL);

  // Number of new stubs added
  size_t num_new_stubs = 0;
  // String lengh to hold new stub symbols
  size_t stubs_strlen = 0;

  if (config().targets().fixCA53Erratum835769() ||
      config().targets().fixCA53Erratum843419()) {
    scanErrata(pModule, pBuilder, num_new_stubs, stubs_strlen);
  }

  ELFFileFormat* file_format = getOutputFormat();
  // check branch relocs and create the related stubs if needed
  Module::obj_iterator input, inEnd = pModule.obj_end();
  for (input = pModule.obj_begin(); input != inEnd; ++input) {
    LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
    for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
      if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData())
        continue;
      RelocData::iterator reloc, rEnd = (*rs)->getRelocData()->end();
      for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) {
        Relocation* relocation = llvm::cast<Relocation>(reloc);

        switch (relocation->type()) {
          case llvm::ELF::R_AARCH64_CALL26:
          case llvm::ELF::R_AARCH64_JUMP26: {
            // calculate the possible symbol value
            uint64_t sym_value = 0x0;
            LDSymbol* symbol = relocation->symInfo()->outSymbol();
            if (symbol->hasFragRef()) {
              uint64_t value = symbol->fragRef()->getOutputOffset();
              uint64_t addr =
                  symbol->fragRef()->frag()->getParent()->getSection().addr();
              sym_value = addr + value;
            }
            if ((relocation->symInfo()->reserved() &
                 AArch64Relocator::ReservePLT) != 0x0) {
              // FIXME: we need to find out the address of the specific plt
              // entry
              assert(file_format->hasPLT());
              sym_value = file_format->getPLT().addr();
            }
            Stub* stub = getStubFactory()->create(*relocation,  // relocation
                                                  sym_value,    // symbol value
                                                  pBuilder,
                                                  *getBRIslandFactory());
            if (stub != NULL) {
              // a stub symbol should be local
              assert(stub->symInfo() != NULL && stub->symInfo()->isLocal());
              // reset the branch target of the reloc to this stub instead
              relocation->setSymInfo(stub->symInfo());

              ++num_new_stubs;
              stubs_strlen += stub->symInfo()->nameSize() + 1;
            }
            break;
          }
          default: {
            break;
          }
        }  // end of switch
      }  // for all relocations
    }  // for all relocation section
  }  // for all inputs

  // Find the first fragment w/ invalid offset due to stub insertion.
  std::vector<Fragment*> invalid_frags;
  pFinished = true;
  for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(),
                                     island_end = getBRIslandFactory()->end();
       island != island_end;
       ++island) {
    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();
    }
  }

  // Fix up the size of .symtab, .strtab, and TEXT sections
  if (num_new_stubs == 0) {
    return false;
  } else {
    switch (config().options().getStripSymbolMode()) {
      case GeneralOptions::StripSymbolMode::StripAllSymbols:
      case GeneralOptions::StripSymbolMode::StripLocals:
        break;
      default: {
        LDSection& symtab = file_format->getSymTab();
        LDSection& strtab = file_format->getStrTab();

        symtab.setSize(symtab.size() +
                       sizeof(llvm::ELF::Elf64_Sym) * num_new_stubs);
        symtab.setInfo(symtab.getInfo() + num_new_stubs);
        strtab.setSize(strtab.size() + stubs_strlen);
      }
    }  // switch (config().options().getStripSymbolMode())

    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 true;
  }  // if (num_new_stubs == 0)
}
void ARMGNULDBackend::scanLocalReloc(Relocation& pReloc,
                                     const LDSymbol& pInputSym,
                                     MCLinker& pLinker,
                                     const MCLDInfo& pLDInfo,
                                     const Output& pOutput)
{
  // rsym - The relocation target symbol
  ResolveInfo* rsym = pReloc.symInfo();

  updateAddend(pReloc, pInputSym, pLinker.getLayout());

  switch(pReloc.type()){

    // Set R_ARM_TARGET1 to R_ARM_ABS32
    // Ref: GNU gold 1.11 arm.cc, line 9892
    case llvm::ELF::R_ARM_TARGET1:
       pReloc.setType(llvm::ELF::R_ARM_ABS32);
    case llvm::ELF::R_ARM_ABS32:
    case llvm::ELF::R_ARM_ABS32_NOI: {
      // If buiding PIC object (shared library or PIC executable),
      // a dynamic relocations with RELATIVE type to this location is needed.
      // Reserve an entry in .rel.dyn
      if(isPIC(pLDInfo, pOutput)) {
        // create .rel.dyn section if not exist
        if(NULL == m_pRelDyn)
          createARMRelDyn(pLinker, pOutput);
        m_pRelDyn->reserveEntry(*m_pRelocFactory);
        // set Rel bit
        rsym->setReserved(rsym->reserved() | 0x1u);
        }
      return;
    }

    case llvm::ELF::R_ARM_ABS16:
    case llvm::ELF::R_ARM_ABS12:
    case llvm::ELF::R_ARM_THM_ABS5:
    case llvm::ELF::R_ARM_ABS8:
    case llvm::ELF::R_ARM_BASE_ABS:
    case llvm::ELF::R_ARM_MOVW_ABS_NC:
    case llvm::ELF::R_ARM_MOVT_ABS:
    case llvm::ELF::R_ARM_THM_MOVW_ABS_NC:
    case llvm::ELF::R_ARM_THM_MOVT_ABS: {
      // Update value keep in relocation place if we meet a section symbol
      if(rsym->type() == ResolveInfo::Section) {
        pReloc.target() = pLinker.getLayout().getOutputOffset(
                            *pInputSym.fragRef()) + pReloc.target();
      }

      // If building PIC object (shared library or PIC executable),
      // a dynamic relocation for this location is needed.
      // Reserve an entry in .rel.dyn
      if(isPIC(pLDInfo, pOutput)) {
        checkValidReloc(pReloc, pLDInfo, pOutput);
        // create .rel.dyn section if not exist
        if(NULL == m_pRelDyn)
          createARMRelDyn(pLinker, pOutput);
        m_pRelDyn->reserveEntry(*m_pRelocFactory);
        // set Rel bit
        rsym->setReserved(rsym->reserved() | 0x1u);
      }
      return;
    }
    case llvm::ELF::R_ARM_GOTOFF32:
    case llvm::ELF::R_ARM_GOTOFF12: {
      // A GOT section is needed
      if(NULL == m_pGOT)
        createARMGOT(pLinker, pOutput);
      return;
    }

    // Set R_ARM_TARGET2 to R_ARM_GOT_PREL
    // Ref: GNU gold 1.11 arm.cc, line 9892
    case llvm::ELF::R_ARM_TARGET2:
      pReloc.setType(llvm::ELF::R_ARM_GOT_PREL);
    case llvm::ELF::R_ARM_GOT_BREL:
    case llvm::ELF::R_ARM_GOT_PREL: {
      // A GOT entry is needed for these relocation type.
      // return if we already create GOT for this symbol
      if(rsym->reserved() & 0x6u)
        return;
      if(NULL == m_pGOT)
        createARMGOT(pLinker, pOutput);
      m_pGOT->reserveEntry();
      // If building PIC object, a dynamic relocation with
      // type RELATIVE is needed to relocate this GOT entry.
      // Reserve an entry in .rel.dyn
      if(isPIC(pLDInfo, pOutput)) {
        // create .rel.dyn section if not exist
        if(NULL == m_pRelDyn)
          createARMRelDyn(pLinker, pOutput);
        m_pRelDyn->reserveEntry(*m_pRelocFactory);
        // set GOTRel bit
        rsym->setReserved(rsym->reserved() | 0x4u);
        return;
      }
      // set GOT bit
      rsym->setReserved(rsym->reserved() | 0x2u);
      return;
    }

    case llvm::ELF::R_ARM_BASE_PREL: {
      // FIXME: Currently we only support R_ARM_BASE_PREL against
      // symbol _GLOBAL_OFFSET_TABLE_
      if(rsym != m_pGOTSymbol->resolveInfo()) {
        llvm::report_fatal_error(llvm::Twine("Do not support relocation '") +
                                 llvm::Twine("R_ARM_BASE_PREL' against symbol '") +
                                 llvm::Twine(rsym->name()) +
                                 llvm::Twine(".'"));
      }
      return;
    }
    case llvm::ELF::R_ARM_COPY:
    case llvm::ELF::R_ARM_GLOB_DAT:
    case llvm::ELF::R_ARM_JUMP_SLOT:
    case llvm::ELF::R_ARM_RELATIVE: {
      // These are relocation type for dynamic linker, shold not
      // appear in object file.
      llvm::report_fatal_error(llvm::Twine("unexpected reloc ") +
                               llvm::Twine((int)pReloc.type()) +
                               llvm::Twine(" in object file"));
      break;
    }
    default: {
      break;
    }
  } // end switch
}
Beispiel #30
0
bool HexagonLDBackend::doRelax(Module& pModule, IRBuilder& pBuilder,
                               bool& pFinished)
{
  assert(NULL != getStubFactory() && NULL != getBRIslandFactory());
  bool isRelaxed = false;
  ELFFileFormat* file_format = getOutputFormat();
  // check branch relocs and create the related stubs if needed
  Module::obj_iterator input, inEnd = pModule.obj_end();
  for (input = pModule.obj_begin(); input != inEnd; ++input) {
    LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
    for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
      if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData())
        continue;
      RelocData::iterator reloc, rEnd = (*rs)->getRelocData()->end();
      for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) {
        switch (reloc->type()) {
          case llvm::ELF::R_HEX_B22_PCREL:
          case llvm::ELF::R_HEX_B15_PCREL:
          case llvm::ELF::R_HEX_B7_PCREL:
          case llvm::ELF::R_HEX_B13_PCREL:
          case llvm::ELF::R_HEX_B9_PCREL: {
            Relocation* relocation = llvm::cast<Relocation>(reloc);
            uint64_t sym_value = 0x0;
            LDSymbol* symbol = relocation->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(*relocation, // relocation
                                                  sym_value, //symbol value
                                                  pBuilder,
                                                  *getBRIslandFactory());
            if (NULL != stub) {
              assert(NULL != stub->symInfo());
              // increase the size of .symtab and .strtab
              LDSection& symtab = file_format->getSymTab();
              LDSection& strtab = file_format->getStrTab();
              symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf32_Sym));
              strtab.setSize(strtab.size() + stub->symInfo()->nameSize() + 1);
              isRelaxed = true;
            }
          }
          break;

          default:
            break;
        }
      }
    }
  }

  // find the first fragment w/ invalid offset due to stub insertion
  Fragment* invalid = NULL;
  pFinished = true;
  for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(),
       island_end = getBRIslandFactory()->end(); island != island_end; ++island)
  {
    if ((*island).end() == file_format->getText().getSectionData()->end())
      break;

    Fragment* exit = (*island).end();
    if (((*island).offset() + (*island).size()) > exit->getOffset()) {
      invalid = exit;
      pFinished = false;
      break;
    }
  }

  // reset the offset of invalid fragments
  while (NULL != invalid) {
    invalid->setOffset(invalid->getPrevNode()->getOffset() +
                       invalid->getPrevNode()->size());
    invalid = invalid->getNextNode();
  }

  // reset the size of .text
  if (isRelaxed) {
    file_format->getText().setSize(
      file_format->getText().getSectionData()->back().getOffset() +
      file_format->getText().getSectionData()->back().size());
  }
  return isRelaxed;
}