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
25 using namespace mcld;
26
27 typedef GCFactory<FragmentRef, MCLD_SECTIONS_PER_INPUT> FragRefFactory;
28
29 static llvm::ManagedStatic<FragRefFactory> g_FragRefFactory;
30
31 FragmentRef FragmentRef::g_NullFragmentRef;
32
33 //===----------------------------------------------------------------------===//
34 // FragmentRef
35 //===----------------------------------------------------------------------===//
FragmentRef()36 FragmentRef::FragmentRef()
37 : m_pFragment(NULL), m_Offset(0) {
38 }
39
FragmentRef(Fragment & pFrag,FragmentRef::Offset pOffset)40 FragmentRef::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.
Create(Fragment & pFrag,uint64_t pOffset)52 FragmentRef* 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
Create(LDSection & pSection,uint64_t pOffset)79 FragmentRef* 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
Clear()102 void FragmentRef::Clear()
103 {
104 g_FragRefFactory->clear();
105 }
106
Null()107 FragmentRef* FragmentRef::Null()
108 {
109 return &g_NullFragmentRef;
110 }
111
assign(const FragmentRef & pCopy)112 FragmentRef& 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
assign(Fragment & pFrag,FragmentRef::Offset pOffset)119 FragmentRef& FragmentRef::assign(Fragment& pFrag, FragmentRef::Offset pOffset)
120 {
121 m_pFragment = &pFrag;
122 m_Offset = pOffset;
123 return *this;
124 }
125
memcpy(void * pDest,size_t pNBytes,Offset pOffset) const126 void 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
getOutputOffset() const157 FragmentRef::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