TEST_F(SectionDataTest, Fragment_list_and_iterator) { LDSection* test = LDSection::Create("test", LDFileFormat::Null, 0, 0); SectionData* s = SectionData::Create(*test); EXPECT_TRUE(s->empty()); new Fragment(Fragment::Alignment, s); new Fragment(Fragment::Alignment, s); new Fragment(Fragment::Region, s); new Fragment(Fragment::Fillment, s); new Fragment(Fragment::Target, s); EXPECT_TRUE(5 == s->size()); // iterator llvm::iplist<Fragment>::iterator iter = s->begin(); EXPECT_TRUE(Fragment::Alignment == iter->getKind()); ++iter; EXPECT_TRUE(Fragment::Alignment == iter->getKind()); ++iter; EXPECT_TRUE(Fragment::Region == iter->getKind()); ++iter; EXPECT_TRUE(Fragment::Fillment == iter->getKind()); ++iter; EXPECT_TRUE(Fragment::Target == iter->getKind()); ++iter; EXPECT_TRUE(iter == s->end()); LDSection::Destroy(test); }
static RegionFragment* findRegionFragment(LDSection& pSection) { SectionData* sectData = pSection.getSectionData(); for (SectionData::iterator it = sectData->begin(), end = sectData->end(); it != end; ++it) { if (it->getKind() == Fragment::Region) { return static_cast<RegionFragment*>(&*it); } } return NULL; }
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 }
/// emitSectionData void ELFObjectWriter::emitSectionData(const SectionData& pSD, MemoryRegion& pRegion) const { SectionData::const_iterator fragIter, fragEnd = pSD.end(); size_t cur_offset = 0; for (fragIter = pSD.begin(); fragIter != fragEnd; ++fragIter) { size_t size = fragIter->size(); switch(fragIter->getKind()) { case Fragment::Region: { const RegionFragment& region_frag = llvm::cast<RegionFragment>(*fragIter); const uint8_t* from = region_frag.getRegion().start(); memcpy(pRegion.getBuffer(cur_offset), from, size); break; } case Fragment::Alignment: { // TODO: emit values with different sizes (> 1 byte), and emit nops const AlignFragment& align_frag = llvm::cast<AlignFragment>(*fragIter); uint64_t count = size / align_frag.getValueSize(); switch (align_frag.getValueSize()) { case 1u: std::memset(pRegion.getBuffer(cur_offset), align_frag.getValue(), count); break; default: llvm::report_fatal_error("unsupported value size for align fragment emission yet.\n"); break; } break; } case Fragment::Fillment: { const FillFragment& fill_frag = llvm::cast<FillFragment>(*fragIter); if (0 == size || 0 == fill_frag.getValueSize() || 0 == fill_frag.size()) { // ignore virtual fillment break; } uint64_t num_tiles = fill_frag.size() / fill_frag.getValueSize(); for (uint64_t i = 0; i != num_tiles; ++i) { std::memset(pRegion.getBuffer(cur_offset), fill_frag.getValue(), fill_frag.getValueSize()); } break; } case Fragment::Stub: { const Stub& stub_frag = llvm::cast<Stub>(*fragIter); memcpy(pRegion.getBuffer(cur_offset), stub_frag.getContent(), size); break; } case Fragment::Null: { assert(0x0 == size); break; } case Fragment::Target: llvm::report_fatal_error("Target fragment should not be in a regular section.\n"); break; default: llvm::report_fatal_error("invalid fragment should not be in a regular section.\n"); break; } cur_offset += size; } }
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); }