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