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