• 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 <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