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_64.cpp
35271 views
1
//===---- ELF_x86_64.cpp -JIT linker implementation for ELF/x86-64 ----===//
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-64 jit-link implementation.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h"
14
#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
15
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
16
#include "llvm/ExecutionEngine/JITLink/TableManager.h"
17
#include "llvm/ExecutionEngine/JITLink/x86_64.h"
18
#include "llvm/Object/ELFObjectFile.h"
19
20
#include "DefineExternalSectionStartAndEndSymbols.h"
21
#include "EHFrameSupportImpl.h"
22
#include "ELFLinkGraphBuilder.h"
23
#include "JITLinkGeneric.h"
24
25
#define DEBUG_TYPE "jitlink"
26
27
using namespace llvm;
28
using namespace llvm::jitlink;
29
30
namespace {
31
32
constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";
33
constexpr StringRef ELFTLSInfoSectionName = "$__TLSINFO";
34
35
class TLSInfoTableManager_ELF_x86_64
36
: public TableManager<TLSInfoTableManager_ELF_x86_64> {
37
public:
38
static const uint8_t TLSInfoEntryContent[16];
39
40
static StringRef getSectionName() { return ELFTLSInfoSectionName; }
41
42
bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
43
if (E.getKind() == x86_64::RequestTLSDescInGOTAndTransformToDelta32) {
44
LLVM_DEBUG({
45
dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
46
<< formatv("{0:x}", B->getFixupAddress(E)) << " ("
47
<< formatv("{0:x}", B->getAddress()) << " + "
48
<< formatv("{0:x}", E.getOffset()) << ")\n";
49
});
50
E.setKind(x86_64::Delta32);
51
E.setTarget(getEntryForTarget(G, E.getTarget()));
52
return true;
53
}
54
return false;
55
}
56
57
Symbol &createEntry(LinkGraph &G, Symbol &Target) {
58
// the TLS Info entry's key value will be written by the fixTLVSectionByName
59
// pass, so create mutable content.
60
auto &TLSInfoEntry = G.createMutableContentBlock(
61
getTLSInfoSection(G), G.allocateContent(getTLSInfoEntryContent()),
62
orc::ExecutorAddr(), 8, 0);
63
TLSInfoEntry.addEdge(x86_64::Pointer64, 8, Target, 0);
64
return G.addAnonymousSymbol(TLSInfoEntry, 0, 16, false, false);
65
}
66
67
private:
68
Section &getTLSInfoSection(LinkGraph &G) {
69
if (!TLSInfoTable)
70
TLSInfoTable =
71
&G.createSection(ELFTLSInfoSectionName, orc::MemProt::Read);
72
return *TLSInfoTable;
73
}
74
75
ArrayRef<char> getTLSInfoEntryContent() const {
76
return {reinterpret_cast<const char *>(TLSInfoEntryContent),
77
sizeof(TLSInfoEntryContent)};
78
}
79
80
Section *TLSInfoTable = nullptr;
81
};
82
83
const uint8_t TLSInfoTableManager_ELF_x86_64::TLSInfoEntryContent[16] = {
84
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */
85
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*data address*/
86
};
87
88
Error buildTables_ELF_x86_64(LinkGraph &G) {
89
LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
90
91
x86_64::GOTTableManager GOT;
92
x86_64::PLTTableManager PLT(GOT);
93
TLSInfoTableManager_ELF_x86_64 TLSInfo;
94
visitExistingEdges(G, GOT, PLT, TLSInfo);
95
return Error::success();
96
}
97
} // namespace
98
99
namespace llvm {
100
namespace jitlink {
101
102
class ELFLinkGraphBuilder_x86_64 : public ELFLinkGraphBuilder<object::ELF64LE> {
103
private:
104
using ELFT = object::ELF64LE;
105
106
Error addRelocations() override {
107
LLVM_DEBUG(dbgs() << "Processing relocations:\n");
108
109
using Base = ELFLinkGraphBuilder<ELFT>;
110
using Self = ELFLinkGraphBuilder_x86_64;
111
for (const auto &RelSect : Base::Sections) {
112
// Validate the section to read relocation entries from.
113
if (RelSect.sh_type == ELF::SHT_REL)
114
return make_error<StringError>(
115
"No SHT_REL in valid x64 ELF object files",
116
inconvertibleErrorCode());
117
118
if (Error Err = Base::forEachRelaRelocation(RelSect, this,
119
&Self::addSingleRelocation))
120
return Err;
121
}
122
123
return Error::success();
124
}
125
126
Error addSingleRelocation(const typename ELFT::Rela &Rel,
127
const typename ELFT::Shdr &FixupSection,
128
Block &BlockToFix) {
129
using Base = ELFLinkGraphBuilder<ELFT>;
130
131
auto ELFReloc = Rel.getType(false);
132
133
// R_X86_64_NONE is a no-op.
134
if (LLVM_UNLIKELY(ELFReloc == ELF::R_X86_64_NONE))
135
return Error::success();
136
137
uint32_t SymbolIndex = Rel.getSymbol(false);
138
auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
139
if (!ObjSymbol)
140
return ObjSymbol.takeError();
141
142
Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
143
if (!GraphSymbol)
144
return make_error<StringError>(
145
formatv("Could not find symbol at given index, did you add it to "
146
"JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
147
SymbolIndex, (*ObjSymbol)->st_shndx,
148
Base::GraphSymbols.size()),
149
inconvertibleErrorCode());
150
151
// Validate the relocation kind.
152
int64_t Addend = Rel.r_addend;
153
Edge::Kind Kind = Edge::Invalid;
154
155
switch (ELFReloc) {
156
case ELF::R_X86_64_PC8:
157
Kind = x86_64::Delta8;
158
break;
159
case ELF::R_X86_64_PC32:
160
case ELF::R_X86_64_GOTPC32:
161
Kind = x86_64::Delta32;
162
break;
163
case ELF::R_X86_64_PC64:
164
case ELF::R_X86_64_GOTPC64:
165
Kind = x86_64::Delta64;
166
break;
167
case ELF::R_X86_64_32:
168
Kind = x86_64::Pointer32;
169
break;
170
case ELF::R_X86_64_16:
171
Kind = x86_64::Pointer16;
172
break;
173
case ELF::R_X86_64_8:
174
Kind = x86_64::Pointer8;
175
break;
176
case ELF::R_X86_64_32S:
177
Kind = x86_64::Pointer32Signed;
178
break;
179
case ELF::R_X86_64_64:
180
Kind = x86_64::Pointer64;
181
break;
182
case ELF::R_X86_64_GOTPCREL:
183
Kind = x86_64::RequestGOTAndTransformToDelta32;
184
break;
185
case ELF::R_X86_64_REX_GOTPCRELX:
186
Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable;
187
Addend = 0;
188
break;
189
case ELF::R_X86_64_TLSGD:
190
Kind = x86_64::RequestTLSDescInGOTAndTransformToDelta32;
191
break;
192
case ELF::R_X86_64_GOTPCRELX:
193
Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable;
194
Addend = 0;
195
break;
196
case ELF::R_X86_64_GOTPCREL64:
197
Kind = x86_64::RequestGOTAndTransformToDelta64;
198
break;
199
case ELF::R_X86_64_GOT64:
200
Kind = x86_64::RequestGOTAndTransformToDelta64FromGOT;
201
break;
202
case ELF::R_X86_64_GOTOFF64:
203
Kind = x86_64::Delta64FromGOT;
204
break;
205
case ELF::R_X86_64_PLT32:
206
Kind = x86_64::BranchPCRel32;
207
// BranchPCRel32 implicitly handles the '-4' PC adjustment, so we have to
208
// adjust the addend by '+4' to compensate.
209
Addend += 4;
210
break;
211
default:
212
return make_error<JITLinkError>(
213
"In " + G->getName() + ": Unsupported x86-64 relocation type " +
214
object::getELFRelocationTypeName(ELF::EM_X86_64, ELFReloc));
215
}
216
217
auto FixupAddress = orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset;
218
Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
219
Edge GE(Kind, Offset, *GraphSymbol, Addend);
220
LLVM_DEBUG({
221
dbgs() << " ";
222
printEdge(dbgs(), BlockToFix, GE, x86_64::getEdgeKindName(Kind));
223
dbgs() << "\n";
224
});
225
226
BlockToFix.addEdge(std::move(GE));
227
return Error::success();
228
}
229
230
public:
231
ELFLinkGraphBuilder_x86_64(StringRef FileName,
232
const object::ELFFile<object::ELF64LE> &Obj,
233
SubtargetFeatures Features)
234
: ELFLinkGraphBuilder(Obj, Triple("x86_64-unknown-linux"),
235
std::move(Features), FileName,
236
x86_64::getEdgeKindName) {}
237
};
238
239
class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
240
friend class JITLinker<ELFJITLinker_x86_64>;
241
242
public:
243
ELFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
244
std::unique_ptr<LinkGraph> G,
245
PassConfiguration PassConfig)
246
: JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {
247
248
if (shouldAddDefaultTargetPasses(getGraph().getTargetTriple()))
249
getPassConfig().PostAllocationPasses.push_back(
250
[this](LinkGraph &G) { return getOrCreateGOTSymbol(G); });
251
}
252
253
private:
254
Symbol *GOTSymbol = nullptr;
255
256
Error getOrCreateGOTSymbol(LinkGraph &G) {
257
auto DefineExternalGOTSymbolIfPresent =
258
createDefineExternalSectionStartAndEndSymbolsPass(
259
[&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {
260
if (Sym.getName() == ELFGOTSymbolName)
261
if (auto *GOTSection = G.findSectionByName(
262
x86_64::GOTTableManager::getSectionName())) {
263
GOTSymbol = &Sym;
264
return {*GOTSection, true};
265
}
266
return {};
267
});
268
269
// Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an
270
// external.
271
if (auto Err = DefineExternalGOTSymbolIfPresent(G))
272
return Err;
273
274
// If we succeeded then we're done.
275
if (GOTSymbol)
276
return Error::success();
277
278
// Otherwise look for a GOT section: If it already has a start symbol we'll
279
// record it, otherwise we'll create our own.
280
// If there's a GOT section but we didn't find an external GOT symbol...
281
if (auto *GOTSection =
282
G.findSectionByName(x86_64::GOTTableManager::getSectionName())) {
283
284
// Check for an existing defined symbol.
285
for (auto *Sym : GOTSection->symbols())
286
if (Sym->getName() == ELFGOTSymbolName) {
287
GOTSymbol = Sym;
288
return Error::success();
289
}
290
291
// If there's no defined symbol then create one.
292
SectionRange SR(*GOTSection);
293
if (SR.empty())
294
GOTSymbol =
295
&G.addAbsoluteSymbol(ELFGOTSymbolName, orc::ExecutorAddr(), 0,
296
Linkage::Strong, Scope::Local, true);
297
else
298
GOTSymbol =
299
&G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0,
300
Linkage::Strong, Scope::Local, false, true);
301
}
302
303
// If we still haven't found a GOT symbol then double check the externals.
304
// We may have a GOT-relative reference but no GOT section, in which case
305
// we just need to point the GOT symbol at some address in this graph.
306
if (!GOTSymbol) {
307
for (auto *Sym : G.external_symbols()) {
308
if (Sym->getName() == ELFGOTSymbolName) {
309
auto Blocks = G.blocks();
310
if (!Blocks.empty()) {
311
G.makeAbsolute(*Sym, (*Blocks.begin())->getAddress());
312
GOTSymbol = Sym;
313
break;
314
}
315
}
316
}
317
}
318
319
return Error::success();
320
}
321
322
Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
323
return x86_64::applyFixup(G, B, E, GOTSymbol);
324
}
325
};
326
327
Expected<std::unique_ptr<LinkGraph>>
328
createLinkGraphFromELFObject_x86_64(MemoryBufferRef ObjectBuffer) {
329
LLVM_DEBUG({
330
dbgs() << "Building jitlink graph for new input "
331
<< ObjectBuffer.getBufferIdentifier() << "...\n";
332
});
333
334
auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
335
if (!ELFObj)
336
return ELFObj.takeError();
337
338
auto Features = (*ELFObj)->getFeatures();
339
if (!Features)
340
return Features.takeError();
341
342
auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
343
return ELFLinkGraphBuilder_x86_64((*ELFObj)->getFileName(),
344
ELFObjFile.getELFFile(),
345
std::move(*Features))
346
.buildGraph();
347
}
348
349
void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
350
std::unique_ptr<JITLinkContext> Ctx) {
351
PassConfiguration Config;
352
353
if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
354
355
Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));
356
Config.PrePrunePasses.push_back(EHFrameEdgeFixer(
357
".eh_frame", x86_64::PointerSize, x86_64::Pointer32, x86_64::Pointer64,
358
x86_64::Delta32, x86_64::Delta64, x86_64::NegDelta32));
359
Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));
360
361
// Construct a JITLinker and run the link function.
362
// Add a mark-live pass.
363
if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
364
Config.PrePrunePasses.push_back(std::move(MarkLive));
365
else
366
Config.PrePrunePasses.push_back(markAllSymbolsLive);
367
368
// Add an in-place GOT/Stubs/TLSInfoEntry build pass.
369
Config.PostPrunePasses.push_back(buildTables_ELF_x86_64);
370
371
// Resolve any external section start / end symbols.
372
Config.PostAllocationPasses.push_back(
373
createDefineExternalSectionStartAndEndSymbolsPass(
374
identifyELFSectionStartAndEndSymbols));
375
376
// Add GOT/Stubs optimizer pass.
377
Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses);
378
}
379
380
if (auto Err = Ctx->modifyPassConfig(*G, Config))
381
return Ctx->notifyFailed(std::move(Err));
382
383
ELFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
384
}
385
} // end namespace jitlink
386
} // end namespace llvm
387
388