1//===- FragmentRef.cpp --------------------------------------------------===//
2//
3//                     The MCLinker Project
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include <mcld/LD/FragmentRef.h>
11
12#include <cstring>
13#include <cassert>
14
15#include <llvm/Support/MathExtras.h>
16#include <llvm/Support/Casting.h>
17
18#include <mcld/LD/AlignFragment.h>
19#include <mcld/LD/FillFragment.h>
20#include <mcld/LD/RegionFragment.h>
21#include <mcld/LD/TargetFragment.h>
22#include <mcld/LD/Layout.h>
23
24using namespace mcld;
25
26//===----------------------------------------------------------------------===//
27// Helper Functions
28//===----------------------------------------------------------------------===//
29/// compunteFragmentSize - compute the specific Fragment size
30uint64_t mcld::computeFragmentSize(const Layout& pLayout,
31                                   const Fragment& pFrag)
32{
33  switch (pFrag.getKind()) {
34    case Fragment::Fillment:
35      return static_cast<const FillFragment&>(pFrag).getSize();
36
37    case Fragment::Alignment: {
38      uint64_t offset = pLayout.getOutputOffset(pFrag);
39      const AlignFragment& align_frag = llvm::cast<AlignFragment>(pFrag);
40      uint64_t size = llvm::OffsetToAlignment(offset, align_frag.getAlignment());
41      if (size > align_frag.getMaxBytesToEmit())
42        return 0;
43      return size;
44    }
45
46    case Fragment::Region:
47      return llvm::cast<RegionFragment>(pFrag).getRegion().size();
48
49    case Fragment::Target:
50      return llvm::cast<TargetFragment>(pFrag).getSize();
51
52    case Fragment::Relocation:
53      assert(0 && "the size of FT_Reloc fragment is handled by backend");
54      return 0;
55
56    default:
57      assert(0 && "invalid fragment kind");
58      return 0;
59  }
60}
61
62//===----------------------------------------------------------------------===//
63// FragmentRef
64//===----------------------------------------------------------------------===//
65FragmentRef::FragmentRef()
66  : m_pFragment(NULL), m_Offset(0) {
67}
68
69FragmentRef::FragmentRef(Fragment& pFrag,
70                         FragmentRef::Offset pOffset)
71  : m_pFragment(&pFrag), m_Offset(pOffset) {
72}
73
74FragmentRef::~FragmentRef()
75{
76  m_pFragment = NULL;
77  m_Offset = 0;
78}
79
80FragmentRef& FragmentRef::assign(const FragmentRef& pCopy)
81{
82  m_pFragment = const_cast<Fragment*>(pCopy.m_pFragment);
83  m_Offset = pCopy.m_Offset;
84  return *this;
85}
86
87FragmentRef& FragmentRef::assign(Fragment& pFrag, FragmentRef::Offset pOffset)
88{
89  m_pFragment = &pFrag;
90  m_Offset = pOffset;
91  return *this;
92}
93
94void FragmentRef::memcpy(void* pDest, size_t pNBytes, Offset pOffset) const
95{
96  // check if the offset is still in a legal range.
97  if (NULL == m_pFragment)
98    return;
99  unsigned int total_offset = m_Offset + pOffset;
100  switch(m_pFragment->getKind()) {
101    case Fragment::Region: {
102      RegionFragment* region_frag = static_cast<RegionFragment*>(m_pFragment);
103      unsigned int total_length = region_frag->getRegion().size();
104      if (total_length < (total_offset+pNBytes))
105        pNBytes = total_length - total_offset;
106
107      std::memcpy(pDest, region_frag->getRegion().getBuffer(total_offset), pNBytes);
108      return;
109    }
110    case Fragment::Alignment:
111    case Fragment::Fillment:
112    default:
113      return;
114  }
115}
116
117FragmentRef::Address FragmentRef::deref()
118{
119  if (NULL == m_pFragment)
120    return NULL;
121  Address base = NULL;
122  switch(m_pFragment->getKind()) {
123    case Fragment::Region:
124      base = static_cast<RegionFragment*>(m_pFragment)->getRegion().getBuffer();
125      break;
126    case Fragment::Alignment:
127    case Fragment::Fillment:
128    default:
129      return NULL;
130  }
131  return base + m_Offset;
132}
133
134FragmentRef::ConstAddress FragmentRef::deref() const
135{
136  if (NULL == m_pFragment)
137    return NULL;
138  ConstAddress base = NULL;
139  switch(m_pFragment->getKind()) {
140    case Fragment::Region:
141      base = static_cast<const RegionFragment*>(m_pFragment)->getRegion().getBuffer();
142      break;
143    case Fragment::Alignment:
144    case Fragment::Fillment:
145    default:
146      return NULL;
147  }
148  return base + m_Offset;
149}
150
151