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 //===----------------------------------------------------------------------===// 36 FragmentRef::FragmentRef() : m_pFragment(NULL), m_Offset(0) { 37 } 38 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. 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 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 98 void FragmentRef::Clear() { 99 g_FragRefFactory->clear(); 100 } 101 102 FragmentRef* FragmentRef::Null() { 103 return &g_NullFragmentRef; 104 } 105 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 112 FragmentRef& FragmentRef::assign(Fragment& pFrag, FragmentRef::Offset pOffset) { 113 m_pFragment = &pFrag; 114 m_Offset = pOffset; 115 return *this; 116 } 117 118 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 150 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