StubFactory.cpp revision d0fbbb227051be16931a1aa9b4a7722ac039c698
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/LD/BranchIslandFactory.h>
11#include <mcld/LD/BranchIsland.h>
12#include <mcld/LD/LDSymbol.h>
13#include <mcld/LD/ResolveInfo.h>
14#include <mcld/Fragment/Stub.h>
15#include <mcld/Fragment/Relocation.h>
16#include <mcld/Fragment/FragmentLinker.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                          FragmentLinker& pLinker,
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        pLinker.defineSymbol<FragmentLinker::Force,
78                             FragmentLinker::Resolve>(name,
79                               false, // isDyn
80                               ResolveInfo::Function,
81                               ResolveInfo::Define,
82                               ResolveInfo::Local,
83                               stub->size(), // size
84                               stub->initSymValue(), // value
85                               FragmentRef::Create(*stub, stub->initSymValue()),
86                               ResolveInfo::Default);
87      stub->setSymInfo(symbol->resolveInfo());
88
89      // add relocations of this stub (i.e., set the branch target of the stub)
90      for (Stub::fixup_iterator it = stub->fixup_begin(),
91             ie = stub->fixup_end(); it != ie; ++it) {
92
93        Relocation* reloc = Relocation::Create((*it)->type(),
94                                 *(FragmentRef::Create(*stub, (*it)->offset())),
95                                 (*it)->addend());
96        reloc->setSymInfo(pReloc.symInfo());
97        island->addRelocation(*reloc);
98      }
99
100      // add stub to the branch island
101      island->addStub(prototype, pReloc, *stub);
102
103      // reset the branch target of the input reloc to this stub instead!
104      pReloc.setSymInfo(stub->symInfo());
105      return stub;
106    }
107  }
108  return NULL;
109}
110
111/// findPrototype - find if there is a registered stub prototype for the given
112/// relocation
113Stub* StubFactory::findPrototype(const Relocation& pReloc,
114                                 uint64_t pSource,
115                                 uint64_t pTargetSymValue)
116{
117  for (StubPoolType::iterator it = m_StubPool.begin(), ie = m_StubPool.end();
118       it != ie; ++it) {
119    if ((*it)->isMyDuty(pReloc, pSource, pTargetSymValue))
120      return (*it);
121  }
122  return NULL;
123}
124
125