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/Relocation.h"
     13 #include "mcld/Fragment/Stub.h"
     14 #include "mcld/LD/BranchIsland.h"
     15 #include "mcld/LD/BranchIslandFactory.h"
     16 #include "mcld/LD/LDSymbol.h"
     17 #include "mcld/LD/ResolveInfo.h"
     18 
     19 #include <string>
     20 
     21 namespace mcld {
     22 
     23 //===----------------------------------------------------------------------===//
     24 // StubFactory
     25 //===----------------------------------------------------------------------===//
     26 StubFactory::~StubFactory() {
     27   for (StubPoolType::iterator it = m_StubPool.begin(), ie = m_StubPool.end();
     28        it != ie;
     29        ++it)
     30     delete (*it);
     31 }
     32 
     33 /// addPrototype - register a stub prototype
     34 void StubFactory::addPrototype(Stub* pPrototype) {
     35   m_StubPool.push_back(pPrototype);
     36 }
     37 
     38 /// create - create a stub if needed, otherwise return NULL
     39 Stub* StubFactory::create(Relocation& pReloc,
     40                           uint64_t pTargetSymValue,
     41                           IRBuilder& pBuilder,
     42                           BranchIslandFactory& pBRIslandFactory) {
     43   // find if there is a prototype stub for the input relocation
     44   Stub* stub = NULL;
     45   Stub* prototype = findPrototype(pReloc, pReloc.place(), pTargetSymValue);
     46   if (prototype != NULL) {
     47     const Fragment* frag = pReloc.targetRef().frag();
     48     // find the islands for the input relocation
     49     std::pair<BranchIsland*, BranchIsland*> islands =
     50         pBRIslandFactory.getIslands(*frag);
     51     if (islands.first == NULL) {
     52       // early exit if we can not find the forward island.
     53       return NULL;
     54     }
     55 
     56     // find if there is such a stub in the backward island first.
     57     if (islands.second != NULL) {
     58       stub = islands.second->findStub(prototype, pReloc);
     59     }
     60 
     61     if (stub != NULL) {
     62       // reset the branch target to the stub instead!
     63       pReloc.setSymInfo(stub->symInfo());
     64     } else {
     65       // find if there is such a stub in the forward island.
     66       stub = islands.first->findStub(prototype, pReloc);
     67       if (stub != NULL) {
     68         // reset the branch target to the stub instead!
     69         pReloc.setSymInfo(stub->symInfo());
     70       } else {
     71         // create a stub from the prototype
     72         stub = prototype->clone();
     73 
     74         // build a name for stub symbol
     75         std::string name("__");
     76         name.append(pReloc.symInfo()->name())
     77             .append("_")
     78             .append(stub->name())
     79             .append("@")
     80             .append(islands.first->name());
     81 
     82         // create LDSymbol for the stub
     83         LDSymbol* symbol =
     84             pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
     85                 name,
     86                 ResolveInfo::Function,
     87                 ResolveInfo::Define,
     88                 ResolveInfo::Local,
     89                 stub->size(),          // size
     90                 stub->initSymValue(),  // value
     91                 FragmentRef::Create(*stub, stub->initSymValue()),
     92                 ResolveInfo::Default);
     93         stub->setSymInfo(symbol->resolveInfo());
     94 
     95         // add relocations of this stub (i.e., set the branch target of the
     96         // stub)
     97         for (Stub::fixup_iterator it = stub->fixup_begin(),
     98                                   ie = stub->fixup_end();
     99              it != ie;
    100              ++it) {
    101           Relocation* reloc =
    102               Relocation::Create((*it)->type(),
    103                                  *(FragmentRef::Create(*stub, (*it)->offset())),
    104                                  (*it)->addend());
    105           reloc->setSymInfo(pReloc.symInfo());
    106           islands.first->addRelocation(*reloc);
    107         }
    108 
    109         // add stub to the forward branch island
    110         islands.first->addStub(prototype, pReloc, *stub);
    111 
    112         // reset the branch target of the input reloc to this stub instead!
    113         pReloc.setSymInfo(stub->symInfo());
    114       }
    115     }
    116   }
    117   return stub;
    118 }
    119 
    120 /// findPrototype - find if there is a registered stub prototype for the given
    121 /// relocation
    122 Stub* StubFactory::findPrototype(const Relocation& pReloc,
    123                                  uint64_t pSource,
    124                                  uint64_t pTargetSymValue) {
    125   for (StubPoolType::iterator it = m_StubPool.begin(), ie = m_StubPool.end();
    126        it != ie;
    127        ++it) {
    128     if ((*it)->isMyDuty(pReloc, pSource, pTargetSymValue))
    129       return (*it);
    130   }
    131   return NULL;
    132 }
    133 
    134 }  // namespace mcld
    135