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();
}
/// 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_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_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_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 CodeSection::relocate(address at, RelocationHolder const& spec, int format) {
  Relocation* reloc = spec.reloc();
  relocInfo::relocType rtype = (relocInfo::relocType) reloc->type();
  if (rtype == relocInfo::none)  return;

  // The assertion below has been adjusted, to also work for
  // relocation for fixup.  Sometimes we want to put relocation
  // information for the next instruction, since it will be patched
  // with a call.
  assert(start() <= at && at <= end()+1,
         "cannot relocate data outside code boundaries");

  if (!has_locs()) {
    // no space for relocation information provided => code cannot be
    // relocated.  Make sure that relocate is only called with rtypes
    // that can be ignored for this kind of code.
    assert(rtype == relocInfo::none              ||
           rtype == relocInfo::runtime_call_type ||
           rtype == relocInfo::internal_word_type||
           rtype == relocInfo::section_word_type ||
           rtype == relocInfo::external_word_type,
           "code needs relocation information");
    // leave behind an indication that we attempted a relocation
    DEBUG_ONLY(_locs_start = _locs_limit = (relocInfo*)badAddress);
    return;
  }

  // Advance the point, noting the offset we'll have to record.
  csize_t offset = at - locs_point();
  set_locs_point(at);

  // Test for a couple of overflow conditions; maybe expand the buffer.
  relocInfo* end = locs_end();
  relocInfo* req = end + relocInfo::length_limit;
  // Check for (potential) overflow
  if (req >= locs_limit() || offset >= relocInfo::offset_limit()) {
    req += (uint)offset / (uint)relocInfo::offset_limit();
    if (req >= locs_limit()) {
      // Allocate or reallocate.
      expand_locs(locs_count() + (req - end));
      // reload pointer
      end = locs_end();
    }
  }

  // If the offset is giant, emit filler relocs, of type 'none', but
  // each carrying the largest possible offset, to advance the locs_point.
  while (offset >= relocInfo::offset_limit()) {
    assert(end < locs_limit(), "adjust previous paragraph of code");
    *end++ = filler_relocInfo();
    offset -= filler_relocInfo().addr_offset();
  }

  // If it's a simple reloc with no data, we'll just write (rtype | offset).
  (*end) = relocInfo(rtype, offset, format);

  // If it has data, insert the prefix, as (data_prefix_tag | data1), data2.
  end->initialize(this, reloc);
}
Relocator::Result HexagonRelocator::applyRelocation(Relocation& pRelocation) {
  Relocation::Type type = pRelocation.type();

  if (type > 85) {  // 86-255 relocs do not exists for Hexagon
    return Relocator::Unknown;
  }

  // apply the relocation
  return ApplyFunctions[type].func(pRelocation, *this);
}
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_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;
}
Esempio n. 10
0
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;
  }
}
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);
}
Esempio n. 12
0
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;
}
Esempio n. 14
0
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);
}
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::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
}
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
}
Esempio n. 18
0
void HexagonRelocator::scanGlobalReloc(Relocation& pReloc,
                                       IRBuilder& pBuilder,
                                       Module& pModule,
                                       LDSection& pSection) {
  // rsym - The relocation target symbol
  ResolveInfo* rsym = pReloc.symInfo();
  HexagonLDBackend& ld_backend = getTarget();

  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 (ld_backend.symbolNeedsPLT(*rsym)) {
        // create PLT for this symbol if it does not have.
        if (!(rsym->reserved() & ReservePLT)) {
          helper_PLT_init(pReloc, *this);
          rsym->setReserved(rsym->reserved() | ReservePLT);
        }
      }

      if (ld_backend.symbolNeedsDynRel(
              *rsym, (rsym->reserved() & ReservePLT), true)) {
        if (ld_backend.symbolNeedsCopyReloc(pReloc, *rsym)) {
          LDSymbol& cpy_sym =
              defineSymbolforCopyReloc(pBuilder, *rsym, ld_backend);
          addCopyReloc(*cpy_sym.resolveInfo(), ld_backend);
        } else {
          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);
          rsym->setReserved(rsym->reserved() | ReserveRel);
          ld_backend.checkAndSetHasTextRel(*pSection.getLink());
        }
      }
      return;

    case llvm::ELF::R_HEX_GOTREL_LO16:
    case llvm::ELF::R_HEX_GOTREL_HI16:
    case llvm::ELF::R_HEX_GOTREL_32:
    case llvm::ELF::R_HEX_GOTREL_32_6_X:
    case llvm::ELF::R_HEX_GOTREL_16_X:
    case llvm::ELF::R_HEX_GOTREL_11_X:
      // This assumes that GOT exists
      return;

    case llvm::ELF::R_HEX_GOT_LO16:
    case llvm::ELF::R_HEX_GOT_HI16:
    case llvm::ELF::R_HEX_GOT_32:
    case llvm::ELF::R_HEX_GOT_16:
    case llvm::ELF::R_HEX_GOT_32_6_X:
    case llvm::ELF::R_HEX_GOT_16_X:
    case llvm::ELF::R_HEX_GOT_11_X:
      // Symbol needs GOT entry, reserve entry in .got
      // return if we already create GOT for this symbol
      if (rsym->reserved() & ReserveGOT)
        return;
      // If the GOT is used in statically linked binaries,
      // the GOT entry is enough and no relocation is needed.
      if (config().isCodeStatic())
        helper_GOT_init(pReloc, false, *this);
      else
        helper_GOT_init(pReloc, true, *this);
      // set GOT bit
      rsym->setReserved(rsym->reserved() | ReserveGOT);
      return;

    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:
    case llvm::ELF::R_HEX_B32_PCREL_X:
    case llvm::ELF::R_HEX_B22_PCREL_X:
    case llvm::ELF::R_HEX_B15_PCREL_X:
    case llvm::ELF::R_HEX_B13_PCREL_X:
    case llvm::ELF::R_HEX_B9_PCREL_X:
    case llvm::ELF::R_HEX_B7_PCREL_X:
    case llvm::ELF::R_HEX_32_PCREL:
    case llvm::ELF::R_HEX_6_PCREL_X:
    case llvm::ELF::R_HEX_PLT_B22_PCREL:
      if (rsym->reserved() & ReservePLT)
        return;
      if (ld_backend.symbolNeedsPLT(*rsym) ||
          pReloc.type() == llvm::ELF::R_HEX_PLT_B22_PCREL) {
        helper_PLT_init(pReloc, *this);
        rsym->setReserved(rsym->reserved() | ReservePLT);
      }
      return;

    default:
      break;
  }  // end of switch
}
Esempio n. 19
0
// 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;
}
Esempio n. 20
0
// 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;
}
Esempio n. 21
0
// R_HEX_GOT_LO16 and its class : (G) Signed Truncate
// Exception: R_HEX_GOT_16(_X): signed verify
// Exception: R_HEX_GOT_11_X : unsigned truncate
Relocator::Result relocGOT(Relocation& pReloc, HexagonRelocator& pParent) {
  if (!(pReloc.symInfo()->reserved() & HexagonRelocator::ReserveGOT)) {
    return Relocator::BadReloc;
  }

  // set got entry value if needed
  HexagonGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
  assert(got_entry != NULL);
  if (HexagonRelocator::SymVal == got_entry->getValue())
    got_entry->setValue(pReloc.symValue());

  Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent);
  Relocator::Address GOT = pParent.getTarget().getGOTSymbolAddr();
  int32_t result = (int32_t)(GOT_S - GOT);
  uint32_t effectiveBits = 0;
  uint32_t alignment = 1;
  uint32_t bitMask = 0;
  uint32_t result_u;
  uint32_t shift = 0;

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

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

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

    case llvm::ELF::R_HEX_GOT_16:
      bitMask = FINDBITMASK(pReloc.target());
      effectiveBits = 16;
      break;

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

    case llvm::ELF::R_HEX_GOT_16_X:
      bitMask = FINDBITMASK(pReloc.target());
      effectiveBits = 6;
      break;

    case llvm::ELF::R_HEX_GOT_11_X:
      bitMask = FINDBITMASK(pReloc.target());
      result_u = GOT_S - GOT;
      pReloc.target() |= ApplyMask<uint32_t>(bitMask, result_u);
      return Relocator::OK;

    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) {
    int32_t range = 1 << (effectiveBits - 1);
    if ((result > range - 1) || (result < -range))
      return Relocator::Overflow;
  }
  pReloc.target() |= ApplyMask<int32_t>(bitMask, result);
  return Relocator::OK;
}
Esempio n. 22
0
/// doRelax
bool
ARMGNULDBackend::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) {
        Relocation* relocation = llvm::cast<Relocation>(reloc);

        switch (relocation->type()) {
          case llvm::ELF::R_ARM_PC24:
          case llvm::ELF::R_ARM_CALL:
          case llvm::ELF::R_ARM_JUMP24:
          case llvm::ELF::R_ARM_PLT32:
          case llvm::ELF::R_ARM_THM_CALL:
          case llvm::ELF::R_ARM_THM_XPC22:
          case llvm::ELF::R_ARM_THM_JUMP24:
          case llvm::ELF::R_ARM_THM_JUMP19: {
            // 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()->isGlobal() &&
                (relocation->symInfo()->reserved() & ARMRelocator::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 (NULL != stub) {
              switch (config().options().getStripSymbolMode()) {
                case GeneralOptions::StripAllSymbols:
                case GeneralOptions::StripLocals:
                  break;
                default: {
                  // a stub symbol should be local
                  assert(NULL != stub->symInfo() && stub->symInfo()->isLocal());
                  LDSection& symtab = file_format->getSymTab();
                  LDSection& strtab = file_format->getStrTab();

                  // increase the size of .symtab and .strtab if needed
                  if (config().targets().is32Bits())
                    symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf32_Sym));
                  else
                    symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf64_Sym));
                  symtab.setInfo(symtab.getInfo() + 1);
                  strtab.setSize(strtab.size() + stub->symInfo()->nameSize() + 1);
                }
              } // end of switch
              isRelaxed = true;
            }
            break;
          }
          case llvm::ELF::R_ARM_V4BX:
            /* FIXME: bypass R_ARM_V4BX relocation now */
            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
  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;
}
Esempio n. 23
0
Relocator::Result NyuziRelocator::applyRelocation(Relocation& pRelocation)
{
  Relocation::Type type = pRelocation.type();
  assert(ApplyFunctions.find(type) != ApplyFunctions.end());
  return ApplyFunctions[type].func(pRelocation, *this);
}