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