Home | History | Annotate | Download | only in Fragment
      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 
     26 using namespace mcld;
     27 
     28 typedef GCFactory<FragmentRef, MCLD_SECTIONS_PER_INPUT> FragRefFactory;
     29 
     30 static llvm::ManagedStatic<FragRefFactory> g_FragRefFactory;
     31 
     32 FragmentRef FragmentRef::g_NullFragmentRef;
     33 
     34 //===----------------------------------------------------------------------===//
     35 // FragmentRef
     36 //===----------------------------------------------------------------------===//
     37 FragmentRef::FragmentRef()
     38   : m_pFragment(NULL), m_Offset(0) {
     39 }
     40 
     41 FragmentRef::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.
     53 FragmentRef* 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 
     75 FragmentRef* 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 
     98 void FragmentRef::Clear()
     99 {
    100   g_FragRefFactory->clear();
    101 }
    102 
    103 FragmentRef* FragmentRef::Null()
    104 {
    105   return &g_NullFragmentRef;
    106 }
    107 
    108 FragmentRef& 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 
    115 FragmentRef& FragmentRef::assign(Fragment& pFrag, FragmentRef::Offset pOffset)
    116 {
    117   m_pFragment = &pFrag;
    118   m_Offset = pOffset;
    119   return *this;
    120 }
    121 
    122 void 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 
    153 FragmentRef::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 
    170 FragmentRef::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 
    187 FragmentRef::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