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 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); } } }
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 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) }
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; }
/// 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; }