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 <cstring> 12#include <cassert> 13 14#include <llvm/Support/Casting.h> 15#include <llvm/Support/ManagedStatic.h> 16 17#include <mcld/Fragment/Fragment.h> 18#include <mcld/LD/LDSection.h> 19#include <mcld/LD/SectionData.h> 20#include <mcld/LD/EhFrame.h> 21#include <mcld/Support/GCFactory.h> 22#include <mcld/Support/MemoryRegion.h> 23#include <mcld/Fragment/RegionFragment.h> 24#include <mcld/Fragment/Stub.h> 25 26using namespace mcld; 27 28typedef GCFactory<FragmentRef, MCLD_SECTIONS_PER_INPUT> FragRefFactory; 29 30static llvm::ManagedStatic<FragRefFactory> g_FragRefFactory; 31 32FragmentRef FragmentRef::g_NullFragmentRef; 33 34//===----------------------------------------------------------------------===// 35// FragmentRef 36//===----------------------------------------------------------------------===// 37FragmentRef::FragmentRef() 38 : m_pFragment(NULL), m_Offset(0) { 39} 40 41FragmentRef::FragmentRef(Fragment& pFrag, 42 FragmentRef::Offset pOffset) 43 : m_pFragment(&pFrag), m_Offset(pOffset) { 44} 45 46/// Create - create a fragment reference for a given fragment. 47/// 48/// @param pFrag - the given fragment 49/// @param pOffset - the offset, can be larger than the fragment, but can not 50/// be larger than the section size. 51/// @return if the offset is legal, return the fragment reference. Otherwise, 52/// return NULL. 53FragmentRef* FragmentRef::Create(Fragment& pFrag, uint64_t pOffset) 54{ 55 int64_t offset = pOffset; 56 Fragment* frag = &pFrag; 57 58 while (NULL != frag) { 59 offset -= frag->size(); 60 if (offset <= 0) 61 break; 62 frag = frag->getNextNode(); 63 } 64 65 66 if (NULL == frag) 67 return Null(); 68 69 FragmentRef* result = g_FragRefFactory->allocate(); 70 new (result) FragmentRef(*frag, offset + frag->size()); 71 72 return result; 73} 74 75FragmentRef* FragmentRef::Create(LDSection& pSection, uint64_t pOffset) 76{ 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 (NULL == data || data->empty()) { 92 return Null(); 93 } 94 95 return Create(data->front(), pOffset); 96} 97 98void FragmentRef::Clear() 99{ 100 g_FragRefFactory->clear(); 101} 102 103FragmentRef* FragmentRef::Null() 104{ 105 return &g_NullFragmentRef; 106} 107 108FragmentRef& FragmentRef::assign(const FragmentRef& pCopy) 109{ 110 m_pFragment = const_cast<Fragment*>(pCopy.m_pFragment); 111 m_Offset = pCopy.m_Offset; 112 return *this; 113} 114 115FragmentRef& FragmentRef::assign(Fragment& pFrag, FragmentRef::Offset pOffset) 116{ 117 m_pFragment = &pFrag; 118 m_Offset = pOffset; 119 return *this; 120} 121 122void FragmentRef::memcpy(void* pDest, size_t pNBytes, Offset pOffset) const 123{ 124 // check if the offset is still in a legal range. 125 if (NULL == m_pFragment) 126 return; 127 unsigned int total_offset = m_Offset + pOffset; 128 switch(m_pFragment->getKind()) { 129 case Fragment::Region: { 130 RegionFragment* region_frag = static_cast<RegionFragment*>(m_pFragment); 131 unsigned int total_length = region_frag->getRegion().size(); 132 if (total_length < (total_offset+pNBytes)) 133 pNBytes = total_length - total_offset; 134 135 std::memcpy(pDest, region_frag->getRegion().getBuffer(total_offset), pNBytes); 136 return; 137 } 138 case Fragment::Stub: { 139 Stub* stub_frag = static_cast<Stub*>(m_pFragment); 140 unsigned int total_length = stub_frag->size(); 141 if (total_length < (total_offset+pNBytes)) 142 pNBytes = total_length - total_offset; 143 std::memcpy(pDest, stub_frag->getContent() + total_offset, pNBytes); 144 return; 145 } 146 case Fragment::Alignment: 147 case Fragment::Fillment: 148 default: 149 return; 150 } 151} 152 153FragmentRef::Address FragmentRef::deref() 154{ 155 if (NULL == m_pFragment) 156 return NULL; 157 Address base = NULL; 158 switch(m_pFragment->getKind()) { 159 case Fragment::Region: 160 base = static_cast<RegionFragment*>(m_pFragment)->getRegion().getBuffer(); 161 break; 162 case Fragment::Alignment: 163 case Fragment::Fillment: 164 default: 165 return NULL; 166 } 167 return base + m_Offset; 168} 169 170FragmentRef::ConstAddress FragmentRef::deref() const 171{ 172 if (NULL == m_pFragment) 173 return NULL; 174 ConstAddress base = NULL; 175 switch(m_pFragment->getKind()) { 176 case Fragment::Region: 177 base = static_cast<const RegionFragment*>(m_pFragment)->getRegion().getBuffer(); 178 break; 179 case Fragment::Alignment: 180 case Fragment::Fillment: 181 default: 182 return NULL; 183 } 184 return base + m_Offset; 185} 186 187FragmentRef::Offset FragmentRef::getOutputOffset() const 188{ 189 Offset result = 0; 190 if (NULL != m_pFragment) 191 result = m_pFragment->getOffset(); 192 return (result + m_Offset); 193} 194 195