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 //===----------------------------------------------------------------------===// 36 FragmentRef::FragmentRef() 37 : m_pFragment(NULL), m_Offset(0) { 38 } 39 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. 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 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 102 void FragmentRef::Clear() 103 { 104 g_FragRefFactory->clear(); 105 } 106 107 FragmentRef* FragmentRef::Null() 108 { 109 return &g_NullFragmentRef; 110 } 111 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 119 FragmentRef& FragmentRef::assign(Fragment& pFrag, FragmentRef::Offset pOffset) 120 { 121 m_pFragment = &pFrag; 122 m_Offset = pOffset; 123 return *this; 124 } 125 126 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 157 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