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