Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_x86.cpp
213799 views
1
//===--------- ELF_x86.cpp - JIT linker implementation for ELF/x86 --------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// ELF/x86 jit-link implementation.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "llvm/ExecutionEngine/JITLink/ELF_x86.h"
14
#include "DefineExternalSectionStartAndEndSymbols.h"
15
#include "ELFLinkGraphBuilder.h"
16
#include "JITLinkGeneric.h"
17
#include "llvm/BinaryFormat/ELF.h"
18
#include "llvm/ExecutionEngine/JITLink/x86.h"
19
#include "llvm/Object/ELFObjectFile.h"
20
21
#define DEBUG_TYPE "jitlink"
22
23
using namespace llvm;
24
using namespace llvm::jitlink;
25
26
namespace {
27
constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";
28
29
Error buildTables_ELF_x86(LinkGraph &G) {
30
LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
31
32
x86::GOTTableManager GOT;
33
x86::PLTTableManager PLT(GOT);
34
visitExistingEdges(G, GOT, PLT);
35
return Error::success();
36
}
37
} // namespace
38
39
namespace llvm::jitlink {
40
41
class ELFJITLinker_x86 : public JITLinker<ELFJITLinker_x86> {
42
friend class JITLinker<ELFJITLinker_x86>;
43
44
public:
45
ELFJITLinker_x86(std::unique_ptr<JITLinkContext> Ctx,
46
std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)
47
: JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {
48
getPassConfig().PostAllocationPasses.push_back(
49
[this](LinkGraph &G) { return getOrCreateGOTSymbol(G); });
50
}
51
52
private:
53
Symbol *GOTSymbol = nullptr;
54
55
Error getOrCreateGOTSymbol(LinkGraph &G) {
56
auto DefineExternalGOTSymbolIfPresent =
57
createDefineExternalSectionStartAndEndSymbolsPass(
58
[&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {
59
if (Sym.getName() != nullptr &&
60
*Sym.getName() == ELFGOTSymbolName)
61
if (auto *GOTSection = G.findSectionByName(
62
x86::GOTTableManager::getSectionName())) {
63
GOTSymbol = &Sym;
64
return {*GOTSection, true};
65
}
66
return {};
67
});
68
69
// Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an
70
// external.
71
if (auto Err = DefineExternalGOTSymbolIfPresent(G))
72
return Err;
73
74
// If we succeeded then we're done.
75
if (GOTSymbol)
76
return Error::success();
77
78
// Otherwise look for a GOT section: If it already has a start symbol we'll
79
// record it, otherwise we'll create our own.
80
// If there's a GOT section but we didn't find an external GOT symbol...
81
if (auto *GOTSection =
82
G.findSectionByName(x86::GOTTableManager::getSectionName())) {
83
84
// Check for an existing defined symbol.
85
for (auto *Sym : GOTSection->symbols())
86
if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) {
87
GOTSymbol = Sym;
88
return Error::success();
89
}
90
91
// If there's no defined symbol then create one.
92
SectionRange SR(*GOTSection);
93
94
if (SR.empty()) {
95
GOTSymbol =
96
&G.addAbsoluteSymbol(ELFGOTSymbolName, orc::ExecutorAddr(), 0,
97
Linkage::Strong, Scope::Local, true);
98
} else {
99
GOTSymbol =
100
&G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0,
101
Linkage::Strong, Scope::Local, false, true);
102
}
103
}
104
105
return Error::success();
106
}
107
108
Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
109
return x86::applyFixup(G, B, E, GOTSymbol);
110
}
111
};
112
113
class ELFLinkGraphBuilder_x86 : public ELFLinkGraphBuilder<object::ELF32LE> {
114
private:
115
using ELFT = object::ELF32LE;
116
117
Expected<x86::EdgeKind_x86> getRelocationKind(const uint32_t Type) {
118
switch (Type) {
119
case ELF::R_386_32:
120
return x86::Pointer32;
121
case ELF::R_386_PC32:
122
return x86::PCRel32;
123
case ELF::R_386_16:
124
return x86::Pointer16;
125
case ELF::R_386_PC16:
126
return x86::PCRel16;
127
case ELF::R_386_GOT32:
128
return x86::RequestGOTAndTransformToDelta32FromGOT;
129
case ELF::R_386_GOT32X:
130
// TODO: Add a relaxable edge kind and update relaxation optimization.
131
return x86::RequestGOTAndTransformToDelta32FromGOT;
132
case ELF::R_386_GOTPC:
133
return x86::Delta32;
134
case ELF::R_386_GOTOFF:
135
return x86::Delta32FromGOT;
136
case ELF::R_386_PLT32:
137
return x86::BranchPCRel32;
138
}
139
140
return make_error<JITLinkError>(
141
"In " + G->getName() + ": Unsupported x86 relocation type " +
142
object::getELFRelocationTypeName(ELF::EM_386, Type));
143
}
144
145
Error addRelocations() override {
146
LLVM_DEBUG(dbgs() << "Adding relocations\n");
147
using Base = ELFLinkGraphBuilder<ELFT>;
148
using Self = ELFLinkGraphBuilder_x86;
149
150
for (const auto &RelSect : Base::Sections) {
151
// Validate the section to read relocation entries from.
152
if (RelSect.sh_type == ELF::SHT_RELA)
153
return make_error<StringError>(
154
"No SHT_RELA in valid x86 ELF object files",
155
inconvertibleErrorCode());
156
157
if (Error Err = Base::forEachRelRelocation(RelSect, this,
158
&Self::addSingleRelocation))
159
return Err;
160
}
161
162
return Error::success();
163
}
164
165
Error addSingleRelocation(const typename ELFT::Rel &Rel,
166
const typename ELFT::Shdr &FixupSection,
167
Block &BlockToFix) {
168
using Base = ELFLinkGraphBuilder<ELFT>;
169
170
auto ELFReloc = Rel.getType(false);
171
172
// R_386_NONE is a no-op.
173
if (LLVM_UNLIKELY(ELFReloc == ELF::R_386_NONE))
174
return Error::success();
175
176
uint32_t SymbolIndex = Rel.getSymbol(false);
177
auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
178
if (!ObjSymbol)
179
return ObjSymbol.takeError();
180
181
Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
182
if (!GraphSymbol)
183
return make_error<StringError>(
184
formatv("Could not find symbol at given index, did you add it to "
185
"JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
186
SymbolIndex, (*ObjSymbol)->st_shndx,
187
Base::GraphSymbols.size()),
188
inconvertibleErrorCode());
189
190
Expected<x86::EdgeKind_x86> Kind = getRelocationKind(ELFReloc);
191
if (!Kind)
192
return Kind.takeError();
193
194
auto FixupAddress = orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset;
195
int64_t Addend = 0;
196
197
switch (*Kind) {
198
case x86::Pointer32:
199
case x86::PCRel32:
200
case x86::RequestGOTAndTransformToDelta32FromGOT:
201
case x86::Delta32:
202
case x86::Delta32FromGOT:
203
case x86::BranchPCRel32:
204
case x86::BranchPCRel32ToPtrJumpStub:
205
case x86::BranchPCRel32ToPtrJumpStubBypassable: {
206
const char *FixupContent = BlockToFix.getContent().data() +
207
(FixupAddress - BlockToFix.getAddress());
208
Addend = *(const support::little32_t *)FixupContent;
209
break;
210
}
211
case x86::Pointer16:
212
case x86::PCRel16: {
213
const char *FixupContent = BlockToFix.getContent().data() +
214
(FixupAddress - BlockToFix.getAddress());
215
Addend = *(const support::little16_t *)FixupContent;
216
break;
217
}
218
}
219
220
Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
221
Edge GE(*Kind, Offset, *GraphSymbol, Addend);
222
LLVM_DEBUG({
223
dbgs() << " ";
224
printEdge(dbgs(), BlockToFix, GE, x86::getEdgeKindName(*Kind));
225
dbgs() << "\n";
226
});
227
228
BlockToFix.addEdge(std::move(GE));
229
return Error::success();
230
}
231
232
public:
233
ELFLinkGraphBuilder_x86(StringRef FileName, const object::ELFFile<ELFT> &Obj,
234
std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
235
SubtargetFeatures Features)
236
: ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),
237
std::move(Features), FileName,
238
x86::getEdgeKindName) {}
239
};
240
241
Expected<std::unique_ptr<LinkGraph>>
242
createLinkGraphFromELFObject_x86(MemoryBufferRef ObjectBuffer,
243
std::shared_ptr<orc::SymbolStringPool> SSP) {
244
LLVM_DEBUG({
245
dbgs() << "Building jitlink graph for new input "
246
<< ObjectBuffer.getBufferIdentifier() << "...\n";
247
});
248
249
auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
250
if (!ELFObj)
251
return ELFObj.takeError();
252
253
auto Features = (*ELFObj)->getFeatures();
254
if (!Features)
255
return Features.takeError();
256
257
assert((*ELFObj)->getArch() == Triple::x86 &&
258
"Only x86 (little endian) is supported for now");
259
260
auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);
261
262
return ELFLinkGraphBuilder_x86((*ELFObj)->getFileName(),
263
ELFObjFile.getELFFile(), std::move(SSP),
264
(*ELFObj)->makeTriple(), std::move(*Features))
265
.buildGraph();
266
}
267
268
void link_ELF_x86(std::unique_ptr<LinkGraph> G,
269
std::unique_ptr<JITLinkContext> Ctx) {
270
PassConfiguration Config;
271
const Triple &TT = G->getTargetTriple();
272
if (Ctx->shouldAddDefaultTargetPasses(TT)) {
273
if (auto MarkLive = Ctx->getMarkLivePass(TT))
274
Config.PrePrunePasses.push_back(std::move(MarkLive));
275
else
276
Config.PrePrunePasses.push_back(markAllSymbolsLive);
277
278
// Add an in-place GOT and PLT build pass.
279
Config.PostPrunePasses.push_back(buildTables_ELF_x86);
280
281
// Add GOT/Stubs optimizer pass.
282
Config.PreFixupPasses.push_back(x86::optimizeGOTAndStubAccesses);
283
}
284
if (auto Err = Ctx->modifyPassConfig(*G, Config))
285
return Ctx->notifyFailed(std::move(Err));
286
287
ELFJITLinker_x86::link(std::move(Ctx), std::move(G), std::move(Config));
288
}
289
290
} // namespace llvm::jitlink
291
292