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; }
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); }
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; }
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 }
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 }
// R_HEX_32 and its class of relocations use only addend and symbol value // S + A : result is unsigned truncate. // Exception: R_HEX_32_6_X : unsigned verify Relocator::Result applyAbs(Relocation& pReloc) { Relocator::Address S = pReloc.symValue(); Relocator::DWord A = pReloc.addend(); uint32_t result = (uint32_t)(S + A); uint32_t bitMask = 0; uint32_t effectiveBits = 0; uint32_t alignment = 1; uint32_t shift = 0; switch (pReloc.type()) { case llvm::ELF::R_HEX_LO16: bitMask = 0x00c03fff; break; case llvm::ELF::R_HEX_HI16: shift = 16; bitMask = 0x00c03fff; break; case llvm::ELF::R_HEX_32: bitMask = 0xffffffff; break; case llvm::ELF::R_HEX_16: bitMask = 0x0000ffff; alignment = 2; break; case llvm::ELF::R_HEX_8: bitMask = 0x000000ff; alignment = 1; break; case llvm::ELF::R_HEX_12_X: bitMask = 0x000007e0; break; case llvm::ELF::R_HEX_32_6_X: bitMask = 0xfff3fff; shift = 6; effectiveBits = 26; break; case llvm::ELF::R_HEX_16_X: case llvm::ELF::R_HEX_11_X: case llvm::ELF::R_HEX_10_X: case llvm::ELF::R_HEX_9_X: case llvm::ELF::R_HEX_8_X: case llvm::ELF::R_HEX_7_X: case llvm::ELF::R_HEX_6_X: bitMask = FINDBITMASK(pReloc.target()); break; default: // show proper error fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type()) << "*****@*****.**"; } if ((shift != 0) && (result % alignment != 0)) return Relocator::BadReloc; result >>= shift; if (effectiveBits) { uint32_t range = 1 << effectiveBits; if (result > (range - 1)) return Relocator::Overflow; } pReloc.target() |= ApplyMask<uint32_t>(bitMask, result); return Relocator::OK; }
// R_HEX_B22_PCREL and its class of relocations, use // S + A - P : result is signed verify. // Exception: R_HEX_B32_PCREL_X : signed truncate // Another Exception: R_HEX_6_PCREL_X is unsigned truncate Relocator::Result applyRel(Relocation& pReloc, int64_t pResult) { uint32_t bitMask = 0; uint32_t effectiveBits = 0; uint32_t alignment = 1; uint32_t result; uint32_t shift = 0; switch (pReloc.type()) { case llvm::ELF::R_HEX_B22_PCREL: bitMask = 0x01ff3ffe; effectiveBits = 22; alignment = 4; shift = 2; break; case llvm::ELF::R_HEX_B15_PCREL: bitMask = 0x00df20fe; effectiveBits = 15; alignment = 4; shift = 2; break; case llvm::ELF::R_HEX_B7_PCREL: bitMask = 0x00001f18; effectiveBits = 7; alignment = 4; shift = 2; break; case llvm::ELF::R_HEX_B13_PCREL: bitMask = 0x00202ffe; effectiveBits = 13; alignment = 4; shift = 2; break; case llvm::ELF::R_HEX_B9_PCREL: bitMask = 0x003000fe; effectiveBits = 9; alignment = 4; shift = 2; break; case llvm::ELF::R_HEX_B32_PCREL_X: bitMask = 0xfff3fff; shift = 6; break; case llvm::ELF::R_HEX_B22_PCREL_X: bitMask = 0x01ff3ffe; effectiveBits = 22; pResult &= 0x3f; break; case llvm::ELF::R_HEX_B15_PCREL_X: bitMask = 0x00df20fe; effectiveBits = 15; pResult &= 0x3f; break; case llvm::ELF::R_HEX_B13_PCREL_X: bitMask = 0x00202ffe; effectiveBits = 13; pResult &= 0x3f; break; case llvm::ELF::R_HEX_B9_PCREL_X: bitMask = 0x003000fe; effectiveBits = 9; pResult &= 0x3f; break; case llvm::ELF::R_HEX_B7_PCREL_X: bitMask = 0x00001f18; effectiveBits = 7; pResult &= 0x3f; break; case llvm::ELF::R_HEX_32_PCREL: bitMask = 0xffffffff; effectiveBits = 32; break; case llvm::ELF::R_HEX_6_PCREL_X: // This is unique since it has a unsigned operand and its truncated bitMask = FINDBITMASK(pReloc.target()); result = pReloc.addend() + pReloc.symValue() - pReloc.place(); pReloc.target() |= ApplyMask<uint32_t>(bitMask, result); return Relocator::OK; default: // show proper error fatal(diag::unsupported_relocation) << static_cast<int>(pReloc.type()) << "*****@*****.**"; } if ((shift != 0) && (pResult % alignment != 0)) return Relocator::BadReloc; pResult >>= shift; if (effectiveBits) { int64_t range = 1LL << (effectiveBits - 1); if ((pResult > (range - 1)) || (pResult < -range)) return Relocator::Overflow; } pReloc.target() |= (uint32_t)ApplyMask<int32_t>(bitMask, pResult); return Relocator::OK; }
// 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; }
/// 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; }
Relocator::Result NyuziRelocator::applyRelocation(Relocation& pRelocation) { Relocation::Type type = pRelocation.type(); assert(ApplyFunctions.find(type) != ApplyFunctions.end()); return ApplyFunctions[type].func(pRelocation, *this); }