LLVM 17.0.0git
ELFLinkGraphBuilder.h
Go to the documentation of this file.
1//===------- ELFLinkGraphBuilder.h - ELF LinkGraph builder ------*- C++ -*-===//
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// Generic ELF LinkGraph building code.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H
14#define LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H
15
17#include "llvm/Object/ELF.h"
18#include "llvm/Support/Debug.h"
19#include "llvm/Support/Error.h"
21
22#define DEBUG_TYPE "jitlink"
23
24namespace llvm {
25namespace jitlink {
26
27/// Common link-graph building code shared between all ELFFiles.
29public:
30 ELFLinkGraphBuilderBase(std::unique_ptr<LinkGraph> G) : G(std::move(G)) {}
32
33protected:
35 return llvm::is_contained(DwarfSectionNames, SectionName);
36 }
37
39 if (!CommonSection)
40 CommonSection = &G->createSection(
41 CommonSectionName, orc::MemProt::Read | orc::MemProt::Write);
42 return *CommonSection;
43 }
44
45 std::unique_ptr<LinkGraph> G;
46
47private:
48 static StringRef CommonSectionName;
49 static ArrayRef<const char *> DwarfSectionNames;
50
51 Section *CommonSection = nullptr;
52};
53
54/// Ling-graph building code that's specific to the given ELFT, but common
55/// across all architectures.
56template <typename ELFT>
59
60public:
62 StringRef FileName,
64
65 /// Attempt to construct and return the LinkGraph.
67
68 /// Call to derived class to handle relocations. These require
69 /// architecture specific knowledge to map to JITLink edge kinds.
70 virtual Error addRelocations() = 0;
71
72protected:
75
76 bool isRelocatable() const {
77 return Obj.getHeader().e_type == llvm::ELF::ET_REL;
78 }
79
81 assert(!GraphBlocks.count(SecIndex) && "Duplicate section at index");
82 GraphBlocks[SecIndex] = B;
83 }
84
86 auto I = GraphBlocks.find(SecIndex);
87 if (I == GraphBlocks.end())
88 return nullptr;
89 return I->second;
90 }
91
92 void setGraphSymbol(ELFSymbolIndex SymIndex, Symbol &Sym) {
93 assert(!GraphSymbols.count(SymIndex) && "Duplicate symbol at index");
94 GraphSymbols[SymIndex] = &Sym;
95 }
96
98 auto I = GraphSymbols.find(SymIndex);
99 if (I == GraphSymbols.end())
100 return nullptr;
101 return I->second;
102 }
103
105 getSymbolLinkageAndScope(const typename ELFT::Sym &Sym, StringRef Name);
106
110
111 /// Traverse all matching ELFT::Rela relocation records in the given section.
112 /// The handler function Func should be callable with this signature:
113 /// Error(const typename ELFT::Rela &,
114 /// const typename ELFT::Shdr &, Section &)
115 ///
116 template <typename RelocHandlerMethod>
117 Error forEachRelaRelocation(const typename ELFT::Shdr &RelSect,
118 RelocHandlerMethod &&Func,
119 bool ProcessDebugSections = false);
120
121 /// Traverse all matching ELFT::Rel relocation records in the given section.
122 /// The handler function Func should be callable with this signature:
123 /// Error(const typename ELFT::Rel &,
124 /// const typename ELFT::Shdr &, Section &)
125 ///
126 template <typename RelocHandlerMethod>
127 Error forEachRelRelocation(const typename ELFT::Shdr &RelSect,
128 RelocHandlerMethod &&Func,
129 bool ProcessDebugSections = false);
130
131 /// Traverse all matching rela relocation records in the given section.
132 /// Convenience wrapper to allow passing a member function for the handler.
133 ///
134 template <typename ClassT, typename RelocHandlerMethod>
135 Error forEachRelaRelocation(const typename ELFT::Shdr &RelSect,
136 ClassT *Instance, RelocHandlerMethod &&Method,
137 bool ProcessDebugSections = false) {
139 RelSect,
140 [Instance, Method](const auto &Rel, const auto &Target, auto &GS) {
141 return (Instance->*Method)(Rel, Target, GS);
142 },
143 ProcessDebugSections);
144 }
145
146 /// Traverse all matching rel relocation records in the given section.
147 /// Convenience wrapper to allow passing a member function for the handler.
148 ///
149 template <typename ClassT, typename RelocHandlerMethod>
150 Error forEachRelRelocation(const typename ELFT::Shdr &RelSect,
151 ClassT *Instance, RelocHandlerMethod &&Method,
152 bool ProcessDebugSections = false) {
154 RelSect,
155 [Instance, Method](const auto &Rel, const auto &Target, auto &GS) {
156 return (Instance->*Method)(Rel, Target, GS);
157 },
158 ProcessDebugSections);
159 }
160
161 const ELFFile &Obj;
162
163 typename ELFFile::Elf_Shdr_Range Sections;
164 const typename ELFFile::Elf_Shdr *SymTabSec = nullptr;
166
167 // Maps ELF section indexes to LinkGraph Blocks.
168 // Only SHF_ALLOC sections will have graph blocks.
171 DenseMap<const typename ELFFile::Elf_Shdr *,
174};
175
176template <typename ELFT>
178 const ELFFile &Obj, Triple TT, StringRef FileName,
180 : ELFLinkGraphBuilderBase(std::make_unique<LinkGraph>(
181 FileName.str(), Triple(std::move(TT)), ELFT::Is64Bits ? 8 : 4,
182 support::endianness(ELFT::TargetEndianness),
183 std::move(GetEdgeKindName))),
184 Obj(Obj) {
186 { dbgs() << "Created ELFLinkGraphBuilder for \"" << FileName << "\""; });
187}
188
189template <typename ELFT>
191 if (!isRelocatable())
192 return make_error<JITLinkError>("Object is not a relocatable ELF file");
193
194 if (auto Err = prepare())
195 return std::move(Err);
196
197 if (auto Err = graphifySections())
198 return std::move(Err);
199
200 if (auto Err = graphifySymbols())
201 return std::move(Err);
202
203 if (auto Err = addRelocations())
204 return std::move(Err);
205
206 return std::move(G);
207}
208
209template <typename ELFT>
212 const typename ELFT::Sym &Sym, StringRef Name) {
215
216 switch (Sym.getBinding()) {
217 case ELF::STB_LOCAL:
218 S = Scope::Local;
219 break;
220 case ELF::STB_GLOBAL:
221 // Nothing to do here.
222 break;
223 case ELF::STB_WEAK:
225 L = Linkage::Weak;
226 break;
227 default:
228 return make_error<StringError>(
229 "Unrecognized symbol binding " +
230 Twine(static_cast<int>(Sym.getBinding())) + " for " + Name,
232 }
233
234 switch (Sym.getVisibility()) {
235 case ELF::STV_DEFAULT:
237 // FIXME: Make STV_DEFAULT symbols pre-emptible? This probably needs
238 // Orc support.
239 // Otherwise nothing to do here.
240 break;
241 case ELF::STV_HIDDEN:
242 // Default scope -> Hidden scope. No effect on local scope.
243 if (S == Scope::Default)
244 S = Scope::Hidden;
245 break;
247 return make_error<StringError>(
248 "Unrecognized symbol visibility " +
249 Twine(static_cast<int>(Sym.getVisibility())) + " for " + Name,
251 }
252
253 return std::make_pair(L, S);
254}
255
256template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::prepare() {
257 LLVM_DEBUG(dbgs() << " Preparing to build...\n");
258
259 // Get the sections array.
260 if (auto SectionsOrErr = Obj.sections())
261 Sections = *SectionsOrErr;
262 else
263 return SectionsOrErr.takeError();
264
265 // Get the section string table.
266 if (auto SectionStringTabOrErr = Obj.getSectionStringTable(Sections))
267 SectionStringTab = *SectionStringTabOrErr;
268 else
269 return SectionStringTabOrErr.takeError();
270
271 // Get the SHT_SYMTAB section.
272 for (auto &Sec : Sections) {
273 if (Sec.sh_type == ELF::SHT_SYMTAB) {
274 if (!SymTabSec)
275 SymTabSec = &Sec;
276 else
277 return make_error<JITLinkError>("Multiple SHT_SYMTAB sections in " +
278 G->getName());
279 }
280
281 // Extended table.
282 if (Sec.sh_type == ELF::SHT_SYMTAB_SHNDX) {
283 uint32_t SymtabNdx = Sec.sh_link;
284 if (SymtabNdx >= Sections.size())
285 return make_error<JITLinkError>("sh_link is out of bound");
286
287 auto ShndxTable = Obj.getSHNDXTable(Sec);
288 if (!ShndxTable)
289 return ShndxTable.takeError();
290
291 ShndxTables.insert({&Sections[SymtabNdx], *ShndxTable});
292 }
293 }
294
295 return Error::success();
296}
297
299 LLVM_DEBUG(dbgs() << " Creating graph sections...\n");
300
301 // For each section...
302 for (ELFSectionIndex SecIndex = 0; SecIndex != Sections.size(); ++SecIndex) {
303
304 auto &Sec = Sections[SecIndex];
305
306 // Start by getting the section name.
307 auto Name = Obj.getSectionName(Sec, SectionStringTab);
308 if (!Name)
309 return Name.takeError();
310
311 // If the name indicates that it's a debug section then skip it: We don't
312 // support those yet.
313 if (isDwarfSection(*Name)) {
314 LLVM_DEBUG({
315 dbgs() << " " << SecIndex << ": \"" << *Name
316 << "\" is a debug section: "
317 "No graph section will be created.\n";
318 });
319 continue;
320 }
321
322 // Skip non-SHF_ALLOC sections
323 if (!(Sec.sh_flags & ELF::SHF_ALLOC)) {
324 LLVM_DEBUG({
325 dbgs() << " " << SecIndex << ": \"" << *Name
326 << "\" is not an SHF_ALLOC section: "
327 "No graph section will be created.\n";
328 });
329 continue;
330 }
331
332 LLVM_DEBUG({
333 dbgs() << " " << SecIndex << ": Creating section for \"" << *Name
334 << "\"\n";
335 });
336
337 // Get the section's memory protection flags.
338 orc::MemProt Prot;
339 if (Sec.sh_flags & ELF::SHF_EXECINSTR)
341 else
343
344 // Look for existing sections first.
345 auto *GraphSec = G->findSectionByName(*Name);
346 if (!GraphSec)
347 GraphSec = &G->createSection(*Name, Prot);
348 assert(GraphSec->getMemProt() == Prot && "MemProt should match");
349
350 Block *B = nullptr;
351 if (Sec.sh_type != ELF::SHT_NOBITS) {
352 auto Data = Obj.template getSectionContentsAsArray<char>(Sec);
353 if (!Data)
354 return Data.takeError();
355
356 B = &G->createContentBlock(*GraphSec, *Data,
357 orc::ExecutorAddr(Sec.sh_addr),
358 Sec.sh_addralign, 0);
359 } else
360 B = &G->createZeroFillBlock(*GraphSec, Sec.sh_size,
361 orc::ExecutorAddr(Sec.sh_addr),
362 Sec.sh_addralign, 0);
363
364 setGraphBlock(SecIndex, B);
365 }
366
367 return Error::success();
368}
369
371 LLVM_DEBUG(dbgs() << " Creating graph symbols...\n");
372
373 // No SYMTAB -- Bail out early.
374 if (!SymTabSec)
375 return Error::success();
376
377 // Get the section content as a Symbols array.
378 auto Symbols = Obj.symbols(SymTabSec);
379 if (!Symbols)
380 return Symbols.takeError();
381
382 // Get the string table for this section.
383 auto StringTab = Obj.getStringTableForSymtab(*SymTabSec, Sections);
384 if (!StringTab)
385 return StringTab.takeError();
386
387 LLVM_DEBUG({
388 StringRef SymTabName;
389
390 if (auto SymTabNameOrErr = Obj.getSectionName(*SymTabSec, SectionStringTab))
391 SymTabName = *SymTabNameOrErr;
392 else {
393 dbgs() << "Could not get ELF SHT_SYMTAB section name for logging: "
394 << toString(SymTabNameOrErr.takeError()) << "\n";
395 SymTabName = "<SHT_SYMTAB section with invalid name>";
396 }
397
398 dbgs() << " Adding symbols from symtab section \"" << SymTabName
399 << "\"\n";
400 });
401
402 for (ELFSymbolIndex SymIndex = 0; SymIndex != Symbols->size(); ++SymIndex) {
403 auto &Sym = (*Symbols)[SymIndex];
404
405 // Check symbol type.
406 switch (Sym.getType()) {
407 case ELF::STT_FILE:
408 LLVM_DEBUG({
409 if (auto Name = Sym.getName(*StringTab))
410 dbgs() << " " << SymIndex << ": Skipping STT_FILE symbol \""
411 << *Name << "\"\n";
412 else {
413 dbgs() << "Could not get STT_FILE symbol name: "
414 << toString(Name.takeError()) << "\n";
415 dbgs() << " " << SymIndex
416 << ": Skipping STT_FILE symbol with invalid name\n";
417 }
418 });
419 continue;
420 break;
421 }
422
423 // Get the symbol name.
424 auto Name = Sym.getName(*StringTab);
425 if (!Name)
426 return Name.takeError();
427
428 // Handle common symbols specially.
429 if (Sym.isCommon()) {
430 Symbol &GSym = G->addDefinedSymbol(
431 G->createZeroFillBlock(getCommonSection(), Sym.st_size,
432 orc::ExecutorAddr(), Sym.getValue(), 0),
433 0, *Name, Sym.st_size, Linkage::Strong, Scope::Default, false, false);
434 setGraphSymbol(SymIndex, GSym);
435 continue;
436 }
437
438 if (Sym.isDefined() &&
439 (Sym.getType() == ELF::STT_NOTYPE || Sym.getType() == ELF::STT_FUNC ||
440 Sym.getType() == ELF::STT_OBJECT ||
441 Sym.getType() == ELF::STT_SECTION || Sym.getType() == ELF::STT_TLS)) {
442
443 // Map Visibility and Binding to Scope and Linkage:
444 Linkage L;
445 Scope S;
446 if (auto LSOrErr = getSymbolLinkageAndScope(Sym, *Name))
447 std::tie(L, S) = *LSOrErr;
448 else
449 return LSOrErr.takeError();
450
451 // Handle extended tables.
452 unsigned Shndx = Sym.st_shndx;
453 if (Shndx == ELF::SHN_XINDEX) {
454 auto ShndxTable = ShndxTables.find(SymTabSec);
455 if (ShndxTable == ShndxTables.end())
456 continue;
457 auto NdxOrErr = object::getExtendedSymbolTableIndex<ELFT>(
458 Sym, SymIndex, ShndxTable->second);
459 if (!NdxOrErr)
460 return NdxOrErr.takeError();
461 Shndx = *NdxOrErr;
462 }
463 if (auto *B = getGraphBlock(Shndx)) {
464 LLVM_DEBUG({
465 dbgs() << " " << SymIndex
466 << ": Creating defined graph symbol for ELF symbol \"" << *Name
467 << "\"\n";
468 });
469
470 // In RISCV, temporary symbols (Used to generate dwarf, eh_frame
471 // sections...) will appear in object code's symbol table, and LLVM does
472 // not use names on these temporary symbols (RISCV gnu toolchain uses
473 // names on these temporary symbols). If the symbol is unnamed, add an
474 // anonymous symbol.
475 auto &GSym =
476 Name->empty()
477 ? G->addAnonymousSymbol(*B, Sym.getValue(), Sym.st_size,
478 false, false)
479 : G->addDefinedSymbol(*B, Sym.getValue(), *Name, Sym.st_size, L,
480 S, Sym.getType() == ELF::STT_FUNC, false);
481 setGraphSymbol(SymIndex, GSym);
482 }
483 } else if (Sym.isUndefined() && Sym.isExternal()) {
484 LLVM_DEBUG({
485 dbgs() << " " << SymIndex
486 << ": Creating external graph symbol for ELF symbol \"" << *Name
487 << "\"\n";
488 });
489
490 if (Sym.getBinding() != ELF::STB_GLOBAL &&
491 Sym.getBinding() != ELF::STB_WEAK)
492 return make_error<StringError>(
493 "Invalid symbol binding " +
494 Twine(static_cast<int>(Sym.getBinding())) +
495 " for external symbol " + *Name,
497
498 // If L is Linkage::Weak that means this is a weakly referenced symbol.
499 auto &GSym = G->addExternalSymbol(*Name, Sym.st_size,
500 Sym.getBinding() == ELF::STB_WEAK);
501 setGraphSymbol(SymIndex, GSym);
502 } else {
503 LLVM_DEBUG({
504 dbgs() << " " << SymIndex
505 << ": Not creating graph symbol for ELF symbol \"" << *Name
506 << "\" with unrecognized type\n";
507 });
508 }
509 }
510
511 return Error::success();
512}
513
514template <typename ELFT>
515template <typename RelocHandlerFunction>
517 const typename ELFT::Shdr &RelSect, RelocHandlerFunction &&Func,
518 bool ProcessDebugSections) {
519 // Only look into sections that store relocation entries.
520 if (RelSect.sh_type != ELF::SHT_RELA)
521 return Error::success();
522
523 // sh_info contains the section header index of the target (FixupSection),
524 // which is the section to which all relocations in RelSect apply.
525 auto FixupSection = Obj.getSection(RelSect.sh_info);
526 if (!FixupSection)
527 return FixupSection.takeError();
528
529 // Target sections have names in valid ELF object files.
530 Expected<StringRef> Name = Obj.getSectionName(**FixupSection);
531 if (!Name)
532 return Name.takeError();
533 LLVM_DEBUG(dbgs() << " " << *Name << ":\n");
534
535 // Consider skipping these relocations.
536 if (!ProcessDebugSections && isDwarfSection(*Name)) {
537 LLVM_DEBUG(dbgs() << " skipped (dwarf section)\n\n");
538 return Error::success();
539 }
540
541 // Lookup the link-graph node corresponding to the target section name.
542 auto *BlockToFix = getGraphBlock(RelSect.sh_info);
543 if (!BlockToFix)
544 return make_error<StringError>(
545 "Refencing a section that wasn't added to the graph: " + *Name,
547
548 auto RelEntries = Obj.relas(RelSect);
549 if (!RelEntries)
550 return RelEntries.takeError();
551
552 // Let the callee process relocation entries one by one.
553 for (const typename ELFT::Rela &R : *RelEntries)
554 if (Error Err = Func(R, **FixupSection, *BlockToFix))
555 return Err;
556
557 LLVM_DEBUG(dbgs() << "\n");
558 return Error::success();
559}
560
561template <typename ELFT>
562template <typename RelocHandlerFunction>
564 const typename ELFT::Shdr &RelSect, RelocHandlerFunction &&Func,
565 bool ProcessDebugSections) {
566 // Only look into sections that store relocation entries.
567 if (RelSect.sh_type != ELF::SHT_REL)
568 return Error::success();
569
570 // sh_info contains the section header index of the target (FixupSection),
571 // which is the section to which all relocations in RelSect apply.
572 auto FixupSection = Obj.getSection(RelSect.sh_info);
573 if (!FixupSection)
574 return FixupSection.takeError();
575
576 // Target sections have names in valid ELF object files.
577 Expected<StringRef> Name = Obj.getSectionName(**FixupSection);
578 if (!Name)
579 return Name.takeError();
580 LLVM_DEBUG(dbgs() << " " << *Name << ":\n");
581
582 // Consider skipping these relocations.
583 if (!ProcessDebugSections && isDwarfSection(*Name)) {
584 LLVM_DEBUG(dbgs() << " skipped (dwarf section)\n\n");
585 return Error::success();
586 }
587
588 // Lookup the link-graph node corresponding to the target section name.
589 auto *BlockToFix = getGraphBlock(RelSect.sh_info);
590 if (!BlockToFix)
591 return make_error<StringError>(
592 "Refencing a section that wasn't added to the graph: " + *Name,
594
595 auto RelEntries = Obj.rels(RelSect);
596 if (!RelEntries)
597 return RelEntries.takeError();
598
599 // Let the callee process relocation entries one by one.
600 for (const typename ELFT::Rel &R : *RelEntries)
601 if (Error Err = Func(R, **FixupSection, *BlockToFix))
602 return Err;
603
604 LLVM_DEBUG(dbgs() << "\n");
605 return Error::success();
606}
607
608} // end namespace jitlink
609} // end namespace llvm
610
611#undef DEBUG_TYPE
612
613#endif // LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_DEBUG(X)
Definition: Debug.h:101
std::string Name
#define I(x, y, z)
Definition: MD5.cpp:58
#define G(x, y, z)
Definition: MD5.cpp:56
static bool isDwarfSection(const MCObjectFileInfo *FI, const MCSection *Section)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
static ErrorSuccess success()
Create a success value.
Definition: Error.h:330
Tagged union holding either a T or a Error.
Definition: Error.h:470
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
const Elf_Ehdr & getHeader() const
Definition: ELF.h:191
Represents an address in the executor process.
uint64_t getValue() const
@ SHF_ALLOC
Definition: ELF.h:1083
@ SHF_EXECINSTR
Definition: ELF.h:1086
@ STV_INTERNAL
Definition: ELF.h:1267
@ STV_HIDDEN
Definition: ELF.h:1268
@ STV_PROTECTED
Definition: ELF.h:1269
@ STV_DEFAULT
Definition: ELF.h:1266
@ SHN_XINDEX
Definition: ELF.h:988
@ SHT_REL
Definition: ELF.h:1003
@ SHT_NOBITS
Definition: ELF.h:1002
@ SHT_SYMTAB
Definition: ELF.h:996
@ SHT_SYMTAB_SHNDX
Definition: ELF.h:1010
@ SHT_RELA
Definition: ELF.h:998
@ STB_GLOBAL
Definition: ELF.h:1237
@ STB_LOCAL
Definition: ELF.h:1236
@ STB_GNU_UNIQUE
Definition: ELF.h:1239
@ STB_WEAK
Definition: ELF.h:1238
@ ET_REL
Definition: ELF.h:116
@ STT_FUNC
Definition: ELF.h:1250
@ STT_NOTYPE
Definition: ELF.h:1248
@ STT_SECTION
Definition: ELF.h:1251
@ STT_FILE
Definition: ELF.h:1252
@ STT_OBJECT
Definition: ELF.h:1249
@ STT_TLS
Definition: ELF.h:1254
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
MemProt
Describes Read/Write/Exec permissions for memory.
Definition: MemoryFlags.h:27
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:79
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1862
bool is_contained(R &&Range, const E &Element)
Wrapper function around std::find to detect if an element exists in a container.
Definition: STLExtras.h:1869
Definition: BitVector.h:851