FragmentRef.cpp revision 87f34658dec9097d987d254a990ea7f311bfc95f
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 25using namespace mcld; 26 27typedef GCFactory<FragmentRef, MCLD_SECTIONS_PER_INPUT> FragRefFactory; 28 29static llvm::ManagedStatic<FragRefFactory> g_FragRefFactory; 30 31FragmentRef FragmentRef::g_NullFragmentRef; 32 33//===----------------------------------------------------------------------===// 34// FragmentRef 35//===----------------------------------------------------------------------===// 36FragmentRef::FragmentRef() 37 : m_pFragment(NULL), m_Offset(0) { 38} 39 40FragmentRef::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. 52FragmentRef* 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 79FragmentRef* 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 102void FragmentRef::Clear() 103{ 104 g_FragRefFactory->clear(); 105} 106 107FragmentRef* FragmentRef::Null() 108{ 109 return &g_NullFragmentRef; 110} 111 112FragmentRef& 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 119FragmentRef& FragmentRef::assign(Fragment& pFrag, FragmentRef::Offset pOffset) 120{ 121 m_pFragment = &pFrag; 122 m_Offset = pOffset; 123 return *this; 124} 125 126void 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 157FragmentRef::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