C++程序  |  151行  |  4.07 KB

//===- 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;
}