| //===- 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/Module.h> |
| #include <mcld/LinkerConfig.h> |
| #include <mcld/IRBuilder.h> |
| #include <mcld/Object/SectionMap.h> |
| #include <mcld/LD/LDSection.h> |
| #include <mcld/LD/SectionData.h> |
| #include <mcld/LD/RelocData.h> |
| #include <mcld/LD/EhFrame.h> |
| #include <mcld/Fragment/Relocation.h> |
| #include <mcld/Fragment/AlignFragment.h> |
| #include <mcld/Fragment/NullFragment.h> |
| #include <mcld/Fragment/FillFragment.h> |
| |
| #include <llvm/Support/Casting.h> |
| |
| using namespace mcld; |
| |
| //===----------------------------------------------------------------------===// |
| // ObjectBuilder |
| //===----------------------------------------------------------------------===// |
| ObjectBuilder::ObjectBuilder(const LinkerConfig& pConfig, Module& pTheModule) |
| : m_Config(pConfig), 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 |
| const SectionMap::NamePair& pair = m_Config.scripts().sectionMap().find(pName); |
| std::string output_name = (pair.isNull())?pName:pair.to; |
| LDSection* output_sect = LDSection::Create(output_name, 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 |
| bool ObjectBuilder::MergeSection(LDSection& pInputSection) |
| { |
| const SectionMap::NamePair& pair = |
| m_Config.scripts().sectionMap().find(pInputSection.name()); |
| std::string output_name = (pair.isNull())?pInputSection.name():pair.to; |
| LDSection* target = m_Module.getSection(output_name); |
| |
| if (NULL == target) { |
| target = LDSection::Create(output_name, |
| pInputSection.kind(), |
| pInputSection.type(), |
| pInputSection.flag()); |
| target->setAlign(pInputSection.align()); |
| m_Module.getSectionTable().push_back(target); |
| } |
| |
| switch (target->kind()) { |
| // Some *OUTPUT sections should not be merged. |
| case LDFileFormat::Relocation: |
| case LDFileFormat::NamePool: |
| /** do nothing **/ |
| return true; |
| case LDFileFormat::EhFrame: { |
| EhFrame* eh_frame = NULL; |
| if (target->hasEhFrame()) |
| eh_frame = target->getEhFrame(); |
| else |
| eh_frame = IRBuilder::CreateEhFrame(*target); |
| |
| eh_frame->merge(*pInputSection.getEhFrame()); |
| return true; |
| } |
| default: { |
| SectionData* data = NULL; |
| if (target->hasSectionData()) |
| data = target->getSectionData(); |
| else |
| data = IRBuilder::CreateSectionData(*target); |
| |
| return MoveSectionData(*pInputSection.getSectionData(), *data); |
| } |
| } |
| return true; |
| } |
| |
| /// 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!"); |
| |
| uint32_t offset = pTo.getSection().size(); |
| AlignFragment* align = NULL; |
| if (pFrom.getSection().align() > 1) { |
| // if the align constraint is larger than 1, append an alignment |
| align = new AlignFragment(pFrom.getSection().align(), // alignment |
| 0x0, // the filled value |
| 1u, // the size of filled value |
| pFrom.getSection().align() - 1 // max bytes to emit |
| ); |
| 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); |
| |
| // append the null fragment |
| NullFragment* null = new NullFragment(); |
| null->setParent(&pTo); |
| null->setOffset(offset); |
| pTo.getFragmentList().push_back(null); |
| |
| // set up pTo's header |
| pTo.getSection().setSize(offset); |
| if (pFrom.getSection().align() > pTo.getSection().align()) |
| pTo.getSection().setAlign(pFrom.getSection().align()); |
| |
| return true; |
| } |
| |
| /// AppendFragment - To append pFrag to the given SectionData pSD. |
| uint64_t ObjectBuilder::AppendFragment(Fragment& pFrag, |
| SectionData& pSD, |
| uint32_t pAlignConstraint) |
| { |
| // get initial offset. |
| uint32_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(pAlignConstraint, // alignment |
| 0x0, // the filled value |
| 1u, // the size of filled value |
| pAlignConstraint - 1 // max bytes to emit |
| ); |
| 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 (NULL != align) |
| return align->size() + pFrag.size(); |
| else |
| return pFrag.size(); |
| } |
| |