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 <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 
     25 using 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()
     37   : m_pFragment(NULL), m_Offset(0) {
     38 }
     39 
     40 FragmentRef::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.
     52 FragmentRef* 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 
     79 FragmentRef* 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 
    102 void FragmentRef::Clear()
    103 {
    104   g_FragRefFactory->clear();
    105 }
    106 
    107 FragmentRef* FragmentRef::Null()
    108 {
    109   return &g_NullFragmentRef;
    110 }
    111 
    112 FragmentRef& 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 
    119 FragmentRef& FragmentRef::assign(Fragment& pFrag, FragmentRef::Offset pOffset)
    120 {
    121   m_pFragment = &pFrag;
    122   m_Offset = pOffset;
    123   return *this;
    124 }
    125 
    126 void 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 
    157 FragmentRef::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