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