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/Fragment/RegionFragment.h"
13 #include "mcld/Fragment/Stub.h"
14 #include "mcld/LD/EhFrame.h"
15 #include "mcld/LD/LDSection.h"
16 #include "mcld/LD/SectionData.h"
17 #include "mcld/Support/GCFactory.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 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() : m_pFragment(NULL), m_Offset(0) {
37 }
38
FragmentRef(Fragment & pFrag,FragmentRef::Offset pOffset)39 FragmentRef::FragmentRef(Fragment& pFrag, FragmentRef::Offset pOffset)
40 : m_pFragment(&pFrag), m_Offset(pOffset) {
41 }
42
43 /// Create - create a fragment reference for a given fragment.
44 ///
45 /// @param pFrag - the given fragment
46 /// @param pOffset - the offset, can be larger than the fragment, but can not
47 /// be larger than the section size.
48 /// @return if the offset is legal, return the fragment reference. Otherwise,
49 /// return NULL.
Create(Fragment & pFrag,uint64_t pOffset)50 FragmentRef* FragmentRef::Create(Fragment& pFrag, uint64_t pOffset) {
51 int64_t offset = pOffset;
52 Fragment* frag = &pFrag;
53
54 while (frag != NULL) {
55 offset -= frag->size();
56 if (offset <= 0)
57 break;
58 frag = frag->getNextNode();
59 }
60 if ((frag != NULL) && (frag->size() != 0)) {
61 if (offset == 0)
62 frag = frag->getNextNode();
63 else
64 offset += frag->size();
65 }
66
67 if (frag == NULL)
68 return Null();
69
70 FragmentRef* result = g_FragRefFactory->allocate();
71 new (result) FragmentRef(*frag, offset);
72
73 return result;
74 }
75
Create(LDSection & pSection,uint64_t pOffset)76 FragmentRef* FragmentRef::Create(LDSection& pSection, uint64_t pOffset) {
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 (data == NULL || data->empty()) {
92 return Null();
93 }
94
95 return Create(data->front(), pOffset);
96 }
97
Clear()98 void FragmentRef::Clear() {
99 g_FragRefFactory->clear();
100 }
101
Null()102 FragmentRef* FragmentRef::Null() {
103 return &g_NullFragmentRef;
104 }
105
assign(const FragmentRef & pCopy)106 FragmentRef& FragmentRef::assign(const FragmentRef& pCopy) {
107 m_pFragment = const_cast<Fragment*>(pCopy.m_pFragment);
108 m_Offset = pCopy.m_Offset;
109 return *this;
110 }
111
assign(Fragment & pFrag,FragmentRef::Offset pOffset)112 FragmentRef& FragmentRef::assign(Fragment& pFrag, FragmentRef::Offset pOffset) {
113 m_pFragment = &pFrag;
114 m_Offset = pOffset;
115 return *this;
116 }
117
memcpy(void * pDest,size_t pNBytes,Offset pOffset) const118 void FragmentRef::memcpy(void* pDest, size_t pNBytes, Offset pOffset) const {
119 // check if the offset is still in a legal range.
120 if (m_pFragment == NULL)
121 return;
122
123 unsigned int total_offset = m_Offset + pOffset;
124 switch (m_pFragment->getKind()) {
125 case Fragment::Region: {
126 RegionFragment* region_frag = static_cast<RegionFragment*>(m_pFragment);
127 unsigned int total_length = region_frag->getRegion().size();
128 if (total_length < (total_offset + pNBytes))
129 pNBytes = total_length - total_offset;
130
131 std::memcpy(
132 pDest, region_frag->getRegion().begin() + total_offset, pNBytes);
133 return;
134 }
135 case Fragment::Stub: {
136 Stub* stub_frag = static_cast<Stub*>(m_pFragment);
137 unsigned int total_length = stub_frag->size();
138 if (total_length < (total_offset + pNBytes))
139 pNBytes = total_length - total_offset;
140 std::memcpy(pDest, stub_frag->getContent() + total_offset, pNBytes);
141 return;
142 }
143 case Fragment::Alignment:
144 case Fragment::Fillment:
145 default:
146 return;
147 }
148 }
149
getOutputOffset() const150 FragmentRef::Offset FragmentRef::getOutputOffset() const {
151 Offset result = 0;
152 if (m_pFragment != NULL)
153 result = m_pFragment->getOffset();
154 return (result + m_Offset);
155 }
156
157 } // namespace mcld
158