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; }
//========================== // DebugString void DebugString::merge(LDSection& pSection) { // get the fragment contents llvm::StringRef strings; SectionData::iterator it, end = pSection.getSectionData()->end(); for (it = pSection.getSectionData()->begin(); it != end; ++it) { if ((*it).getKind() == Fragment::Region) { RegionFragment* frag = llvm::cast<RegionFragment>(&(*it)); strings = frag->getRegion().data(); } } // get the debug strings and add them into merged string table const char* str = strings.data(); const char* str_end = str + pSection.size(); while (str < str_end) { size_t len = string_length(str); m_StringTable.insertString(llvm::StringRef(str, len)); str = str + len + 1; } }
/// merge Input Sections bool HexagonLDBackend::mergeSection(Module& pModule, const Input& pInputFile, LDSection& pInputSection) { if ((pInputSection.flag() & llvm::ELF::SHF_HEX_GPREL) || (pInputSection.kind() == LDFileFormat::LinkOnce) || (pInputSection.kind() == LDFileFormat::Target)) { SectionData* sd = NULL; if (!m_psdata->hasSectionData()) { sd = IRBuilder::CreateSectionData(*m_psdata); m_psdata->setSectionData(sd); } sd = m_psdata->getSectionData(); MoveSectionDataAndSort(*pInputSection.getSectionData(), *sd); } else { ObjectBuilder builder(pModule); builder.MergeSection(pInputFile, pInputSection); } return true; }
/// emitSectionData void ELFObjectWriter::emitSectionData(const LDSection& pSection, MemoryRegion& pRegion) const { const SectionData* sd = NULL; switch (pSection.kind()) { case LDFileFormat::Relocation: assert(pSection.hasRelocData()); return; case LDFileFormat::EhFrame: assert(pSection.hasEhFrame()); sd = pSection.getEhFrame()->getSectionData(); break; default: assert(pSection.hasSectionData()); sd = pSection.getSectionData(); break; } emitSectionData(*sd, pRegion); }
uint64_t ARMGNULDBackend::emitSectionData(const Output& pOutput, const LDSection& pSection, const MCLDInfo& pInfo, MemoryRegion& pRegion) const { assert(pRegion.size() && "Size of MemoryRegion is zero!"); ELFFileFormat* file_format = getOutputFormat(pOutput); if (&pSection == m_pAttributes) { // FIXME: Currently Emitting .ARM.attributes directly from the input file. const llvm::MCSectionData* sect_data = pSection.getSectionData(); assert(sect_data && "Emit .ARM.attribute failed, MCSectionData doesn't exist!"); uint8_t* start = llvm::cast<MCRegionFragment>( sect_data->getFragmentList().front()).getRegion().start(); memcpy(pRegion.start(), start, pRegion.size()); return pRegion.size(); } if (&pSection == &(file_format->getPLT())) { assert(NULL != m_pPLT && "emitSectionData failed, m_pPLT is NULL!"); uint64_t result = m_pPLT->emit(pRegion); return result; } if (&pSection == &(file_format->getGOT())) { assert(NULL != m_pGOT && "emitSectionData failed, m_pGOT is NULL!"); uint64_t result = m_pGOT->emit(pRegion); return result; } llvm::report_fatal_error(llvm::Twine("Unable to emit section `") + pSection.name() + llvm::Twine("'.\n")); return 0x0; }
/// group - group fragments and create islands when needed /// @param pSectionData - the SectionData holds fragments need to be grouped void BranchIslandFactory::group(Module& pModule) { /* FIXME: Currently only support relaxing .text section! */ LDSection* text = pModule.getSection(".text"); if (text != NULL && text->hasSectionData()) { SectionData& sd = *text->getSectionData(); uint64_t group_end = m_MaxFwdBranchRange; for (SectionData::iterator it = sd.begin(), ie = sd.end(); it != ie; ++it) { if ((*it).getOffset() + (*it).size() > group_end) { Fragment* frag = (*it).getPrevNode(); while (frag != NULL && frag->getKind() == Fragment::Alignment) { frag = frag->getPrevNode(); } if (frag != NULL) { produce(*frag); group_end = (*it).getOffset() + m_MaxFwdBranchRange; } } } if (getIslands(sd.back()).first == NULL) produce(sd.back()); } }
bool MipsAbiFlags::fillBySection(const Input& pInput, const LDSection& pSection, MipsAbiFlags& mipsAbi) { assert(pSection.type() == llvm::ELF::SHT_MIPS_ABIFLAGS && "Unexpected section type"); if (pSection.size() != size()) { error(diag::error_Mips_abiflags_invalid_size) << pInput.name(); return false; } const SectionData* secData = pSection.getSectionData(); if (secData->size() != 2 || !llvm::isa<RegionFragment>(secData->front())) { error(diag::error_Mips_abiflags_invalid_size) << pInput.name(); return false; } const auto& frag = llvm::cast<RegionFragment>(secData->front()); auto* data = reinterpret_cast<const ElfMipsAbiFlags*>(frag.getRegion().data()); if (data->version != 0) { error(diag::error_Mips_abiflags_invalid_version) << int(data->version) << pInput.name(); return false; } mipsAbi.m_IsaLevel = data->isa_level; mipsAbi.m_IsaRev = data->isa_rev; mipsAbi.m_GprSize = data->gpr_size; mipsAbi.m_Cpr1Size = data->cpr1_size; mipsAbi.m_Cpr2Size = data->cpr2_size; mipsAbi.m_FpAbi = data->fp_abi; mipsAbi.m_IsaExt = data->isa_ext; mipsAbi.m_Ases = data->ases; mipsAbi.m_Flags1 = data->flags1; return true; }
uint64_t HexagonLDBackend::emitSectionData(const LDSection& pSection, MemoryRegion& pRegion) const { if (!pRegion.size()) return 0; const ELFFileFormat* FileFormat = getOutputFormat(); unsigned int EntrySize = 0; uint64_t RegionSize = 0; if ((LinkerConfig::Object != config().codeGenType()) && (!config().isCodeStatic())) { if (FileFormat->hasPLT() && (&pSection == &(FileFormat->getPLT()))) { unsigned char* buffer = pRegion.begin(); m_pPLT->applyPLT0(); m_pPLT->applyPLT1(); HexagonPLT::iterator it = m_pPLT->begin(); unsigned int plt0_size = llvm::cast<PLTEntryBase>((*it)).size(); memcpy(buffer, llvm::cast<PLTEntryBase>((*it)).getValue(), plt0_size); RegionSize += plt0_size; ++it; PLTEntryBase* plt1 = 0; HexagonPLT::iterator ie = m_pPLT->end(); while (it != ie) { plt1 = &(llvm::cast<PLTEntryBase>(*it)); EntrySize = plt1->size(); memcpy(buffer + RegionSize, plt1->getValue(), EntrySize); RegionSize += EntrySize; ++it; } return RegionSize; } else if (FileFormat->hasGOT() && (&pSection == &(FileFormat->getGOT()))) { RegionSize += emitGOTSectionData(pRegion); return RegionSize; } else if (FileFormat->hasGOTPLT() && (&pSection == &(FileFormat->getGOTPLT()))) { RegionSize += emitGOTPLTSectionData(pRegion, FileFormat); return RegionSize; } } const SectionData* sect_data = pSection.getSectionData(); SectionData::const_iterator frag_iter, frag_end = sect_data->end(); uint8_t* out_offset = pRegion.begin(); for (frag_iter = sect_data->begin(); frag_iter != frag_end; ++frag_iter) { size_t size = frag_iter->size(); switch(frag_iter->getKind()) { case Fragment::Fillment: { const FillFragment& fill_frag = llvm::cast<FillFragment>(*frag_iter); if (0 == fill_frag.getValueSize()) { // virtual fillment, ignore it. break; } memset(out_offset, fill_frag.getValue(), fill_frag.size()); break; } case Fragment::Region: { const RegionFragment& region_frag = llvm::cast<RegionFragment>(*frag_iter); const char* start = region_frag.getRegion().begin(); memcpy(out_offset, start, size); break; } case Fragment::Alignment: { const AlignFragment& align_frag = llvm::cast<AlignFragment>(*frag_iter); uint64_t count = size / align_frag.getValueSize(); switch (align_frag.getValueSize()) { case 1u: std::memset(out_offset, align_frag.getValue(), count); break; default: llvm::report_fatal_error( "unsupported value size for align fragment emission yet.\n"); break; } // end switch break; } case Fragment::Null: { assert(0x0 == size); break; } default: llvm::report_fatal_error("unsupported fragment type.\n"); break; } // end switch out_offset += size; } // end for return pRegion.size(); }
bool ELFAttribute::merge(const Input &pInput, LDSection &pInputAttrSectHdr) { // Skip corrupt subsection if (pInputAttrSectHdr.size() < MinimalELFAttributeSectionSize) return true; // Obtain the region containing the attribute data. Expect exactly one // RegionFragment in the section data. const SectionData* sect_data = pInputAttrSectHdr.getSectionData(); // FIXME: Why is 2? if ((sect_data->size() != 2) || (!llvm::isa<RegionFragment>(sect_data->front()))) { return true; } const RegionFragment& region_frag = llvm::cast<RegionFragment>(sect_data->front()); llvm::StringRef region = region_frag.getRegion(); // Parse the ELF attribute section header. ARM [ABI-addenda], 2.2.3. // // <format-version: ‘A’> // [ <uint32: subsection-length> NTBS: vendor-name // <bytes: vendor-data> // ]* const char *attribute_data = region.begin(); // format-version if (attribute_data[0] != FormatVersion) { warning(diag::warn_unsupported_attribute_section_format) << pInput.name() << attribute_data[0]; return true; } size_t subsection_offset = FormatVersionFieldSize; // Iterate all subsections containing in this attribute section. do { const char *subsection_data = region.begin() + subsection_offset; // subsection-length uint32_t subsection_length = *reinterpret_cast<const uint32_t*>(subsection_data); if(llvm::sys::IsLittleEndianHost != m_Config.targets().isLittleEndian()) bswap32(subsection_length); // vendor-name const char* vendor_name = subsection_data + SubsectionLengthFieldSize; const size_t vendor_name_length = ::strlen(vendor_name) + 1 /* '\0' */; // Check the length. if ((vendor_name_length <= 1) || (subsection_length <= (SubsectionLengthFieldSize + vendor_name_length))) return true; // Select the attribute subsection. Subsection *subsection = getSubsection(vendor_name); // Only process the subsections whose vendor can be recognized. if (subsection == NULL) { warning(diag::warn_unrecognized_vendor_subsection) << vendor_name << pInput.name(); } else { // vendor-data size_t vendor_data_offset = subsection_offset + SubsectionLengthFieldSize + vendor_name_length; size_t vendor_data_size = subsection_length - SubsectionLengthFieldSize - vendor_name_length; ConstAddress vendor_data = reinterpret_cast<ConstAddress>(region.begin()) + vendor_data_offset; // Merge the vendor data in the subsection. if (!subsection->merge(pInput, vendor_data, vendor_data_size)) return false; } subsection_offset += subsection_length; } while ((subsection_offset + SubsectionLengthFieldSize) < pInputAttrSectHdr.size()); return true; }
uint64_t ARMGNULDBackend::emitSectionData(const LDSection& pSection, MemoryRegion& pRegion) const { assert(pRegion.size() && "Size of MemoryRegion is zero!"); const ELFFileFormat* file_format = getOutputFormat(); if (file_format->hasPLT() && (&pSection == &(file_format->getPLT()))) { uint64_t result = m_pPLT->emit(pRegion); return result; } if (file_format->hasGOT() && (&pSection == &(file_format->getGOT()))) { uint64_t result = m_pGOT->emit(pRegion); return result; } if (&pSection == m_pAttributes) { return attribute().emit(pRegion); } // FIXME: Currently Emitting .ARM.attributes, .ARM.exidx, and .ARM.extab // directly from the input file. const SectionData* sect_data = pSection.getSectionData(); SectionData::const_iterator frag_iter, frag_end = sect_data->end(); uint8_t* out_offset = pRegion.begin(); for (frag_iter = sect_data->begin(); frag_iter != frag_end; ++frag_iter) { size_t size = frag_iter->size(); switch(frag_iter->getKind()) { case Fragment::Fillment: { const FillFragment& fill_frag = llvm::cast<FillFragment>(*frag_iter); if (0 == fill_frag.getValueSize()) { // virtual fillment, ignore it. break; } memset(out_offset, fill_frag.getValue(), fill_frag.size()); break; } case Fragment::Region: { const RegionFragment& region_frag = llvm::cast<RegionFragment>(*frag_iter); const char* start = region_frag.getRegion().begin(); memcpy(out_offset, start, size); break; } case Fragment::Alignment: { const AlignFragment& align_frag = llvm::cast<AlignFragment>(*frag_iter); uint64_t count = size / align_frag.getValueSize(); switch (align_frag.getValueSize()) { case 1u: std::memset(out_offset, align_frag.getValue(), count); break; default: llvm::report_fatal_error( "unsupported value size for align fragment emission yet.\n"); break; } // end switch break; } case Fragment::Null: { assert(0x0 == size); break; } default: llvm::report_fatal_error("unsupported fragment type.\n"); break; } // end switch out_offset += size; } // end for return pRegion.size(); }