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