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