FragmentRef.cpp revision 87f34658dec9097d987d254a990ea7f311bfc95f
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#include <mcld/Fragment/FragmentRef.h>
10
11#include <mcld/Fragment/Fragment.h>
12#include <mcld/LD/LDSection.h>
13#include <mcld/LD/SectionData.h>
14#include <mcld/LD/EhFrame.h>
15#include <mcld/Support/GCFactory.h>
16#include <mcld/Fragment/RegionFragment.h>
17#include <mcld/Fragment/Stub.h>
18
19#include <llvm/ADT/StringRef.h>
20#include <llvm/Support/Casting.h>
21#include <llvm/Support/ManagedStatic.h>
22
23#include <cassert>
24
25using namespace mcld;
26
27typedef GCFactory<FragmentRef, MCLD_SECTIONS_PER_INPUT> FragRefFactory;
28
29static llvm::ManagedStatic<FragRefFactory> g_FragRefFactory;
30
31FragmentRef FragmentRef::g_NullFragmentRef;
32
33//===----------------------------------------------------------------------===//
34// FragmentRef
35//===----------------------------------------------------------------------===//
36FragmentRef::FragmentRef()
37  : m_pFragment(NULL), m_Offset(0) {
38}
39
40FragmentRef::FragmentRef(Fragment& pFrag,
41                         FragmentRef::Offset pOffset)
42  : m_pFragment(&pFrag), m_Offset(pOffset) {
43}
44
45/// Create - create a fragment reference for a given fragment.
46///
47/// @param pFrag - the given fragment
48/// @param pOffset - the offset, can be larger than the fragment, but can not
49///                  be larger than the section size.
50/// @return if the offset is legal, return the fragment reference. Otherwise,
51/// return NULL.
52FragmentRef* FragmentRef::Create(Fragment& pFrag, uint64_t pOffset)
53{
54  int64_t offset = pOffset;
55  Fragment* frag = &pFrag;
56
57  while (NULL != frag) {
58    offset -= frag->size();
59    if (offset <= 0)
60      break;
61    frag = frag->getNextNode();
62  }
63  if ((frag != NULL) && (frag->size() != 0)) {
64    if (offset == 0)
65      frag = frag->getNextNode();
66    else
67      offset += frag->size();
68  }
69
70  if (NULL == frag)
71    return Null();
72
73  FragmentRef* result = g_FragRefFactory->allocate();
74  new (result) FragmentRef(*frag, offset);
75
76  return result;
77}
78
79FragmentRef* FragmentRef::Create(LDSection& pSection, uint64_t pOffset)
80{
81  SectionData* data = NULL;
82  switch (pSection.kind()) {
83    case LDFileFormat::Relocation:
84      // No fragment reference refers to a relocation section
85      break;
86    case LDFileFormat::EhFrame:
87      if (pSection.hasEhFrame())
88        data = pSection.getEhFrame()->getSectionData();
89      break;
90    default:
91      data = pSection.getSectionData();
92      break;
93  }
94
95  if (NULL == data || data->empty()) {
96    return Null();
97  }
98
99  return Create(data->front(), pOffset);
100}
101
102void FragmentRef::Clear()
103{
104  g_FragRefFactory->clear();
105}
106
107FragmentRef* FragmentRef::Null()
108{
109  return &g_NullFragmentRef;
110}
111
112FragmentRef& FragmentRef::assign(const FragmentRef& pCopy)
113{
114  m_pFragment = const_cast<Fragment*>(pCopy.m_pFragment);
115  m_Offset = pCopy.m_Offset;
116  return *this;
117}
118
119FragmentRef& FragmentRef::assign(Fragment& pFrag, FragmentRef::Offset pOffset)
120{
121  m_pFragment = &pFrag;
122  m_Offset = pOffset;
123  return *this;
124}
125
126void FragmentRef::memcpy(void* pDest, size_t pNBytes, Offset pOffset) const
127{
128  // check if the offset is still in a legal range.
129  if (NULL == m_pFragment)
130    return;
131  unsigned int total_offset = m_Offset + pOffset;
132  switch(m_pFragment->getKind()) {
133    case Fragment::Region: {
134      RegionFragment* region_frag = static_cast<RegionFragment*>(m_pFragment);
135      unsigned int total_length = region_frag->getRegion().size();
136      if (total_length < (total_offset+pNBytes))
137        pNBytes = total_length - total_offset;
138
139      std::memcpy(pDest, region_frag->getRegion().begin() + total_offset, pNBytes);
140      return;
141    }
142    case Fragment::Stub: {
143      Stub* stub_frag = static_cast<Stub*>(m_pFragment);
144      unsigned int total_length = stub_frag->size();
145      if (total_length < (total_offset+pNBytes))
146        pNBytes = total_length - total_offset;
147      std::memcpy(pDest, stub_frag->getContent() + total_offset, pNBytes);
148      return;
149    }
150    case Fragment::Alignment:
151    case Fragment::Fillment:
152    default:
153      return;
154  }
155}
156
157FragmentRef::Offset FragmentRef::getOutputOffset() const
158{
159  Offset result = 0;
160  if (NULL != m_pFragment)
161    result = m_pFragment->getOffset();
162  return (result + m_Offset);
163}
164