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/XCOFFLinkGraphBuilder.cpp
213799 views
1
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2
// See https://llvm.org/LICENSE.txt for license information.
3
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
//
5
//===----------------------------------------------------------------------===//
6
//
7
// Generic XCOFF LinkGraph building code.
8
//
9
//===----------------------------------------------------------------------===//
10
11
#include "XCOFFLinkGraphBuilder.h"
12
#include "llvm/ADT/STLExtras.h"
13
#include "llvm/BinaryFormat/XCOFF.h"
14
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
15
#include "llvm/ExecutionEngine/JITLink/ppc64.h"
16
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
17
#include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h"
18
#include "llvm/Object/ObjectFile.h"
19
#include "llvm/Object/XCOFFObjectFile.h"
20
#include "llvm/Support/Debug.h"
21
#include "llvm/Support/Error.h"
22
#include "llvm/Support/Format.h"
23
#include "llvm/Support/raw_ostream.h"
24
#include <memory>
25
26
using namespace llvm;
27
28
#define DEBUG_TYPE "jitlink"
29
30
namespace llvm {
31
namespace jitlink {
32
33
XCOFFLinkGraphBuilder::XCOFFLinkGraphBuilder(
34
const object::XCOFFObjectFile &Obj,
35
std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
36
SubtargetFeatures Features,
37
LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
38
: Obj(Obj),
39
G(std::make_unique<LinkGraph>(
40
std::string(Obj.getFileName()), std::move(SSP), std::move(TT),
41
std::move(Features), std::move(GetEdgeKindName))) {}
42
43
#ifndef NDEBUG
44
static llvm::StringRef getStorageClassString(XCOFF::StorageClass SC) {
45
switch (SC) {
46
case XCOFF::StorageClass::C_FILE:
47
return "C_FILE (File name)";
48
case XCOFF::StorageClass::C_BINCL:
49
return "C_BINCL (Beginning of include file)";
50
case XCOFF::StorageClass::C_EINCL:
51
return "C_EINCL (Ending of include file)";
52
case XCOFF::StorageClass::C_GSYM:
53
return "C_GSYM (Global variable)";
54
case XCOFF::StorageClass::C_STSYM:
55
return "C_STSYM (Statically allocated symbol)";
56
case XCOFF::StorageClass::C_BCOMM:
57
return "C_BCOMM (Beginning of common block)";
58
case XCOFF::StorageClass::C_ECOMM:
59
return "C_ECOMM (End of common block)";
60
case XCOFF::StorageClass::C_ENTRY:
61
return "C_ENTRY (Alternate entry)";
62
case XCOFF::StorageClass::C_BSTAT:
63
return "C_BSTAT (Beginning of static block)";
64
case XCOFF::StorageClass::C_ESTAT:
65
return "C_ESTAT (End of static block)";
66
case XCOFF::StorageClass::C_GTLS:
67
return "C_GTLS (Global thread-local variable)";
68
case XCOFF::StorageClass::C_STTLS:
69
return "C_STTLS (Static thread-local variable)";
70
case XCOFF::StorageClass::C_DWARF:
71
return "C_DWARF (DWARF section symbol)";
72
case XCOFF::StorageClass::C_LSYM:
73
return "C_LSYM (Automatic variable allocated on stack)";
74
case XCOFF::StorageClass::C_PSYM:
75
return "C_PSYM (Argument to subroutine allocated on stack)";
76
case XCOFF::StorageClass::C_RSYM:
77
return "C_RSYM (Register variable)";
78
case XCOFF::StorageClass::C_RPSYM:
79
return "C_RPSYM (Argument to function stored in register)";
80
case XCOFF::StorageClass::C_ECOML:
81
return "C_ECOML (Local member of common block)";
82
case XCOFF::StorageClass::C_FUN:
83
return "C_FUN (Function or procedure)";
84
case XCOFF::StorageClass::C_EXT:
85
return "C_EXT (External symbol)";
86
case XCOFF::StorageClass::C_WEAKEXT:
87
return "C_WEAKEXT (Weak external symbol)";
88
case XCOFF::StorageClass::C_NULL:
89
return "C_NULL";
90
case XCOFF::StorageClass::C_STAT:
91
return "C_STAT (Static)";
92
case XCOFF::StorageClass::C_BLOCK:
93
return "C_BLOCK (\".bb\" or \".eb\")";
94
case XCOFF::StorageClass::C_FCN:
95
return "C_FCN (\".bf\" or \".ef\")";
96
case XCOFF::StorageClass::C_HIDEXT:
97
return "C_HIDEXT (Un-named external symbol)";
98
case XCOFF::StorageClass::C_INFO:
99
return "C_INFO (Comment string in .info section)";
100
case XCOFF::StorageClass::C_DECL:
101
return "C_DECL (Declaration of object)";
102
case XCOFF::StorageClass::C_AUTO:
103
return "C_AUTO (Automatic variable)";
104
case XCOFF::StorageClass::C_REG:
105
return "C_REG (Register variable)";
106
case XCOFF::StorageClass::C_EXTDEF:
107
return "C_EXTDEF (External definition)";
108
case XCOFF::StorageClass::C_LABEL:
109
return "C_LABEL (Label)";
110
case XCOFF::StorageClass::C_ULABEL:
111
return "C_ULABEL (Undefined label)";
112
case XCOFF::StorageClass::C_MOS:
113
return "C_MOS (Member of structure)";
114
case XCOFF::StorageClass::C_ARG:
115
return "C_ARG (Function argument)";
116
case XCOFF::StorageClass::C_STRTAG:
117
return "C_STRTAG (Structure tag)";
118
case XCOFF::StorageClass::C_MOU:
119
return "C_MOU (Member of union)";
120
case XCOFF::StorageClass::C_UNTAG:
121
return "C_UNTAG (Union tag)";
122
case XCOFF::StorageClass::C_TPDEF:
123
return "C_TPDEF (Type definition)";
124
case XCOFF::StorageClass::C_USTATIC:
125
return "C_USTATIC (Undefined static)";
126
case XCOFF::StorageClass::C_ENTAG:
127
return "C_ENTAG (Enumeration tag)";
128
case XCOFF::StorageClass::C_MOE:
129
return "C_MOE (Member of enumeration)";
130
case XCOFF::StorageClass::C_REGPARM:
131
return "C_REGPARM (Register parameter)";
132
case XCOFF::StorageClass::C_FIELD:
133
return "C_FIELD (Bit field)";
134
case XCOFF::StorageClass::C_EOS:
135
return "C_EOS (End of structure)";
136
case XCOFF::StorageClass::C_LINE:
137
return "C_LINE";
138
case XCOFF::StorageClass::C_ALIAS:
139
return "C_ALIAS (Duplicate tag)";
140
case XCOFF::StorageClass::C_HIDDEN:
141
return "C_HIDDEN (Special storage class for external)";
142
case XCOFF::StorageClass::C_EFCN:
143
return "C_EFCN (Physical end of function)";
144
case XCOFF::StorageClass::C_TCSYM:
145
return "C_TCSYM (Reserved)";
146
}
147
llvm_unreachable("Unknown XCOFF::StorageClass enum");
148
}
149
#endif
150
151
Error XCOFFLinkGraphBuilder::processSections() {
152
LLVM_DEBUG(dbgs() << " Creating graph sections...\n");
153
154
UndefSection = &G->createSection("*UND*", orc::MemProt::None);
155
156
for (object::SectionRef Section : Obj.sections()) {
157
auto SectionName = Section.getName();
158
if (!SectionName)
159
return SectionName.takeError();
160
161
LLVM_DEBUG({
162
dbgs() << " section = " << *SectionName
163
<< ", idx = " << Section.getIndex()
164
<< ", size = " << format_hex_no_prefix(Section.getSize(), 8)
165
<< ", vma = " << format_hex(Section.getAddress(), 16) << "\n";
166
});
167
168
// We can skip debug (including dawrf) and pad sections
169
if (Section.isDebugSection() || *SectionName == "pad")
170
continue;
171
LLVM_DEBUG(dbgs() << " creating graph section\n");
172
173
orc::MemProt Prot = orc::MemProt::Read;
174
if (Section.isText())
175
Prot |= orc::MemProt::Exec;
176
if (Section.isData() || Section.isBSS())
177
Prot |= orc::MemProt::Write;
178
179
jitlink::Section *GraphSec = &G->createSection(*SectionName, Prot);
180
// TODO: Check for no_alloc for certain sections
181
182
assert(!SectionTable.contains(Section.getIndex()) &&
183
"Section with same index already exists");
184
SectionTable[Section.getIndex()] = {GraphSec, Section};
185
}
186
187
return Error::success();
188
}
189
190
static std::optional<object::XCOFFSymbolRef>
191
getXCOFFSymbolContainingSymbolRef(const object::XCOFFObjectFile &Obj,
192
const object::SymbolRef &Sym) {
193
const object::XCOFFSymbolRef SymRef =
194
Obj.toSymbolRef(Sym.getRawDataRefImpl());
195
if (!SymRef.isCsectSymbol())
196
return std::nullopt;
197
198
Expected<object::XCOFFCsectAuxRef> CsectAuxEntOrErr =
199
SymRef.getXCOFFCsectAuxRef();
200
if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel())
201
return std::nullopt;
202
uint32_t Idx =
203
static_cast<uint32_t>(CsectAuxEntOrErr.get().getSectionOrLength());
204
object::DataRefImpl DRI;
205
DRI.p = Obj.getSymbolByIndex(Idx);
206
return object::XCOFFSymbolRef(DRI, &Obj);
207
}
208
209
#ifndef NDEBUG
210
static void printSymbolEntry(raw_ostream &OS,
211
const object::XCOFFObjectFile &Obj,
212
const object::XCOFFSymbolRef &Sym) {
213
OS << " " << format_hex(cantFail(Sym.getAddress()), 16);
214
OS << " " << left_justify(cantFail(Sym.getName()), 10);
215
if (Sym.isCsectSymbol()) {
216
auto CsectAuxEntry = cantFail(Sym.getXCOFFCsectAuxRef());
217
if (!CsectAuxEntry.isLabel()) {
218
std::string MCStr =
219
"[" +
220
XCOFF::getMappingClassString(CsectAuxEntry.getStorageMappingClass())
221
.str() +
222
"]";
223
OS << left_justify(MCStr, 3);
224
}
225
}
226
OS << " " << format_hex(Sym.getSize(), 8);
227
OS << " " << Sym.getSectionNumber();
228
OS << " " << getStorageClassString(Sym.getStorageClass());
229
OS << " (idx: " << Obj.getSymbolIndex(Sym.getRawDataRefImpl().p) << ")";
230
if (Sym.isCsectSymbol()) {
231
if (auto ParentSym = getXCOFFSymbolContainingSymbolRef(Obj, Sym)) {
232
OS << " (csect idx: "
233
<< Obj.getSymbolIndex(ParentSym->getRawDataRefImpl().p) << ")";
234
}
235
}
236
OS << "\n";
237
}
238
#endif
239
240
Error XCOFFLinkGraphBuilder::processCsectsAndSymbols() {
241
LLVM_DEBUG(dbgs() << " Creating graph blocks and symbols...\n");
242
243
for ([[maybe_unused]] auto [K, V] : SectionTable) {
244
LLVM_DEBUG(dbgs() << " section entry(idx: " << K
245
<< " section: " << V.Section->getName() << ")\n");
246
}
247
248
for (object::XCOFFSymbolRef Symbol : Obj.symbols()) {
249
LLVM_DEBUG({ printSymbolEntry(dbgs(), Obj, Symbol); });
250
251
auto Flags = Symbol.getFlags();
252
if (!Flags)
253
return Flags.takeError();
254
255
bool External = *Flags & object::SymbolRef::SF_Undefined;
256
bool Weak = *Flags & object::SymbolRef::SF_Weak;
257
bool Global = *Flags & object::SymbolRef::SF_Global;
258
259
auto SymbolIndex = Obj.getSymbolIndex(Symbol.getEntryAddress());
260
auto SymbolName = Symbol.getName();
261
if (!SymbolName)
262
return SymbolName.takeError();
263
264
if (External) {
265
LLVM_DEBUG(dbgs() << " created external symbol\n");
266
SymbolIndexTable[SymbolIndex] =
267
&G->addExternalSymbol(*SymbolName, Symbol.getSize(), Weak);
268
continue;
269
}
270
271
if (!Symbol.isCsectSymbol()) {
272
LLVM_DEBUG(dbgs() << " skipped: not a csect symbol\n");
273
continue;
274
}
275
276
auto ParentSym = getXCOFFSymbolContainingSymbolRef(Obj, Symbol);
277
object::XCOFFSymbolRef CsectSymbol = ParentSym ? *ParentSym : Symbol;
278
279
auto CsectSymbolIndex = Obj.getSymbolIndex(CsectSymbol.getEntryAddress());
280
auto ParentSectionNumber = CsectSymbol.getSectionNumber();
281
282
bool IsUndefinedSection = !SectionTable.contains(ParentSectionNumber);
283
Section *ParentSection = !IsUndefinedSection
284
? SectionTable[ParentSectionNumber].Section
285
: UndefSection;
286
Block *B = nullptr;
287
288
// TODO: Clean up the logic for handling undefined symbols
289
if (!CsectTable.contains(CsectSymbolIndex) && !IsUndefinedSection) {
290
object::SectionRef &SectionRef =
291
SectionTable[ParentSectionNumber].SectionData;
292
auto Data = SectionRef.getContents();
293
if (!Data)
294
return Data.takeError();
295
auto CsectSymbolAddr = CsectSymbol.getAddress();
296
if (!CsectSymbolAddr)
297
return CsectSymbolAddr.takeError();
298
299
ArrayRef<char> SectionBuffer{*Data};
300
auto Offset = *CsectSymbolAddr - SectionRef.getAddress();
301
302
LLVM_DEBUG(dbgs() << " symbol entry: offset = " << Offset
303
<< ", size = " << CsectSymbol.getSize()
304
<< ", storage class = "
305
<< getStorageClassString(CsectSymbol.getStorageClass())
306
<< "\n");
307
308
B = &G->createContentBlock(
309
*ParentSection, SectionBuffer.slice(Offset, CsectSymbol.getSize()),
310
orc::ExecutorAddr(*CsectSymbolAddr), CsectSymbol.getAlignment(), 0);
311
312
CsectTable[CsectSymbolIndex] = B;
313
} else {
314
B = CsectTable[CsectSymbolIndex];
315
}
316
317
Scope S{Scope::Local};
318
if (Symbol.getSymbolType() & XCOFF::SYM_V_HIDDEN ||
319
Symbol.getSymbolType() & XCOFF::SYM_V_INTERNAL)
320
S = Scope::Hidden;
321
else if (Global)
322
S = Scope::Default;
323
// TODO: map all symbols for c++ static initialization to SideEffectOnly
324
325
Linkage L = Weak ? Linkage::Weak : Linkage::Strong;
326
auto SymbolAddr = Symbol.getAddress();
327
if (!SymbolAddr)
328
return SymbolAddr.takeError();
329
auto IsCallableOrErr = Symbol.isFunction();
330
if (!IsCallableOrErr)
331
return IsCallableOrErr.takeError();
332
333
auto BlockOffset = *SymbolAddr - B->getAddress().getValue();
334
335
LLVM_DEBUG(dbgs() << " creating with linkage = " << getLinkageName(L)
336
<< ", scope = " << getScopeName(S) << ", B = "
337
<< format_hex(B->getAddress().getValue(), 16) << "\n");
338
339
SymbolIndexTable[SymbolIndex] =
340
&G->addDefinedSymbol(*B, BlockOffset, *SymbolName, Symbol.getSize(), L,
341
S, *IsCallableOrErr, true);
342
}
343
344
return Error::success();
345
}
346
347
Error XCOFFLinkGraphBuilder::processRelocations() {
348
LLVM_DEBUG(dbgs() << " Creating relocations...\n");
349
350
for (object::SectionRef Section : Obj.sections()) {
351
auto SectionName = Section.getName();
352
if (!SectionName)
353
return SectionName.takeError();
354
355
LLVM_DEBUG(dbgs() << " Relocations for section " << *SectionName
356
<< ":\n");
357
358
for (object::RelocationRef Relocation : Section.relocations()) {
359
SmallString<16> RelocName;
360
Relocation.getTypeName(RelocName);
361
object::SymbolRef Symbol = *Relocation.getSymbol();
362
363
auto TargetSymbol = Symbol.getName();
364
if (!TargetSymbol)
365
return TargetSymbol.takeError();
366
367
auto SymbolIndex = Obj.getSymbolIndex(Symbol.getRawDataRefImpl().p);
368
369
LLVM_DEBUG(dbgs() << " " << format_hex(Relocation.getOffset(), 16)
370
<< " (idx: " << SymbolIndex << ")"
371
<< " " << RelocName << " " << *TargetSymbol << "\n";);
372
373
assert(SymbolIndexTable.contains(SymbolIndex) &&
374
"Relocation needs a record in the symbol table");
375
auto *S = SymbolIndexTable[SymbolIndex];
376
auto It = find_if(G->blocks(),
377
[Target = orc::ExecutorAddr(Section.getAddress() +
378
Relocation.getOffset())](
379
const Block *B) -> bool {
380
return B->getRange().contains(Target);
381
});
382
assert(It != G->blocks().end() &&
383
"Cannot find the target relocation block");
384
Block *B = *It;
385
386
auto TargetBlockOffset = Section.getAddress() + Relocation.getOffset() -
387
B->getAddress().getValue();
388
switch (Relocation.getType()) {
389
case XCOFF::R_POS:
390
B->addEdge(ppc64::EdgeKind_ppc64::Pointer64, TargetBlockOffset, *S, 0);
391
break;
392
default:
393
SmallString<16> RelocType;
394
Relocation.getTypeName(RelocType);
395
return make_error<StringError>(
396
"Unsupported Relocation Type: " + RelocType, std::error_code());
397
}
398
}
399
}
400
401
return Error::success();
402
}
403
404
Expected<std::unique_ptr<LinkGraph>> XCOFFLinkGraphBuilder::buildGraph() {
405
LLVM_DEBUG(dbgs() << "Building XCOFFLinkGraph...\n");
406
407
// FIXME: Check to make sure the object is relocatable
408
409
if (auto Err = processSections())
410
return Err;
411
if (auto Err = processCsectsAndSymbols())
412
return Err;
413
if (auto Err = processRelocations())
414
return Err;
415
416
return std::move(G);
417
}
418
419
} // namespace jitlink
420
} // namespace llvm
421
422