1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
//===- StubFactory.cpp ----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/LD/StubFactory.h"
#include "mcld/IRBuilder.h"
#include "mcld/Fragment/Relocation.h"
#include "mcld/Fragment/Stub.h"
#include "mcld/LD/BranchIsland.h"
#include "mcld/LD/BranchIslandFactory.h"
#include "mcld/LD/LDSymbol.h"
#include "mcld/LD/ResolveInfo.h"
#include <string>
namespace mcld {
//===----------------------------------------------------------------------===//
// StubFactory
//===----------------------------------------------------------------------===//
StubFactory::~StubFactory() {
for (StubPoolType::iterator it = m_StubPool.begin(), ie = m_StubPool.end();
it != ie;
++it)
delete (*it);
}
/// addPrototype - register a stub prototype
void StubFactory::addPrototype(Stub* pPrototype) {
m_StubPool.push_back(pPrototype);
}
/// create - create a stub if needed, otherwise return NULL
Stub* StubFactory::create(Relocation& pReloc,
uint64_t pTargetSymValue,
IRBuilder& pBuilder,
BranchIslandFactory& pBRIslandFactory) {
// find if there is a prototype stub for the input relocation
Stub* stub = NULL;
Stub* prototype = findPrototype(pReloc, pReloc.place(), pTargetSymValue);
if (prototype != NULL) {
const Fragment* frag = pReloc.targetRef().frag();
// find the islands for the input relocation
std::pair<BranchIsland*, BranchIsland*> islands =
pBRIslandFactory.getIslands(*frag);
if (islands.first == NULL) {
// early exit if we can not find the forward island.
return NULL;
}
// find if there is such a stub in the backward island first.
if (islands.second != NULL) {
stub = islands.second->findStub(prototype, pReloc);
}
if (stub != NULL) {
// reset the branch target to the stub instead!
pReloc.setSymInfo(stub->symInfo());
} else {
// find if there is such a stub in the forward island.
stub = islands.first->findStub(prototype, pReloc);
if (stub != NULL) {
// reset the branch target to the stub instead!
pReloc.setSymInfo(stub->symInfo());
} else {
// create a stub from the prototype
stub = prototype->clone();
// build a name for stub symbol
std::string name("__");
name.append(pReloc.symInfo()->name())
.append("_")
.append(stub->name())
.append("@")
.append(islands.first->name());
// create LDSymbol for the stub
LDSymbol* symbol =
pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
name,
ResolveInfo::Function,
ResolveInfo::Define,
ResolveInfo::Local,
stub->size(), // size
stub->initSymValue(), // value
FragmentRef::Create(*stub, stub->initSymValue()),
ResolveInfo::Default);
stub->setSymInfo(symbol->resolveInfo());
// add relocations of this stub (i.e., set the branch target of the
// stub)
for (Stub::fixup_iterator it = stub->fixup_begin(),
ie = stub->fixup_end();
it != ie;
++it) {
Relocation* reloc =
Relocation::Create((*it)->type(),
*(FragmentRef::Create(*stub, (*it)->offset())),
(*it)->addend());
reloc->setSymInfo(pReloc.symInfo());
islands.first->addRelocation(*reloc);
}
// add stub to the forward branch island
islands.first->addStub(prototype, pReloc, *stub);
// reset the branch target of the input reloc to this stub instead!
pReloc.setSymInfo(stub->symInfo());
}
}
}
return stub;
}
/// findPrototype - find if there is a registered stub prototype for the given
/// relocation
Stub* StubFactory::findPrototype(const Relocation& pReloc,
uint64_t pSource,
uint64_t pTargetSymValue) {
for (StubPoolType::iterator it = m_StubPool.begin(), ie = m_StubPool.end();
it != ie;
++it) {
if ((*it)->isMyDuty(pReloc, pSource, pTargetSymValue))
return (*it);
}
return NULL;
}
} // namespace mcld
|