//===- BranchIsland.cpp ---------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/LD/BranchIsland.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/LD/LDSection.h>
#include <mcld/Fragment/Stub.h>
#include <mcld/Fragment/AlignFragment.h>
#include <sstream>
using namespace mcld;
//==========================
// BranchIsland
BranchIsland::BranchIsland(Fragment& pEntryFrag,
size_t pMaxSize,
size_t pIndex)
: m_Entry(pEntryFrag),
m_pExit(pEntryFrag.getNextNode()),
m_pRear(NULL),
m_MaxSize(pMaxSize),
m_Name("island-")
{
// island name
std::ostringstream index;
index << pIndex;
m_Name.append(index.str());
}
BranchIsland::~BranchIsland()
{
}
/// fragment iterators of the island
SectionData::iterator BranchIsland::begin()
{
return ++iterator(&m_Entry);
}
SectionData::const_iterator BranchIsland::begin() const
{
return ++iterator(&m_Entry);
}
SectionData::iterator BranchIsland::end()
{
if (NULL != m_pExit)
return iterator(m_pExit);
return m_Entry.getParent()->end();
}
SectionData::const_iterator BranchIsland::end() const
{
if (NULL != m_pExit)
return iterator(m_pExit);
return m_Entry.getParent()->end();
}
uint64_t BranchIsland::offset() const
{
return m_Entry.getOffset() + m_Entry.size();
}
size_t BranchIsland::size() const
{
size_t size = 0x0;
if (0x0 != numOfStubs()) {
size = m_pRear->getOffset() + m_pRear->size() -
m_Entry.getNextNode()->getOffset();
}
return size;
}
size_t BranchIsland::maxSize() const
{
return m_MaxSize;
}
const std::string& BranchIsland::name() const
{
return m_Name;
}
size_t BranchIsland::numOfStubs() const
{
return m_StubMap.numOfEntries();
}
/// findStub - return true if there is a stub built from the given prototype
/// for the given relocation
Stub* BranchIsland::findStub(const Stub* pPrototype, const Relocation& pReloc)
{
Key key(pPrototype, pReloc.symInfo()->outSymbol(), pReloc.addend());
StubMapType::iterator it = m_StubMap.find(key);
if (it != m_StubMap.end()) {
assert(NULL != it.getEntry()->value());
return it.getEntry()->value();
}
return NULL;
}
/// addStub - add a stub into the island
bool BranchIsland::addStub(const Stub* pPrototype,
const Relocation& pReloc,
Stub& pStub)
{
bool exist = false;
Key key(pPrototype, pReloc.symInfo()->outSymbol(), pReloc.addend());
StubEntryType* entry = m_StubMap.insert(key, exist);
if (!exist) {
entry->setValue(&pStub);
m_pRear = &pStub;
SectionData* sd = m_Entry.getParent();
// insert alignment fragment
// TODO: check if we can reduce this alignment fragment for some cases
AlignFragment* align_frag = new AlignFragment(pStub.alignment(),
0x0,
1u,
pStub.alignment() - 1);
align_frag->setParent(sd);
sd->getFragmentList().insert(end(), align_frag);
align_frag->setOffset(align_frag->getPrevNode()->getOffset() +
align_frag->getPrevNode()->size());
// insert stub fragment
pStub.setParent(sd);
sd->getFragmentList().insert(end(), &pStub);
pStub.setOffset(pStub.getPrevNode()->getOffset() +
pStub.getPrevNode()->size());
}
return !exist;
}
/// addRelocation - add a relocation into island
bool BranchIsland::addRelocation(Relocation& pReloc)
{
m_Relocations.push_back(&pReloc);
return true;
}