//===- FragmentRef.cpp --------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/LD/FragmentRef.h>
#include <cstring>
#include <cassert>
#include <llvm/Support/MathExtras.h>
#include <llvm/Support/Casting.h>
#include <mcld/LD/AlignFragment.h>
#include <mcld/LD/FillFragment.h>
#include <mcld/LD/RegionFragment.h>
#include <mcld/LD/TargetFragment.h>
#include <mcld/LD/Layout.h>
using namespace mcld;
//===----------------------------------------------------------------------===//
// Helper Functions
//===----------------------------------------------------------------------===//
/// compunteFragmentSize - compute the specific Fragment size
uint64_t mcld::computeFragmentSize(const Layout& pLayout,
const Fragment& pFrag)
{
switch (pFrag.getKind()) {
case Fragment::Fillment:
return static_cast<const FillFragment&>(pFrag).getSize();
case Fragment::Alignment: {
uint64_t offset = pLayout.getOutputOffset(pFrag);
const AlignFragment& align_frag = llvm::cast<AlignFragment>(pFrag);
uint64_t size = llvm::OffsetToAlignment(offset, align_frag.getAlignment());
if (size > align_frag.getMaxBytesToEmit())
return 0;
return size;
}
case Fragment::Region:
return llvm::cast<RegionFragment>(pFrag).getRegion().size();
case Fragment::Target:
return llvm::cast<TargetFragment>(pFrag).getSize();
case Fragment::Relocation:
assert(0 && "the size of FT_Reloc fragment is handled by backend");
return 0;
default:
assert(0 && "invalid fragment kind");
return 0;
}
}
//===----------------------------------------------------------------------===//
// FragmentRef
//===----------------------------------------------------------------------===//
FragmentRef::FragmentRef()
: m_pFragment(NULL), m_Offset(0) {
}
FragmentRef::FragmentRef(Fragment& pFrag,
FragmentRef::Offset pOffset)
: m_pFragment(&pFrag), m_Offset(pOffset) {
}
FragmentRef::~FragmentRef()
{
m_pFragment = NULL;
m_Offset = 0;
}
FragmentRef& FragmentRef::assign(const FragmentRef& pCopy)
{
m_pFragment = const_cast<Fragment*>(pCopy.m_pFragment);
m_Offset = pCopy.m_Offset;
return *this;
}
FragmentRef& FragmentRef::assign(Fragment& pFrag, FragmentRef::Offset pOffset)
{
m_pFragment = &pFrag;
m_Offset = pOffset;
return *this;
}
void FragmentRef::memcpy(void* pDest, size_t pNBytes, Offset pOffset) const
{
// check if the offset is still in a legal range.
if (NULL == m_pFragment)
return;
unsigned int total_offset = m_Offset + pOffset;
switch(m_pFragment->getKind()) {
case Fragment::Region: {
RegionFragment* region_frag = static_cast<RegionFragment*>(m_pFragment);
unsigned int total_length = region_frag->getRegion().size();
if (total_length < (total_offset+pNBytes))
pNBytes = total_length - total_offset;
std::memcpy(pDest, region_frag->getRegion().getBuffer(total_offset), pNBytes);
return;
}
case Fragment::Alignment:
case Fragment::Fillment:
default:
return;
}
}
FragmentRef::Address FragmentRef::deref()
{
if (NULL == m_pFragment)
return NULL;
Address base = NULL;
switch(m_pFragment->getKind()) {
case Fragment::Region:
base = static_cast<RegionFragment*>(m_pFragment)->getRegion().getBuffer();
break;
case Fragment::Alignment:
case Fragment::Fillment:
default:
return NULL;
}
return base + m_Offset;
}
FragmentRef::ConstAddress FragmentRef::deref() const
{
if (NULL == m_pFragment)
return NULL;
ConstAddress base = NULL;
switch(m_pFragment->getKind()) {
case Fragment::Region:
base = static_cast<const RegionFragment*>(m_pFragment)->getRegion().getBuffer();
break;
case Fragment::Alignment:
case Fragment::Fillment:
default:
return NULL;
}
return base + m_Offset;
}