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