//===- ObjectBuilder.cpp --------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "mcld/Object/ObjectBuilder.h" #include "mcld/IRBuilder.h" #include "mcld/LinkerScript.h" #include "mcld/Module.h" #include "mcld/Fragment/AlignFragment.h" #include "mcld/Fragment/FillFragment.h" #include "mcld/Fragment/NullFragment.h" #include "mcld/LD/DebugString.h" #include "mcld/LD/EhFrame.h" #include "mcld/LD/LDSection.h" #include "mcld/LD/SectionData.h" #include "mcld/Object/SectionMap.h" #include <llvm/Support/Casting.h> namespace mcld { //===----------------------------------------------------------------------===// // ObjectBuilder //===----------------------------------------------------------------------===// ObjectBuilder::ObjectBuilder(Module& pTheModule) : m_Module(pTheModule) { } /// CreateSection - create an output section. LDSection* ObjectBuilder::CreateSection(const std::string& pName, LDFileFormat::Kind pKind, uint32_t pType, uint32_t pFlag, uint32_t pAlign) { // try to get one from output LDSection SectionMap::const_mapping pair = m_Module.getScript().sectionMap().find("*", pName); std::string output_name = (pair.first == NULL) ? pName : pair.first->name(); LDSection* output_sect = m_Module.getSection(output_name); if (output_sect == NULL) { output_sect = LDSection::Create(pName, pKind, pType, pFlag); output_sect->setAlign(pAlign); m_Module.getSectionTable().push_back(output_sect); } return output_sect; } /// MergeSection - merge the pInput section to the pOutput section LDSection* ObjectBuilder::MergeSection(const Input& pInputFile, LDSection& pInputSection) { SectionMap::mapping pair = m_Module.getScript().sectionMap().find( pInputFile.path().native(), pInputSection.name()); if (pair.first != NULL && pair.first->isDiscard()) { pInputSection.setKind(LDFileFormat::Ignore); return NULL; } std::string output_name = (pair.first == NULL) ? pInputSection.name() : pair.first->name(); LDSection* target = m_Module.getSection(output_name); if (target == NULL) { target = LDSection::Create(output_name, pInputSection.kind(), pInputSection.type(), pInputSection.flag()); target->setAlign(pInputSection.align()); m_Module.getSectionTable().push_back(target); } switch (target->kind()) { case LDFileFormat::EhFrame: { EhFrame* eh_frame = NULL; if (target->hasEhFrame()) eh_frame = target->getEhFrame(); else eh_frame = IRBuilder::CreateEhFrame(*target); eh_frame->merge(pInputFile, *pInputSection.getEhFrame()); UpdateSectionAlign(*target, pInputSection); return target; } case LDFileFormat::DebugString: { DebugString* debug_str = NULL; if (target->hasDebugString()) debug_str = target->getDebugString(); else debug_str = IRBuilder::CreateDebugString(*target); debug_str->merge(pInputSection); UpdateSectionAlign(*target, pInputSection); return target; } default: { if (!target->hasSectionData()) IRBuilder::CreateSectionData(*target); SectionData* data = NULL; if (pair.first != NULL) { assert(pair.second != NULL); data = pair.second->getSection()->getSectionData(); // force input alignment from ldscript if any if (pair.first->prolog().hasSubAlign()) { pInputSection.setAlign(pair.second->getSection()->align()); } } else { // orphan section data = target->getSectionData(); } if (MoveSectionData(*pInputSection.getSectionData(), *data)) { UpdateSectionAlign(*target, pInputSection); return target; } return NULL; } } return target; } /// MoveSectionData - move the fragments of pTO section data to pTo bool ObjectBuilder::MoveSectionData(SectionData& pFrom, SectionData& pTo) { assert(&pFrom != &pTo && "Cannot move section data to itself!"); uint64_t offset = pTo.getSection().size(); AlignFragment* align = NULL; if (pFrom.getSection().align() > 1) { // if the align constraint is larger than 1, append an alignment unsigned int alignment = pFrom.getSection().align(); align = new AlignFragment(/*alignment*/alignment, /*the filled value*/0x0, /*the size of filled value*/1u, /*max bytes to emit*/alignment - 1); align->setOffset(offset); align->setParent(&pTo); pTo.getFragmentList().push_back(align); offset += align->size(); } // move fragments from pFrom to pTO SectionData::FragmentListType& from_list = pFrom.getFragmentList(); SectionData::FragmentListType& to_list = pTo.getFragmentList(); SectionData::FragmentListType::iterator frag, fragEnd = from_list.end(); for (frag = from_list.begin(); frag != fragEnd; ++frag) { frag->setParent(&pTo); frag->setOffset(offset); offset += frag->size(); } to_list.splice(to_list.end(), from_list); // set up pTo's header pTo.getSection().setSize(offset); return true; } /// UpdateSectionAlign - update alignment for input section void ObjectBuilder::UpdateSectionAlign(LDSection& pTo, const LDSection& pFrom) { if (pFrom.align() > pTo.align()) pTo.setAlign(pFrom.align()); } /// UpdateSectionAlign - update alignment for input section void ObjectBuilder::UpdateSectionAlign(LDSection& pSection, uint32_t pAlignConstraint) { if (pSection.align() < pAlignConstraint) pSection.setAlign(pAlignConstraint); } /// AppendFragment - To append pFrag to the given SectionData pSD. uint64_t ObjectBuilder::AppendFragment(Fragment& pFrag, SectionData& pSD, uint32_t pAlignConstraint) { // get initial offset. uint64_t offset = 0; if (!pSD.empty()) offset = pSD.back().getOffset() + pSD.back().size(); AlignFragment* align = NULL; if (pAlignConstraint > 1) { // if the align constraint is larger than 1, append an alignment align = new AlignFragment(/*alignment*/pAlignConstraint, /*the filled value*/0x0, /*the size of filled value*/1u, /*max bytes to emit*/pAlignConstraint - 1); align->setOffset(offset); align->setParent(&pSD); pSD.getFragmentList().push_back(align); offset += align->size(); } // append the fragment pFrag.setParent(&pSD); pFrag.setOffset(offset); pSD.getFragmentList().push_back(&pFrag); // append the null fragment offset += pFrag.size(); NullFragment* null = new NullFragment(&pSD); null->setOffset(offset); if (align != NULL) return align->size() + pFrag.size(); else return pFrag.size(); } } // namespace mcld