void AArch64GNULDBackend::scanErrata(Module& pModule, IRBuilder& pBuilder, size_t& num_new_stubs, size_t& stubs_strlen) { // TODO: Implement AArch64 ErrataStubFactory to create the specific erratum // stub and simplify the logics. for (Module::iterator sect = pModule.begin(), sectEnd = pModule.end(); sect != sectEnd; ++sect) { if (((*sect)->kind() == LDFileFormat::TEXT) && (*sect)->hasSectionData()) { SectionData* sd = (*sect)->getSectionData(); for (SectionData::iterator it = sd->begin(), ie = sd->end(); it != ie; ++it) { Fragment* frag = llvm::dyn_cast<RegionFragment>(it); if (frag != NULL) { FragmentRef* frag_ref = FragmentRef::Create(*frag, 0); for (unsigned offset = 0; offset < frag->size(); offset += AArch64InsnHelpers::InsnSize) { Stub* stub = getStubFactory()->create(*frag_ref, pBuilder, *getBRIslandFactory()); if (stub != NULL) { // A stub symbol should be local assert(stub->symInfo() != NULL && stub->symInfo()->isLocal()); const AArch64CA53ErratumStub* erratum_stub = reinterpret_cast<const AArch64CA53ErratumStub*>(stub); assert(erratum_stub != NULL); // Rewrite the erratum instruction as a branch to the stub. uint64_t offset = frag_ref->offset() + erratum_stub->getErratumInsnOffset(); Relocation* reloc = Relocation::Create(llvm::ELF::R_AARCH64_JUMP26, *(FragmentRef::Create(*frag, offset)), /* pAddend */0); reloc->setSymInfo(stub->symInfo()); reloc->target() = AArch64InsnHelpers::buildBranchInsn(); addExtraRelocation(reloc); ++num_new_stubs; stubs_strlen += stub->symInfo()->nameSize() + 1; } frag_ref->assign(*frag, offset + AArch64InsnHelpers::InsnSize); } // for each INSN } } // for each FRAGMENT } } // for each TEXT section }
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); }