Home | History | Annotate | Download | only in LD
      1 //===- StubFactory.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/LD/StubFactory.h"
     10 
     11 #include "mcld/IRBuilder.h"
     12 #include "mcld/Fragment/FragmentRef.h"
     13 #include "mcld/Fragment/Relocation.h"
     14 #include "mcld/Fragment/Stub.h"
     15 #include "mcld/LD/BranchIsland.h"
     16 #include "mcld/LD/BranchIslandFactory.h"
     17 #include "mcld/LD/LDSymbol.h"
     18 #include "mcld/LD/ResolveInfo.h"
     19 
     20 #include <string>
     21 
     22 namespace mcld {
     23 
     24 //===----------------------------------------------------------------------===//
     25 // StubFactory
     26 //===----------------------------------------------------------------------===//
     27 StubFactory::~StubFactory() {
     28   for (StubPoolType::iterator it = m_StubPool.begin(), ie = m_StubPool.end();
     29        it != ie;
     30        ++it)
     31     delete (*it);
     32 }
     33 
     34 /// addPrototype - register a stub prototype
     35 void StubFactory::addPrototype(Stub* pPrototype) {
     36   m_StubPool.push_back(pPrototype);
     37 }
     38 
     39 /// create - create a stub if needed, otherwise return NULL
     40 Stub* StubFactory::create(Relocation& pReloc,
     41                           uint64_t pTargetSymValue,
     42                           IRBuilder& pBuilder,
     43                           BranchIslandFactory& pBRIslandFactory) {
     44   // find if there is a prototype stub for the input relocation
     45   Stub* stub = NULL;
     46   Stub* prototype = findPrototype(pReloc, pReloc.place(), pTargetSymValue);
     47   if (prototype != NULL) {
     48     const Fragment* frag = pReloc.targetRef().frag();
     49     // find the islands for the input relocation
     50     std::pair<BranchIsland*, BranchIsland*> islands =
     51         pBRIslandFactory.getIslands(*frag);
     52     if (islands.first == NULL) {
     53       // early exit if we can not find the forward island.
     54       return NULL;
     55     }
     56 
     57     // find if there is such a stub in the backward island first.
     58     if (islands.second != NULL) {
     59       stub = islands.second->findStub(prototype, pReloc);
     60     }
     61 
     62     if (stub == NULL) {
     63       // find if there is such a stub in the forward island.
     64       stub = islands.first->findStub(prototype, pReloc);
     65       if (stub == NULL) {
     66         // create a stub from the prototype
     67         stub = prototype->clone();
     68 
     69         // apply fixups in this new stub
     70         stub->applyFixup(pReloc, pBuilder, *islands.first);
     71 
     72         // add stub to the forward branch island
     73         islands.first->addStub(prototype, pReloc, *stub);
     74       }
     75     }
     76   }
     77   return stub;
     78 }
     79 
     80 Stub* StubFactory::create(FragmentRef& pFragRef,
     81                           IRBuilder& pBuilder,
     82                           BranchIslandFactory& pBRIslandFactory) {
     83   Stub* prototype = findPrototype(pFragRef);
     84   if (prototype == NULL) {
     85     return NULL;
     86   } else {
     87     std::pair<BranchIsland*, BranchIsland*> islands =
     88         pBRIslandFactory.getIslands(*(pFragRef.frag()));
     89     // early exit if we can not find the forward island.
     90     if (islands.first == NULL) {
     91       return NULL;
     92     } else {
     93       // create a stub from the prototype
     94       Stub* stub = prototype->clone();
     95 
     96       // apply fixups in this new stub
     97       stub->applyFixup(pFragRef, pBuilder, *islands.first);
     98 
     99       // add stub to the forward branch island
    100       islands.first->addStub(*stub);
    101 
    102       return stub;
    103     }  // (islands.first == NULL)
    104   }  // if (prototype == NULL)
    105 }
    106 
    107 /// findPrototype - find if there is a registered stub prototype for the given
    108 /// relocation
    109 Stub* StubFactory::findPrototype(const Relocation& pReloc,
    110                                  uint64_t pSource,
    111                                  uint64_t pTargetSymValue) const {
    112   for (StubPoolType::const_iterator it = m_StubPool.begin(),
    113                                     ie = m_StubPool.end(); it != ie; ++it) {
    114     if ((*it)->isMyDuty(pReloc, pSource, pTargetSymValue))
    115       return (*it);
    116   }
    117   return NULL;
    118 }
    119 
    120 Stub* StubFactory::findPrototype(const FragmentRef& pFragRef) const {
    121   for (StubPoolType::const_iterator it = m_StubPool.begin(),
    122                                     ie = m_StubPool.end(); it != ie; ++it) {
    123     if ((*it)->isMyDuty(pFragRef))
    124       return (*it);
    125   }
    126   return NULL;
    127 }
    128 
    129 }  // namespace mcld
    130