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 //===----------------------------------------------------------------------===//
~StubFactory()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
addPrototype(Stub * pPrototype)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
create(Relocation & pReloc,uint64_t pTargetSymValue,IRBuilder & pBuilder,BranchIslandFactory & pBRIslandFactory)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
findPrototype(const Relocation & pReloc,uint64_t pSource,uint64_t pTargetSymValue)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