bool operator()(const Fragment& a, const Fragment& b) { ARMExSectionTuple* tupleA = m_ExData.getTupleByExIdx(&a); ARMExSectionTuple* tupleB = m_ExData.getTupleByExIdx(&b); Fragment* textFragA = tupleA->getTextFragment(); Fragment* textFragB = tupleB->getTextFragment(); uint64_t addrA = textFragA->getParent()->getSection().addr() + textFragA->getOffset(); uint64_t addrB = textFragB->getParent()->getSection().addr() + textFragB->getOffset(); return (addrA < addrB); }
/// getIsland - find fwd and bwd islands for the fragment /// @param pFragment - the fragment needs a branch island std::pair<BranchIsland*, BranchIsland*> BranchIslandFactory::getIslands( const Fragment& pFragment) { BranchIsland* fwd = NULL; BranchIsland* bwd = NULL; for (iterator it = begin(), ie = end(), prev = ie; it != ie; prev = it, ++it) { if ((pFragment.getOffset() < (*it).offset()) && ((pFragment.getOffset() + m_MaxFwdBranchRange) >= (*it).offset())) { fwd = &*it; if (prev != ie) { int64_t bwd_off = (int64_t)pFragment.getOffset() + m_MaxBwdBranchRange; if ((pFragment.getOffset() > (*prev).offset()) && (bwd_off <= (int64_t)(*prev).offset())) { bwd = &*prev; } } break; } } return std::make_pair(fwd, bwd); }
/// produce - produce a island for the given fragment /// @param pFragment - the fragment needs a branch island BranchIsland* BranchIslandFactory::produce(Fragment& pFragment) { assert(NULL == find(pFragment)); uint64_t island_offset = pFragment.getOffset() + m_MaxBranchRange - (pFragment.getOffset() % m_MaxBranchRange); // find out the last fragment whose offset is smaller than the calculated // offset of the island Fragment* frag = &pFragment; while (NULL != frag->getNextNode()) { if (frag->getNextNode()->getOffset() > island_offset) break; frag = frag->getNextNode(); } // fall back one step if needed if (NULL != frag && (frag->getOffset() + frag->size()) > island_offset) frag = frag->getPrevNode(); // check not to break the alignment constraint in the target section // (i.e., do not insert the island after a Alignment fragment) while (NULL != frag && Fragment::Alignment == frag->getKind()) { frag = frag->getPrevNode(); } // can not find an entry fragment to bridge the island if (NULL == frag) return NULL; BranchIsland *island = allocate(); new (island) BranchIsland(*frag, // entry fragment to the island m_MaxIslandSize, // the max size of the island size() - 1u); // index in the island factory return island; }
bool MipsGNULDBackend::doRelax(Module& pModule, IRBuilder& pBuilder, bool& pFinished) { assert(getStubFactory() != NULL && getBRIslandFactory() != NULL); bool isRelaxed = false; for (Module::obj_iterator input = pModule.obj_begin(); input != pModule.obj_end(); ++input) { LDContext* context = (*input)->context(); for (LDContext::sect_iterator rs = context->relocSectBegin(); rs != context->relocSectEnd(); ++rs) { LDSection* sec = *rs; if (LDFileFormat::Ignore == sec->kind() || !sec->hasRelocData()) continue; for (RelocData::iterator reloc = sec->getRelocData()->begin(); reloc != sec->getRelocData()->end(); ++reloc) { if (llvm::ELF::R_MIPS_26 != reloc->type()) continue; if (relaxRelocation(pBuilder, *llvm::cast<Relocation>(reloc))) isRelaxed = true; } } } SectionData* textData = getOutputFormat()->getText().getSectionData(); // find the first fragment w/ invalid offset due to stub insertion Fragment* invalid = NULL; pFinished = true; for (BranchIslandFactory::iterator ii = getBRIslandFactory()->begin(), ie = getBRIslandFactory()->end(); ii != ie; ++ii) { BranchIsland& island = *ii; if (island.end() == textData->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 (invalid != NULL) { invalid->setOffset(invalid->getPrevNode()->getOffset() + invalid->getPrevNode()->size()); invalid = invalid->getNextNode(); } // reset the size of .text if (isRelaxed) getOutputFormat()->getText().setSize(textData->back().getOffset() + textData->back().size()); return isRelaxed; }
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; }
uint64_t MipsGOT::getGPRelOffset(const Input& pInput, const Fragment& pEntry) const { return addr() + pEntry.getOffset() - getGPAddr(pInput); }
void ARMGNULDBackend::rewriteARMExIdxSection(Module& pModule) { if (!m_pEXIDX->hasSectionData()) { // Return if this is empty section. return; } SectionData* sectData = m_pEXIDX->getSectionData(); SectionData::FragmentListType& list = sectData->getFragmentList(); // Move the first fragment (align fragment) and last fragment (null fragment) // to temporary list because we would only like to sort the region fragment. SectionData::FragmentListType tmp; { SectionData::iterator first = sectData->begin(); SectionData::iterator last = sectData->end(); --last; assert(first->getKind() == Fragment::Alignment); assert(last->getKind() == Fragment::Null); tmp.splice(tmp.end(), list, first); tmp.splice(tmp.end(), list, last); } // Sort the region fragments in the .ARM.exidx output section. sort(list, ExIdxFragmentComparator(m_ExData)); // Fix the coverage of the .ARM.exidx table. llvm::StringRef cantUnwindRegion(g_CantUnwindEntry, sizeof(g_CantUnwindEntry)); SectionData::FragmentListType::iterator it = list.begin(); if (it != list.end()) { Fragment* prevTextFrag = m_ExData.getTupleByExIdx(it)->getTextFragment(); uint64_t prevTextEnd = prevTextFrag->getParent()->getSection().addr() + prevTextFrag->getOffset() + prevTextFrag->size(); ++it; while (it != list.end()) { Fragment* currTextFrag = m_ExData.getTupleByExIdx(it)->getTextFragment(); uint64_t currTextBegin = currTextFrag->getParent()->getSection().addr() + currTextFrag->getOffset(); if (currTextBegin > prevTextEnd) { // Found a gap. Insert a can't unwind entry. RegionFragment* frag = new RegionFragment(cantUnwindRegion, nullptr); frag->setParent(sectData); list.insert(it, frag); // Add PREL31 reference to the beginning of the uncovered region. Relocation* reloc = Relocation::Create(static_cast<uint32_t>(llvm::ELF::R_ARM_PREL31), *FragmentRef::Create(*frag, /* pOffset */0), /* pAddend */0); reloc->setSymInfo( CreateLocalSymbolToFragmentEnd(pModule, *prevTextFrag)); addExtraRelocation(reloc); } prevTextEnd = currTextBegin + currTextFrag->size(); prevTextFrag = currTextFrag; ++it; } // Add a can't unwind entry to terminate .ARM.exidx section. RegionFragment* frag = new RegionFragment(cantUnwindRegion, nullptr); frag->setParent(sectData); list.push_back(frag); // Add PREL31 reference to the end of the .text section. Relocation* reloc = Relocation::Create(static_cast<uint32_t>(llvm::ELF::R_ARM_PREL31), *FragmentRef::Create(*frag, /* pOffset */0), /* pAddend */0); reloc->setSymInfo(CreateLocalSymbolToFragmentEnd(pModule, *prevTextFrag)); addExtraRelocation(reloc); } // Add the first and the last fragment back. list.splice(list.begin(), tmp, tmp.begin()); list.splice(list.end(), tmp, tmp.begin()); // Update the fragment offsets. uint64_t offset = 0; for (SectionData::iterator it = sectData->begin(), end = sectData->end(); it != end; ++it) { it->setOffset(offset); offset += it->size(); } // Update the section size. m_pEXIDX->setSize(offset); // Rebuild the section header. setOutputSectionAddress(pModule); }
/// 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; }