StubFactory.cpp revision 6f75755c9204b1d8817ae5a65a2f7e5af0ec3f70
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
21using namespace mcld;
22
23//===----------------------------------------------------------------------===//
24// StubFactory
25//===----------------------------------------------------------------------===//
26StubFactory::~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
34void StubFactory::addPrototype(Stub* pPrototype)
35{
36  m_StubPool.push_back(pPrototype);
37}
38
39/// create - create a stub if needed, otherwise return NULL
40Stub* 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
112Stub* 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