void IdenticalCodeFolding::findCandidates(FoldingCandidates& pCandidateList) { Module::obj_iterator obj, objEnd = m_Module.obj_end(); for (obj = m_Module.obj_begin(); obj != objEnd; ++obj) { std::set<const LDSection*> funcptr_access_set; typedef std::map<LDSection*, LDSection*> CandidateMap; CandidateMap candidate_map; LDContext::sect_iterator sect, sectEnd = (*obj)->context()->sectEnd(); for (sect = (*obj)->context()->sectBegin(); sect != sectEnd; ++sect) { switch ((*sect)->kind()) { case LDFileFormat::TEXT: { candidate_map.insert( std::make_pair(*sect, reinterpret_cast<LDSection*>(NULL))); break; } case LDFileFormat::Relocation: { LDSection* target = (*sect)->getLink(); if (target->kind() == LDFileFormat::TEXT) { candidate_map[target] = *sect; } // Safe icf if (m_Config.options().getICFMode() == GeneralOptions::ICF::Safe) { RelocData::iterator rel, relEnd = (*sect)->getRelocData()->end(); for (rel = (*sect)->getRelocData()->begin(); rel != relEnd; ++rel) { LDSymbol* sym = rel->symInfo()->outSymbol(); if (sym->hasFragRef() && (sym->type() == ResolveInfo::Function)) { const LDSection* def = &sym->fragRef()->frag()->getParent()->getSection(); if (!isSymCtorOrDtor(*rel->symInfo()) && m_Backend.mayHaveUnsafeFunctionPointerAccess(*target) && m_Backend.getRelocator() ->mayHaveFunctionPointerAccess(*rel)) { funcptr_access_set.insert(def); } } } // for each reloc } break; } default: { // skip break; } } // end of switch } // for each section CandidateMap::iterator candidate, candidateEnd = candidate_map.end(); for (candidate = candidate_map.begin(); candidate != candidateEnd; ++candidate) { if ((m_Config.options().getICFMode() == GeneralOptions::ICF::All) || (funcptr_access_set.count(candidate->first) == 0)) { size_t index = m_KeptSections.size(); m_KeptSections[candidate->first] = ObjectAndId(*obj, index); pCandidateList.push_back( FoldingCandidate(candidate->first, candidate->second, *obj)); } } // for each possible candidate } // for each obj }
bool SectionSymbolSet::finalize(LDSection& pOutSect, SymbolTable& pSymTab, bool relocatable) { if (!relocatable && pOutSect.size() == 0) return true; LDSymbol* sym = get(pOutSect); assert(NULL != sym); SectionData* data = NULL; switch (pOutSect.kind()) { case LDFileFormat::Relocation: // Relocation section should not have section symbol. return true; case LDFileFormat::EhFrame: if (EhFrame *ehframe = pOutSect.getEhFrame()) data = ehframe->getSectionData(); break; default: data = pOutSect.getSectionData(); break; } FragmentRef* frag_ref; if (data && !data->empty()) frag_ref = FragmentRef::Create(data->front(), 0x0); else frag_ref = FragmentRef::Null(); sym->setFragmentRef(frag_ref); // push symbol into output symbol table pSymTab.add(*sym); return true; }
void Stub::applyFixup(Relocation& pSrcReloc, IRBuilder& pBuilder, BranchIsland& pIsland) { // build a name for stub symbol std::string sym_name("__"); sym_name.append(pSrcReloc.symInfo()->name()) .append("_") .append(name()) .append("@") .append(pIsland.name()); // create LDSymbol for the stub LDSymbol* symbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>( sym_name, ResolveInfo::Function, ResolveInfo::Define, ResolveInfo::Local, size(), initSymValue(), FragmentRef::Create(*this, initSymValue()), ResolveInfo::Default); setSymInfo(symbol->resolveInfo()); // add relocations of this stub (i.e., set the branch target of the stub) for (fixup_iterator it = fixup_begin(), ie = fixup_end(); it != ie; ++it) { Relocation* reloc = Relocation::Create((*it)->type(), *(FragmentRef::Create(*this, (*it)->offset())), (*it)->addend()); reloc->setSymInfo(pSrcReloc.symInfo()); pIsland.addRelocation(*reloc); } }
bool MipsGNULDBackend::relaxRelocation(IRBuilder& pBuilder, Relocation& pRel) { uint64_t sym_value = 0x0; LDSymbol* symbol = pRel.symInfo()->outSymbol(); if (symbol->hasFragRef()) { uint64_t value = symbol->fragRef()->getOutputOffset(); uint64_t addr = symbol->fragRef()->frag()->getParent()->getSection().addr(); sym_value = addr + value; } Stub* stub = getStubFactory()->create( pRel, sym_value, pBuilder, *getBRIslandFactory()); if (stub == NULL) return false; assert(stub->symInfo() != NULL); // increase the size of .symtab and .strtab LDSection& symtab = getOutputFormat()->getSymTab(); LDSection& strtab = getOutputFormat()->getStrTab(); symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf32_Sym)); strtab.setSize(strtab.size() + stub->symInfo()->nameSize() + 1); return true; }
void GarbageCollection::getEntrySections(SectionVecTy& pEntry) { // all the KEEP sections defined in ldscript are entries, traverse all the // input sections and check the SectionMap to find the KEEP sections Module::obj_iterator obj, objEnd = m_Module.obj_end(); SectionMap& sect_map = m_Module.getScript().sectionMap(); for (obj = m_Module.obj_begin(); obj != objEnd; ++obj) { const std::string input_name = (*obj)->name(); LDContext::sect_iterator sect, sectEnd = (*obj)->context()->sectEnd(); for (sect = (*obj)->context()->sectBegin(); sect != sectEnd; ++sect) { LDSection* section = *sect; if (LDFileFormat::Regular != section->kind() && LDFileFormat::BSS != section->kind()) continue; SectionMap::Input* sm_input = sect_map.find(input_name, section->name()).second; if ((sm_input != NULL) && (InputSectDesc::Keep == sm_input->policy())) pEntry.push_back(section); } } // get the sections those the entry symbols defined in Module::SymbolTable& sym_tab = m_Module.getSymbolTable(); if (LinkerConfig::Exec == m_Config.codeGenType()) { assert(NULL != m_pEntry); pEntry.push_back(&m_pEntry->fragRef()->frag()->getParent()->getSection()); } else { // when building shared objects, the global define symbols are entries SymbolCategory::iterator it, end = sym_tab.regularEnd(); for (it = sym_tab.dynamicBegin(); it != end; ++it) { LDSymbol* sym = *it; if (!sym->resolveInfo()->isDefine() || !sym->hasFragRef()) continue; // only the target symbols defined in the concerned sections can make // the reference const LDSection* sect = &sym->fragRef()->frag()->getParent()->getSection(); if (sect->kind() != LDFileFormat::Regular && sect->kind() != LDFileFormat::BSS) continue; pEntry.push_back(sect); } } }
std::string IdenticalCodeFolding::FoldingCandidate::getContentWithVariables( const TargetLDBackend& pBackend, const IdenticalCodeFolding::KeptSections& pKeptSections) { std::string result(content); // Compute the variable content from relocs. std::vector<Relocation*>::const_iterator rel, relEnd = variable_relocs.end(); for (rel = variable_relocs.begin(); rel != relEnd; ++rel) { LDSymbol* sym = (*rel)->symInfo()->outSymbol(); LDSection* def = &sym->fragRef()->frag()->getParent()->getSection(); // Use the kept section index. KeptSections::const_iterator it = pKeptSections.find(def); llvm::format_object<size_t> kept_info("%x", (*it).second.second); char kept_str[8]; kept_info.print(kept_str, sizeof(kept_str)); result.append(kept_str); } return result; }
void ARMGNULDBackend::updateAddend(Relocation& pReloc, const LDSymbol& pInputSym, const Layout& pLayout) const { // Update value keep in addend if we meet a section symbol if(pReloc.symInfo()->type() == ResolveInfo::Section) { pReloc.setAddend(pLayout.getOutputOffset( *pInputSym.fragRef()) + pReloc.addend()); } }
/// create - create a stub if needed, otherwise return NULL Stub* StubFactory::create(Relocation& pReloc, uint64_t pTargetSymValue, IRBuilder& pBuilder, BranchIslandFactory& pBRIslandFactory) { // find if there is a prototype stub for the input relocation Stub* prototype = findPrototype(pReloc, pReloc.place(), pTargetSymValue); if (NULL != prototype) { // find the island for the input relocation BranchIsland* island = pBRIslandFactory.find(*(pReloc.targetRef().frag())); if (NULL == island) { island = pBRIslandFactory.produce(*(pReloc.targetRef().frag())); } // find if there is such a stub in the island already assert(NULL != island); Stub* stub = island->findStub(prototype, pReloc); if (NULL != stub) { // reset the branch target to the stub instead! pReloc.setSymInfo(stub->symInfo()); } else { // create a stub from the prototype stub = prototype->clone(); // build a name for stub symbol std::string name("__"); name.append(pReloc.symInfo()->name()); name.append("_"); name.append(stub->name()); name.append("@"); name.append(island->name()); // create LDSymbol for the stub LDSymbol* symbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( name, ResolveInfo::Function, ResolveInfo::Define, ResolveInfo::Local, stub->size(), // size stub->initSymValue(), // value FragmentRef::Create(*stub, stub->initSymValue()), ResolveInfo::Default); stub->setSymInfo(symbol->resolveInfo()); // add relocations of this stub (i.e., set the branch target of the stub) for (Stub::fixup_iterator it = stub->fixup_begin(), ie = stub->fixup_end(); it != ie; ++it) { Relocation* reloc = Relocation::Create((*it)->type(), *(FragmentRef::Create(*stub, (*it)->offset())), (*it)->addend()); reloc->setSymInfo(pReloc.symInfo()); island->addRelocation(*reloc); } // add stub to the branch island island->addStub(prototype, pReloc, *stub); // reset the branch target of the input reloc to this stub instead! pReloc.setSymInfo(stub->symInfo()); return stub; } } return NULL; }
void IdenticalCodeFolding::FoldingCandidate::initConstantContent( const TargetLDBackend& pBackend, const IdenticalCodeFolding::KeptSections& pKeptSections) { // Get the static content from text. assert(sect != NULL && sect->hasSectionData()); SectionData::const_iterator frag, fragEnd = sect->getSectionData()->end(); for (frag = sect->getSectionData()->begin(); frag != fragEnd; ++frag) { switch (frag->getKind()) { case Fragment::Region: { const RegionFragment& region = llvm::cast<RegionFragment>(*frag); content.append(region.getRegion().begin(), region.size()); break; } default: { // FIXME: Currently we only take care of RegionFragment. break; } } } // Get the static content from relocs. if (reloc_sect != NULL && reloc_sect->hasRelocData()) { for (Relocation& rel : *reloc_sect->getRelocData()) { llvm::format_object<Relocation::Type, Relocation::Address, Relocation::Address, Relocation::Address> rel_info("%x%llx%llx%llx", rel.type(), rel.symValue(), rel.addend(), rel.place()); char rel_str[48]; rel_info.print(rel_str, sizeof(rel_str)); content.append(rel_str); // Handle the recursive call. LDSymbol* sym = rel.symInfo()->outSymbol(); if ((sym->type() == ResolveInfo::Function) && sym->hasFragRef()) { LDSection* def = &sym->fragRef()->frag()->getParent()->getSection(); if (def == sect) { continue; } } if (!pBackend.isSymbolPreemptible(*rel.symInfo()) && sym->hasFragRef() && (pKeptSections.find( &sym->fragRef()->frag()->getParent()->getSection()) != pKeptSections.end())) { // Mark this reloc as a variable. variable_relocs.push_back(&rel); } else { // TODO: Support inlining merge sections if possible (target-dependent). if ((sym->binding() == ResolveInfo::Local) || (sym->binding() == ResolveInfo::Absolute)) { // ABS or Local symbols. content.append(sym->name()).append(obj->name()).append( obj->path().native()); } else { content.append(sym->name()); } } } } }
bool MipsGNULDBackend::hasEntryInStrTab(const LDSymbol& pSym) const { return ResolveInfo::Section != pSym.type() || m_pGpDispSymbol == &pSym; }
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) }
LDSymbol* LDSymbol::Create(ResolveInfo& pResolveInfo) { LDSymbol* result = g_LDSymbolFactory->allocate(); new (result) LDSymbol(); result->setResolveInfo(pResolveInfo); return result; }
bool HexagonLDBackend::doRelax(Module& pModule, IRBuilder& pBuilder, bool& pFinished) { assert(NULL != getStubFactory() && NULL != getBRIslandFactory()); bool isRelaxed = false; ELFFileFormat* file_format = getOutputFormat(); // check branch relocs and create the related stubs if needed Module::obj_iterator input, inEnd = pModule.obj_end(); for (input = pModule.obj_begin(); input != inEnd; ++input) { LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd(); for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) { if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData()) continue; RelocData::iterator reloc, rEnd = (*rs)->getRelocData()->end(); for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) { switch (reloc->type()) { case llvm::ELF::R_HEX_B22_PCREL: case llvm::ELF::R_HEX_B15_PCREL: case llvm::ELF::R_HEX_B7_PCREL: case llvm::ELF::R_HEX_B13_PCREL: case llvm::ELF::R_HEX_B9_PCREL: { Relocation* relocation = llvm::cast<Relocation>(reloc); uint64_t sym_value = 0x0; LDSymbol* symbol = relocation->symInfo()->outSymbol(); if (symbol->hasFragRef()) { uint64_t value = symbol->fragRef()->getOutputOffset(); uint64_t addr = symbol->fragRef()->frag()->getParent()->getSection().addr(); sym_value = addr + value; } Stub* stub = getStubFactory()->create(*relocation, // relocation sym_value, //symbol value pBuilder, *getBRIslandFactory()); if (NULL != stub) { assert(NULL != stub->symInfo()); // increase the size of .symtab and .strtab LDSection& symtab = file_format->getSymTab(); LDSection& strtab = file_format->getStrTab(); symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf32_Sym)); strtab.setSize(strtab.size() + stub->symInfo()->nameSize() + 1); isRelaxed = true; } } break; default: break; } } } } // find the first fragment w/ invalid offset due to stub insertion Fragment* invalid = NULL; pFinished = true; for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(), island_end = getBRIslandFactory()->end(); island != island_end; ++island) { if ((*island).end() == file_format->getText().getSectionData()->end()) break; Fragment* exit = (*island).end(); if (((*island).offset() + (*island).size()) > exit->getOffset()) { invalid = exit; pFinished = false; break; } } // reset the offset of invalid fragments while (NULL != invalid) { invalid->setOffset(invalid->getPrevNode()->getOffset() + invalid->getPrevNode()->size()); invalid = invalid->getNextNode(); } // reset the size of .text if (isRelaxed) { file_format->getText().setSize( file_format->getText().getSectionData()->back().getOffset() + file_format->getText().getSectionData()->back().size()); } return isRelaxed; }
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 }
/// create - create a stub if needed, otherwise return NULL Stub* StubFactory::create(Relocation& pReloc, uint64_t pTargetSymValue, IRBuilder& pBuilder, BranchIslandFactory& pBRIslandFactory) { // find if there is a prototype stub for the input relocation Stub* stub = NULL; Stub* prototype = findPrototype(pReloc, pReloc.place(), pTargetSymValue); if (prototype != NULL) { const Fragment* frag = pReloc.targetRef().frag(); // find the islands for the input relocation std::pair<BranchIsland*, BranchIsland*> islands = pBRIslandFactory.getIslands(*frag); if (islands.first == NULL) { // early exit if we can not find the forward island. return NULL; } // find if there is such a stub in the backward island first. if (islands.second != NULL) { stub = islands.second->findStub(prototype, pReloc); } if (stub != NULL) { // reset the branch target to the stub instead! pReloc.setSymInfo(stub->symInfo()); } else { // find if there is such a stub in the forward island. stub = islands.first->findStub(prototype, pReloc); if (stub != NULL) { // reset the branch target to the stub instead! pReloc.setSymInfo(stub->symInfo()); } else { // create a stub from the prototype stub = prototype->clone(); // build a name for stub symbol std::string name("__"); name.append(pReloc.symInfo()->name()) .append("_") .append(stub->name()) .append("@") .append(islands.first->name()); // create LDSymbol for the stub LDSymbol* symbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>( name, ResolveInfo::Function, ResolveInfo::Define, ResolveInfo::Local, stub->size(), // size stub->initSymValue(), // value FragmentRef::Create(*stub, stub->initSymValue()), ResolveInfo::Default); stub->setSymInfo(symbol->resolveInfo()); // add relocations of this stub (i.e., set the branch target of the // stub) for (Stub::fixup_iterator it = stub->fixup_begin(), ie = stub->fixup_end(); it != ie; ++it) { Relocation* reloc = Relocation::Create((*it)->type(), *(FragmentRef::Create(*stub, (*it)->offset())), (*it)->addend()); reloc->setSymInfo(pReloc.symInfo()); islands.first->addRelocation(*reloc); } // add stub to the forward branch island islands.first->addStub(prototype, pReloc, *stub); // reset the branch target of the input reloc to this stub instead! pReloc.setSymInfo(stub->symInfo()); } } } return stub; }
/// 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; }