You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
217 lines
7.2 KiB
217 lines
7.2 KiB
4 months ago
|
//===- 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
|