LLVM 20.0.0git
MachOLinkGraphBuilder.cpp
Go to the documentation of this file.
1//=--------- MachOLinkGraphBuilder.cpp - MachO LinkGraph builder ----------===//
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 MachO LinkGraph building code.
10//
11//===----------------------------------------------------------------------===//
12
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/ADT/Sequence.h"
16#include <optional>
17
18#define DEBUG_TYPE "jitlink"
19
20static const char *CommonSectionName = "__common";
21
22namespace llvm {
23namespace jitlink {
24
26
28
29 // We only operate on relocatable objects.
30 if (!Obj.isRelocatableObject())
31 return make_error<JITLinkError>("Object is not a relocatable MachO");
32
33 if (auto Err = createNormalizedSections())
34 return std::move(Err);
35
36 if (auto Err = createNormalizedSymbols())
37 return std::move(Err);
38
39 if (auto Err = graphifyRegularSymbols())
40 return std::move(Err);
41
42 if (auto Err = graphifySectionsWithCustomParsers())
43 return std::move(Err);
44
45 if (auto Err = addRelocations())
46 return std::move(Err);
47
48 return std::move(G);
49}
50
52 const object::MachOObjectFile &Obj,
53 std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
54 SubtargetFeatures Features,
56 : Obj(Obj),
57 G(std::make_unique<LinkGraph>(
58 std::string(Obj.getFileName()), std::move(SSP), std::move(TT),
59 std::move(Features), std::move(GetEdgeKindName))) {
60 auto &MachHeader = Obj.getHeader64();
61 SubsectionsViaSymbols = MachHeader.flags & MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
62}
63
66 assert(!CustomSectionParserFunctions.count(SectionName) &&
67 "Custom parser for this section already exists");
68 CustomSectionParserFunctions[SectionName] = std::move(Parser);
69}
70
73 return Linkage::Weak;
74 return Linkage::Strong;
75}
76
78 if (Type & MachO::N_EXT) {
79 if ((Type & MachO::N_PEXT) || Name.starts_with("l"))
80 return Scope::Hidden;
81 else
82 return Scope::Default;
83 }
84 return Scope::Local;
85}
86
88 return NSym.Desc & MachO::N_ALT_ENTRY;
89}
90
92 return (NSec.Flags & MachO::S_ATTR_DEBUG &&
93 strcmp(NSec.SegName, "__DWARF") == 0);
94}
95
97 switch (NSec.Flags & MachO::SECTION_TYPE) {
101 return true;
102 default:
103 return false;
104 }
105}
106
107Section &MachOLinkGraphBuilder::getCommonSection() {
108 if (!CommonSection)
109 CommonSection = &G->createSection(CommonSectionName,
111 return *CommonSection;
112}
113
114Error MachOLinkGraphBuilder::createNormalizedSections() {
115 // Build normalized sections. Verifies that section data is in-range (for
116 // sections with content) and that address ranges are non-overlapping.
117
118 LLVM_DEBUG(dbgs() << "Creating normalized sections...\n");
119
120 for (auto &SecRef : Obj.sections()) {
121 NormalizedSection NSec;
122 uint32_t DataOffset = 0;
123
124 auto SecIndex = Obj.getSectionIndex(SecRef.getRawDataRefImpl());
125
126 if (Obj.is64Bit()) {
127 const MachO::section_64 &Sec64 =
128 Obj.getSection64(SecRef.getRawDataRefImpl());
129
130 memcpy(&NSec.SectName, &Sec64.sectname, 16);
131 NSec.SectName[16] = '\0';
132 memcpy(&NSec.SegName, Sec64.segname, 16);
133 NSec.SegName[16] = '\0';
134
135 NSec.Address = orc::ExecutorAddr(Sec64.addr);
136 NSec.Size = Sec64.size;
137 NSec.Alignment = 1ULL << Sec64.align;
138 NSec.Flags = Sec64.flags;
139 DataOffset = Sec64.offset;
140 } else {
141 const MachO::section &Sec32 = Obj.getSection(SecRef.getRawDataRefImpl());
142
143 memcpy(&NSec.SectName, &Sec32.sectname, 16);
144 NSec.SectName[16] = '\0';
145 memcpy(&NSec.SegName, Sec32.segname, 16);
146 NSec.SegName[16] = '\0';
147
148 NSec.Address = orc::ExecutorAddr(Sec32.addr);
149 NSec.Size = Sec32.size;
150 NSec.Alignment = 1ULL << Sec32.align;
151 NSec.Flags = Sec32.flags;
152 DataOffset = Sec32.offset;
153 }
154
155 LLVM_DEBUG({
156 dbgs() << " " << NSec.SegName << "," << NSec.SectName << ": "
157 << formatv("{0:x16}", NSec.Address) << " -- "
158 << formatv("{0:x16}", NSec.Address + NSec.Size)
159 << ", align: " << NSec.Alignment << ", index: " << SecIndex
160 << "\n";
161 });
162
163 // Get the section data if any.
164 if (!isZeroFillSection(NSec)) {
165 if (DataOffset + NSec.Size > Obj.getData().size())
166 return make_error<JITLinkError>(
167 "Section data extends past end of file");
168
169 NSec.Data = Obj.getData().data() + DataOffset;
170 }
171
172 // Get prot flags.
173 // FIXME: Make sure this test is correct (it's probably missing cases
174 // as-is).
175 orc::MemProt Prot;
176 if (NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS)
178 else
180
181 auto FullyQualifiedName =
182 G->allocateContent(StringRef(NSec.SegName) + "," + NSec.SectName);
183 NSec.GraphSection = &G->createSection(
184 StringRef(FullyQualifiedName.data(), FullyQualifiedName.size()), Prot);
185
186 // TODO: Are there any other criteria for NoAlloc lifetime?
187 if (NSec.Flags & MachO::S_ATTR_DEBUG)
188 NSec.GraphSection->setMemLifetime(orc::MemLifetime::NoAlloc);
189
190 IndexToSection.insert(std::make_pair(SecIndex, std::move(NSec)));
191 }
192
193 std::vector<NormalizedSection *> Sections;
194 Sections.reserve(IndexToSection.size());
195 for (auto &KV : IndexToSection)
196 Sections.push_back(&KV.second);
197
198 // If we didn't end up creating any sections then bail out. The code below
199 // assumes that we have at least one section.
200 if (Sections.empty())
201 return Error::success();
202
203 llvm::sort(Sections,
204 [](const NormalizedSection *LHS, const NormalizedSection *RHS) {
205 assert(LHS && RHS && "Null section?");
206 if (LHS->Address != RHS->Address)
207 return LHS->Address < RHS->Address;
208 return LHS->Size < RHS->Size;
209 });
210
211 for (unsigned I = 0, E = Sections.size() - 1; I != E; ++I) {
212 auto &Cur = *Sections[I];
213 auto &Next = *Sections[I + 1];
214 if (Next.Address < Cur.Address + Cur.Size)
215 return make_error<JITLinkError>(
216 "Address range for section " +
217 formatv("\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Cur.SegName,
218 Cur.SectName, Cur.Address, Cur.Address + Cur.Size) +
219 "overlaps section \"" + Next.SegName + "/" + Next.SectName + "\"" +
220 formatv("\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Next.SegName,
221 Next.SectName, Next.Address, Next.Address + Next.Size));
222 }
223
224 return Error::success();
225}
226
227Error MachOLinkGraphBuilder::createNormalizedSymbols() {
228 LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n");
229
230 for (auto &SymRef : Obj.symbols()) {
231
232 unsigned SymbolIndex = Obj.getSymbolIndex(SymRef.getRawDataRefImpl());
234 uint32_t NStrX;
236 uint8_t Sect;
238
239 if (Obj.is64Bit()) {
240 const MachO::nlist_64 &NL64 =
241 Obj.getSymbol64TableEntry(SymRef.getRawDataRefImpl());
242 Value = NL64.n_value;
243 NStrX = NL64.n_strx;
244 Type = NL64.n_type;
245 Sect = NL64.n_sect;
246 Desc = NL64.n_desc;
247 } else {
248 const MachO::nlist &NL32 =
249 Obj.getSymbolTableEntry(SymRef.getRawDataRefImpl());
250 Value = NL32.n_value;
251 NStrX = NL32.n_strx;
252 Type = NL32.n_type;
253 Sect = NL32.n_sect;
254 Desc = NL32.n_desc;
255 }
256
257 // Skip stabs.
258 // FIXME: Are there other symbols we should be skipping?
259 if (Type & MachO::N_STAB)
260 continue;
261
262 std::optional<StringRef> Name;
263 if (NStrX) {
264 if (auto NameOrErr = SymRef.getName())
265 Name = *NameOrErr;
266 else
267 return NameOrErr.takeError();
268 } else if (Type & MachO::N_EXT)
269 return make_error<JITLinkError>("Symbol at index " +
270 formatv("{0}", SymbolIndex) +
271 " has no name (string table index 0), "
272 "but N_EXT bit is set");
273
274 LLVM_DEBUG({
275 dbgs() << " ";
276 if (!Name)
277 dbgs() << "<anonymous symbol>";
278 else
279 dbgs() << *Name;
280 dbgs() << ": value = " << formatv("{0:x16}", Value)
281 << ", type = " << formatv("{0:x2}", Type)
282 << ", desc = " << formatv("{0:x4}", Desc) << ", sect = ";
283 if (Sect)
284 dbgs() << static_cast<unsigned>(Sect - 1);
285 else
286 dbgs() << "none";
287 dbgs() << "\n";
288 });
289
290 // If this symbol has a section, verify that the addresses line up.
291 if (Sect != 0) {
292 auto NSec = findSectionByIndex(Sect - 1);
293 if (!NSec)
294 return NSec.takeError();
295
296 if (orc::ExecutorAddr(Value) < NSec->Address ||
297 orc::ExecutorAddr(Value) > NSec->Address + NSec->Size)
298 return make_error<JITLinkError>("Address " + formatv("{0:x}", Value) +
299 " for symbol " + *Name +
300 " does not fall within section");
301
302 if (!NSec->GraphSection) {
303 LLVM_DEBUG({
304 dbgs() << " Skipping: Symbol is in section " << NSec->SegName << "/"
305 << NSec->SectName
306 << " which has no associated graph section.\n";
307 });
308 continue;
309 }
310 }
311
312 IndexToSymbol[SymbolIndex] = &createNormalizedSymbol(
313 Name, Value, Type, Sect, Desc, getLinkage(Desc), getScope(*Name, Type));
314 }
315
316 return Error::success();
317}
318
319void MachOLinkGraphBuilder::addSectionStartSymAndBlock(
320 unsigned SecIndex, Section &GraphSec, orc::ExecutorAddr Address,
321 const char *Data, orc::ExecutorAddrDiff Size, uint32_t Alignment,
322 bool IsLive) {
323 Block &B =
324 Data ? G->createContentBlock(GraphSec, ArrayRef<char>(Data, Size),
325 Address, Alignment, 0)
326 : G->createZeroFillBlock(GraphSec, Size, Address, Alignment, 0);
327 auto &Sym = G->addAnonymousSymbol(B, 0, Size, false, IsLive);
328 auto SecI = IndexToSection.find(SecIndex);
329 assert(SecI != IndexToSection.end() && "SecIndex invalid");
330 auto &NSec = SecI->second;
331 assert(!NSec.CanonicalSymbols.count(Sym.getAddress()) &&
332 "Anonymous block start symbol clashes with existing symbol address");
333 NSec.CanonicalSymbols[Sym.getAddress()] = &Sym;
334}
335
336Error MachOLinkGraphBuilder::graphifyRegularSymbols() {
337
338 LLVM_DEBUG(dbgs() << "Creating graph symbols...\n");
339
340 /// We only have 256 section indexes: Use a vector rather than a map.
341 std::vector<std::vector<NormalizedSymbol *>> SecIndexToSymbols;
342 SecIndexToSymbols.resize(256);
343
344 // Create commons, externs, and absolutes, and partition all other symbols by
345 // section.
346 for (auto &KV : IndexToSymbol) {
347 auto &NSym = *KV.second;
348
349 switch (NSym.Type & MachO::N_TYPE) {
350 case MachO::N_UNDF:
351 if (NSym.Value) {
352 if (!NSym.Name)
353 return make_error<JITLinkError>("Anonymous common symbol at index " +
354 Twine(KV.first));
355 NSym.GraphSymbol = &G->addDefinedSymbol(
356 G->createZeroFillBlock(getCommonSection(),
357 orc::ExecutorAddrDiff(NSym.Value),
358 orc::ExecutorAddr(),
359 1ull << MachO::GET_COMM_ALIGN(NSym.Desc), 0),
360 0, *NSym.Name, orc::ExecutorAddrDiff(NSym.Value), Linkage::Weak,
361 NSym.S, false, NSym.Desc & MachO::N_NO_DEAD_STRIP);
362 } else {
363 if (!NSym.Name)
364 return make_error<JITLinkError>("Anonymous external symbol at "
365 "index " +
366 Twine(KV.first));
367 NSym.GraphSymbol = &G->addExternalSymbol(
368 *NSym.Name, 0, (NSym.Desc & MachO::N_WEAK_REF) != 0);
369 }
370 break;
371 case MachO::N_ABS:
372 if (!NSym.Name)
373 return make_error<JITLinkError>("Anonymous absolute symbol at index " +
374 Twine(KV.first));
375 NSym.GraphSymbol = &G->addAbsoluteSymbol(
376 *NSym.Name, orc::ExecutorAddr(NSym.Value), 0, Linkage::Strong,
377 getScope(*NSym.Name, NSym.Type), NSym.Desc & MachO::N_NO_DEAD_STRIP);
378 break;
379 case MachO::N_SECT:
380 SecIndexToSymbols[NSym.Sect - 1].push_back(&NSym);
381 break;
382 case MachO::N_PBUD:
383 return make_error<JITLinkError>(
384 "Unupported N_PBUD symbol " +
385 (NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) +
386 " at index " + Twine(KV.first));
387 case MachO::N_INDR:
388 return make_error<JITLinkError>(
389 "Unupported N_INDR symbol " +
390 (NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) +
391 " at index " + Twine(KV.first));
392 default:
393 return make_error<JITLinkError>(
394 "Unrecognized symbol type " + Twine(NSym.Type & MachO::N_TYPE) +
395 " for symbol " +
396 (NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) +
397 " at index " + Twine(KV.first));
398 }
399 }
400
401 // Loop over sections performing regular graphification for those that
402 // don't have custom parsers.
403 for (auto &KV : IndexToSection) {
404 auto SecIndex = KV.first;
405 auto &NSec = KV.second;
406
407 if (!NSec.GraphSection) {
408 LLVM_DEBUG({
409 dbgs() << " " << NSec.SegName << "/" << NSec.SectName
410 << " has no graph section. Skipping.\n";
411 });
412 continue;
413 }
414
415 // Skip sections with custom parsers.
416 if (CustomSectionParserFunctions.count(NSec.GraphSection->getName())) {
417 LLVM_DEBUG({
418 dbgs() << " Skipping section " << NSec.GraphSection->getName()
419 << " as it has a custom parser.\n";
420 });
421 continue;
422 } else if ((NSec.Flags & MachO::SECTION_TYPE) ==
424 if (auto Err = graphifyCStringSection(
425 NSec, std::move(SecIndexToSymbols[SecIndex])))
426 return Err;
427 continue;
428 } else
429 LLVM_DEBUG({
430 dbgs() << " Graphifying regular section "
431 << NSec.GraphSection->getName() << "...\n";
432 });
433
434 bool SectionIsNoDeadStrip = NSec.Flags & MachO::S_ATTR_NO_DEAD_STRIP;
435 bool SectionIsText = NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS;
436
437 auto &SecNSymStack = SecIndexToSymbols[SecIndex];
438
439 // If this section is non-empty but there are no symbols covering it then
440 // create one block and anonymous symbol to cover the entire section.
441 if (SecNSymStack.empty()) {
442 if (NSec.Size > 0) {
443 LLVM_DEBUG({
444 dbgs() << " Section non-empty, but contains no symbols. "
445 "Creating anonymous block to cover "
446 << formatv("{0:x16}", NSec.Address) << " -- "
447 << formatv("{0:x16}", NSec.Address + NSec.Size) << "\n";
448 });
449 addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address,
450 NSec.Data, NSec.Size, NSec.Alignment,
451 SectionIsNoDeadStrip);
452 } else
453 LLVM_DEBUG({
454 dbgs() << " Section empty and contains no symbols. Skipping.\n";
455 });
456 continue;
457 }
458
459 // Sort the symbol stack in by address, alt-entry status, scope, and name.
460 // We sort in reverse order so that symbols will be visited in the right
461 // order when we pop off the stack below.
462 llvm::sort(SecNSymStack, [](const NormalizedSymbol *LHS,
463 const NormalizedSymbol *RHS) {
464 if (LHS->Value != RHS->Value)
465 return LHS->Value > RHS->Value;
467 return isAltEntry(*RHS);
468 if (LHS->S != RHS->S)
469 return static_cast<uint8_t>(LHS->S) < static_cast<uint8_t>(RHS->S);
470 return LHS->Name < RHS->Name;
471 });
472
473 // The first symbol in a section can not be an alt-entry symbol.
474 if (!SecNSymStack.empty() && isAltEntry(*SecNSymStack.back()))
475 return make_error<JITLinkError>(
476 "First symbol in " + NSec.GraphSection->getName() + " is alt-entry");
477
478 // If the section is non-empty but there is no symbol covering the start
479 // address then add an anonymous one.
480 if (orc::ExecutorAddr(SecNSymStack.back()->Value) != NSec.Address) {
481 auto AnonBlockSize =
482 orc::ExecutorAddr(SecNSymStack.back()->Value) - NSec.Address;
483 LLVM_DEBUG({
484 dbgs() << " Section start not covered by symbol. "
485 << "Creating anonymous block to cover [ " << NSec.Address
486 << " -- " << (NSec.Address + AnonBlockSize) << " ]\n";
487 });
488 addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address,
489 NSec.Data, AnonBlockSize, NSec.Alignment,
490 SectionIsNoDeadStrip);
491 }
492
493 // Visit section symbols in order by popping off the reverse-sorted stack,
494 // building graph symbols as we go.
495 //
496 // If MH_SUBSECTIONS_VIA_SYMBOLS is set we'll build a block for each
497 // alt-entry chain.
498 //
499 // If MH_SUBSECTIONS_VIA_SYMBOLS is not set then we'll just build one block
500 // for the whole section.
501 while (!SecNSymStack.empty()) {
502 SmallVector<NormalizedSymbol *, 8> BlockSyms;
503
504 // Get the symbols in this alt-entry chain, or the whole section (if
505 // !SubsectionsViaSymbols).
506 BlockSyms.push_back(SecNSymStack.back());
507 SecNSymStack.pop_back();
508 while (!SecNSymStack.empty() &&
509 (isAltEntry(*SecNSymStack.back()) ||
510 SecNSymStack.back()->Value == BlockSyms.back()->Value ||
511 !SubsectionsViaSymbols)) {
512 BlockSyms.push_back(SecNSymStack.back());
513 SecNSymStack.pop_back();
514 }
515
516 // BlockNSyms now contains the block symbols in reverse canonical order.
517 auto BlockStart = orc::ExecutorAddr(BlockSyms.front()->Value);
518 orc::ExecutorAddr BlockEnd =
519 SecNSymStack.empty() ? NSec.Address + NSec.Size
520 : orc::ExecutorAddr(SecNSymStack.back()->Value);
521 orc::ExecutorAddrDiff BlockOffset = BlockStart - NSec.Address;
522 orc::ExecutorAddrDiff BlockSize = BlockEnd - BlockStart;
523
524 LLVM_DEBUG({
525 dbgs() << " Creating block for " << formatv("{0:x16}", BlockStart)
526 << " -- " << formatv("{0:x16}", BlockEnd) << ": "
527 << NSec.GraphSection->getName() << " + "
528 << formatv("{0:x16}", BlockOffset) << " with "
529 << BlockSyms.size() << " symbol(s)...\n";
530 });
531
532 Block &B =
533 NSec.Data
534 ? G->createContentBlock(
535 *NSec.GraphSection,
536 ArrayRef<char>(NSec.Data + BlockOffset, BlockSize),
537 BlockStart, NSec.Alignment, BlockStart % NSec.Alignment)
538 : G->createZeroFillBlock(*NSec.GraphSection, BlockSize,
539 BlockStart, NSec.Alignment,
540 BlockStart % NSec.Alignment);
541
542 std::optional<orc::ExecutorAddr> LastCanonicalAddr;
543 auto SymEnd = BlockEnd;
544 while (!BlockSyms.empty()) {
545 auto &NSym = *BlockSyms.back();
546 BlockSyms.pop_back();
547
548 bool SymLive =
549 (NSym.Desc & MachO::N_NO_DEAD_STRIP) || SectionIsNoDeadStrip;
550
551 auto &Sym = createStandardGraphSymbol(
552 NSym, B, SymEnd - orc::ExecutorAddr(NSym.Value), SectionIsText,
553 SymLive, LastCanonicalAddr != orc::ExecutorAddr(NSym.Value));
554
555 if (LastCanonicalAddr != Sym.getAddress()) {
556 if (LastCanonicalAddr)
557 SymEnd = *LastCanonicalAddr;
558 LastCanonicalAddr = Sym.getAddress();
559 }
560 }
561 }
562 }
563
564 return Error::success();
565}
566
567Symbol &MachOLinkGraphBuilder::createStandardGraphSymbol(NormalizedSymbol &NSym,
568 Block &B, size_t Size,
569 bool IsText,
570 bool IsNoDeadStrip,
571 bool IsCanonical) {
572
573 LLVM_DEBUG({
574 dbgs() << " " << formatv("{0:x16}", NSym.Value) << " -- "
575 << formatv("{0:x16}", NSym.Value + Size) << ": ";
576 if (!NSym.Name)
577 dbgs() << "<anonymous symbol>";
578 else
579 dbgs() << *NSym.Name;
580 if (IsText)
581 dbgs() << " [text]";
582 if (IsNoDeadStrip)
583 dbgs() << " [no-dead-strip]";
584 if (!IsCanonical)
585 dbgs() << " [non-canonical]";
586 dbgs() << "\n";
587 });
588
589 auto SymOffset = orc::ExecutorAddr(NSym.Value) - B.getAddress();
590 auto &Sym =
591 NSym.Name
592 ? G->addDefinedSymbol(B, SymOffset, *NSym.Name, Size, NSym.L, NSym.S,
593 IsText, IsNoDeadStrip)
594 : G->addAnonymousSymbol(B, SymOffset, Size, IsText, IsNoDeadStrip);
595 NSym.GraphSymbol = &Sym;
596
597 if (IsCanonical)
598 setCanonicalSymbol(getSectionByIndex(NSym.Sect - 1), Sym);
599
600 return Sym;
601}
602
603Error MachOLinkGraphBuilder::graphifySectionsWithCustomParsers() {
604 // Graphify special sections.
605 for (auto &KV : IndexToSection) {
606 auto &NSec = KV.second;
607
608 // Skip non-graph sections.
609 if (!NSec.GraphSection)
610 continue;
611
612 auto HI = CustomSectionParserFunctions.find(NSec.GraphSection->getName());
613 if (HI != CustomSectionParserFunctions.end()) {
614 auto &Parse = HI->second;
615 if (auto Err = Parse(NSec))
616 return Err;
617 }
618 }
619
620 return Error::success();
621}
622
623Error MachOLinkGraphBuilder::graphifyCStringSection(
624 NormalizedSection &NSec, std::vector<NormalizedSymbol *> NSyms) {
625 assert(NSec.GraphSection && "C string literal section missing graph section");
626 assert(NSec.Data && "C string literal section has no data");
627
628 LLVM_DEBUG({
629 dbgs() << " Graphifying C-string literal section "
630 << NSec.GraphSection->getName() << "\n";
631 });
632
633 if (NSec.Data[NSec.Size - 1] != '\0')
634 return make_error<JITLinkError>("C string literal section " +
635 NSec.GraphSection->getName() +
636 " does not end with null terminator");
637
638 /// Sort into reverse order to use as a stack.
639 llvm::sort(NSyms,
640 [](const NormalizedSymbol *LHS, const NormalizedSymbol *RHS) {
641 if (LHS->Value != RHS->Value)
642 return LHS->Value > RHS->Value;
643 if (LHS->L != RHS->L)
644 return LHS->L > RHS->L;
645 if (LHS->S != RHS->S)
646 return LHS->S > RHS->S;
647 if (RHS->Name) {
648 if (!LHS->Name)
649 return true;
650 return *LHS->Name > *RHS->Name;
651 }
652 return false;
653 });
654
655 bool SectionIsNoDeadStrip = NSec.Flags & MachO::S_ATTR_NO_DEAD_STRIP;
656 bool SectionIsText = NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS;
657 orc::ExecutorAddrDiff BlockStart = 0;
658
659 // Scan section for null characters.
660 for (size_t I = 0; I != NSec.Size; ++I) {
661 if (NSec.Data[I] == '\0') {
662 size_t BlockSize = I + 1 - BlockStart;
663 // Create a block for this null terminated string.
664 auto &B = G->createContentBlock(*NSec.GraphSection,
665 {NSec.Data + BlockStart, BlockSize},
666 NSec.Address + BlockStart, NSec.Alignment,
667 BlockStart % NSec.Alignment);
668
669 LLVM_DEBUG({
670 dbgs() << " Created block " << B.getRange()
671 << ", align = " << B.getAlignment()
672 << ", align-ofs = " << B.getAlignmentOffset() << " for \"";
673 for (size_t J = 0; J != std::min(B.getSize(), size_t(16)); ++J)
674 switch (B.getContent()[J]) {
675 case '\0': break;
676 case '\n': dbgs() << "\\n"; break;
677 case '\t': dbgs() << "\\t"; break;
678 default: dbgs() << B.getContent()[J]; break;
679 }
680 if (B.getSize() > 16)
681 dbgs() << "...";
682 dbgs() << "\"\n";
683 });
684
685 // If there's no symbol at the start of this block then create one.
686 if (NSyms.empty() ||
687 orc::ExecutorAddr(NSyms.back()->Value) != B.getAddress()) {
688 auto &S = G->addAnonymousSymbol(B, 0, BlockSize, false, false);
689 setCanonicalSymbol(NSec, S);
690 LLVM_DEBUG({
691 dbgs() << " Adding symbol for c-string block " << B.getRange()
692 << ": <anonymous symbol> at offset 0\n";
693 });
694 }
695
696 // Process any remaining symbols that point into this block.
697 auto LastCanonicalAddr = B.getAddress() + BlockSize;
698 while (!NSyms.empty() && orc::ExecutorAddr(NSyms.back()->Value) <
699 B.getAddress() + BlockSize) {
700 auto &NSym = *NSyms.back();
701 size_t SymSize = (B.getAddress() + BlockSize) -
702 orc::ExecutorAddr(NSyms.back()->Value);
703 bool SymLive =
704 (NSym.Desc & MachO::N_NO_DEAD_STRIP) || SectionIsNoDeadStrip;
705
706 bool IsCanonical = false;
707 if (LastCanonicalAddr != orc::ExecutorAddr(NSym.Value)) {
708 IsCanonical = true;
709 LastCanonicalAddr = orc::ExecutorAddr(NSym.Value);
710 }
711
712 auto &Sym = createStandardGraphSymbol(NSym, B, SymSize, SectionIsText,
713 SymLive, IsCanonical);
714 (void)Sym;
715 LLVM_DEBUG({
716 dbgs() << " Adding symbol for c-string block " << B.getRange()
717 << ": "
718 << (Sym.hasName() ? *Sym.getName() : "<anonymous symbol>")
719 << " at offset " << formatv("{0:x}", Sym.getOffset()) << "\n";
720 });
721
722 NSyms.pop_back();
723 }
724
725 BlockStart += BlockSize;
726 }
727 }
728
729 assert(llvm::all_of(NSec.GraphSection->blocks(),
730 [](Block *B) { return isCStringBlock(*B); }) &&
731 "All blocks in section should hold single c-strings");
732
733 return Error::success();
734}
735
737 auto *CUSec = G.findSectionByName(CompactUnwindSectionName);
738 if (!CUSec)
739 return Error::success();
740
741 if (!G.getTargetTriple().isOSBinFormatMachO())
742 return make_error<JITLinkError>(
743 "Error linking " + G.getName() +
744 ": compact unwind splitting not supported on non-macho target " +
745 G.getTargetTriple().str());
746
747 unsigned CURecordSize = 0;
748 unsigned PersonalityEdgeOffset = 0;
749 unsigned LSDAEdgeOffset = 0;
750 switch (G.getTargetTriple().getArch()) {
751 case Triple::aarch64:
752 case Triple::x86_64:
753 // 64-bit compact-unwind record format:
754 // Range start: 8 bytes.
755 // Range size: 4 bytes.
756 // CU encoding: 4 bytes.
757 // Personality: 8 bytes.
758 // LSDA: 8 bytes.
759 CURecordSize = 32;
760 PersonalityEdgeOffset = 16;
761 LSDAEdgeOffset = 24;
762 break;
763 default:
764 return make_error<JITLinkError>(
765 "Error linking " + G.getName() +
766 ": compact unwind splitting not supported on " +
767 G.getTargetTriple().getArchName());
768 }
769
770 std::vector<Block *> OriginalBlocks(CUSec->blocks().begin(),
771 CUSec->blocks().end());
772 LLVM_DEBUG({
773 dbgs() << "In " << G.getName() << " splitting compact unwind section "
774 << CompactUnwindSectionName << " containing "
775 << OriginalBlocks.size() << " initial blocks...\n";
776 });
777
778 while (!OriginalBlocks.empty()) {
779 auto *B = OriginalBlocks.back();
780 OriginalBlocks.pop_back();
781
782 if (B->getSize() == 0) {
783 LLVM_DEBUG({
784 dbgs() << " Skipping empty block at "
785 << formatv("{0:x16}", B->getAddress()) << "\n";
786 });
787 continue;
788 }
789
790 unsigned NumBlocks = B->getSize() / CURecordSize;
791
792 LLVM_DEBUG({
793 dbgs() << " Splitting block at " << formatv("{0:x16}", B->getAddress())
794 << " into " << NumBlocks << " compact unwind record(s)\n";
795 });
796
797 if (B->getSize() % CURecordSize)
798 return make_error<JITLinkError>(
799 "Error splitting compact unwind record in " + G.getName() +
800 ": block at " + formatv("{0:x}", B->getAddress()) + " has size " +
801 formatv("{0:x}", B->getSize()) +
802 " (not a multiple of CU record size of " +
803 formatv("{0:x}", CURecordSize) + ")");
804
805 auto Blocks =
806 G.splitBlock(*B, map_range(seq(1U, NumBlocks), [=](Edge::OffsetT Idx) {
807 return Idx * CURecordSize;
808 }));
809
810 for (auto *CURec : Blocks) {
811 bool AddedKeepAlive = false;
812
813 for (auto &E : CURec->edges()) {
814 if (E.getOffset() == 0) {
815 LLVM_DEBUG({
816 dbgs() << " Updating compact unwind record at "
817 << CURec->getAddress() << " to point to "
818 << (E.getTarget().hasName() ? *E.getTarget().getName()
819 : StringRef())
820 << " (at " << E.getTarget().getAddress() << ")\n";
821 });
822
823 if (E.getTarget().isExternal())
824 return make_error<JITLinkError>(
825 "Error adding keep-alive edge for compact unwind record at " +
826 formatv("{0:x}", CURec->getAddress()) + ": target " +
827 *E.getTarget().getName() + " is an external symbol");
828 auto &TgtBlock = E.getTarget().getBlock();
829 auto &CURecSym =
830 G.addAnonymousSymbol(*CURec, 0, CURecordSize, false, false);
831 TgtBlock.addEdge(Edge::KeepAlive, 0, CURecSym, 0);
832 AddedKeepAlive = true;
833 } else if (E.getOffset() != PersonalityEdgeOffset &&
834 E.getOffset() != LSDAEdgeOffset)
835 return make_error<JITLinkError>(
836 "Unexpected edge at offset " + formatv("{0:x}", E.getOffset()) +
837 " in compact unwind record at " +
838 formatv("{0:x}", CURec->getAddress()));
839 }
840
841 if (!AddedKeepAlive)
842 return make_error<JITLinkError>(
843 "Error adding keep-alive edge for compact unwind record at " +
844 formatv("{0:x}", CURec->getAddress()) +
845 ": no outgoing target edge at offset 0");
846 }
847 }
848
849 return Error::success();
850}
851
852} // end namespace jitlink
853} // end namespace llvm
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static const char * CommonSectionName
static Expected< StringRef > getFileName(const DebugStringTableSubsectionRef &Strings, const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID)
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
#define LLVM_DEBUG(...)
Definition: Debug.h:106
std::string Name
uint64_t Size
DenseMap< Block *, BlockRelaxAux > Blocks
Definition: ELF_riscv.cpp:507
Symbol * Sym
Definition: ELF_riscv.cpp:479
#define I(x, y, z)
Definition: MD5.cpp:58
#define G(x, y, z)
Definition: MD5.cpp:56
static const char * CommonSectionName
if(PassOpts->AAPipeline)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
Provides some synthesis utilities to produce sequences of values.
static const int BlockSize
Definition: TarWriter.cpp:33
Value * RHS
Value * LHS
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Tagged union holding either a T or a Error.
Definition: Error.h:481
iterator end()
Definition: StringMap.h:220
iterator find(StringRef Key)
Definition: StringMap.h:233
size_type count(StringRef Key) const
count - Return 1 if the element is in the map, 0 otherwise.
Definition: StringMap.h:276
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:150
constexpr const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:144
Manages the enabling and disabling of subtarget specific features.
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
StringRef getData() const
Definition: Binary.cpp:39
const MachO::mach_header_64 & getHeader64() const
Expected< SectionRef > getSection(unsigned SectionIndex) const
uint64_t getSymbolIndex(DataRefImpl Symb) const
MachO::nlist getSymbolTableEntry(DataRefImpl DRI) const
MachO::section_64 getSection64(DataRefImpl DRI) const
bool isRelocatableObject() const override
True if this is a relocatable object (.o/.obj).
MachO::nlist_64 getSymbol64TableEntry(DataRefImpl DRI) const
uint64_t getSectionIndex(DataRefImpl Sec) const override
section_iterator_range sections() const
Definition: ObjectFile.h:329
symbol_iterator_range symbols() const
Definition: ObjectFile.h:321
Represents an address in the executor process.
@ SECTION_TYPE
Definition: MachO.h:114
@ S_ATTR_DEBUG
S_ATTR_DEBUG - A debug section.
Definition: MachO.h:207
@ S_ATTR_NO_DEAD_STRIP
S_ATTR_NO_DEAD_STRIP - No dead stripping.
Definition: MachO.h:200
@ S_ATTR_PURE_INSTRUCTIONS
S_ATTR_PURE_INSTRUCTIONS - Section contains only true machine instructions.
Definition: MachO.h:192
@ N_TYPE
Definition: MachO.h:309
@ N_PEXT
Definition: MachO.h:308
@ N_STAB
Definition: MachO.h:307
@ S_GB_ZEROFILL
S_GB_ZEROFILL - Zero fill on demand section (that can be larger than 4 gigabytes).
Definition: MachO.h:155
@ S_THREAD_LOCAL_ZEROFILL
S_THREAD_LOCAL_ZEROFILL - Thread local zerofill section.
Definition: MachO.h:169
@ S_CSTRING_LITERALS
S_CSTRING_LITERALS - Section with literal C strings.
Definition: MachO.h:131
@ S_ZEROFILL
S_ZEROFILL - Zero fill on demand section.
Definition: MachO.h:129
uint8_t GET_COMM_ALIGN(uint16_t n_desc)
Definition: MachO.h:1545
@ N_SECT
Definition: MachO.h:318
@ N_PBUD
Definition: MachO.h:319
@ N_INDR
Definition: MachO.h:320
@ N_UNDF
Definition: MachO.h:316
@ N_WEAK_DEF
Definition: MachO.h:346
@ N_NO_DEAD_STRIP
Definition: MachO.h:344
@ N_ALT_ENTRY
Definition: MachO.h:348
@ N_WEAK_REF
Definition: MachO.h:345
@ MH_SUBSECTIONS_VIA_SYMBOLS
Definition: MachO.h:73
Type
MessagePack types as defined in the standard, with the exception of Integer being divided into a sign...
Definition: MsgPackReader.h:53
MemProt
Describes Read/Write/Exec permissions for memory.
Definition: MemoryFlags.h:27
uint64_t ExecutorAddrDiff
@ NoAlloc
NoAlloc memory should not be allocated by the JITLinkMemoryManager at all.
NodeAddr< BlockNode * > Block
Definition: RDFGraph.h:392
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1739
Op::Description Desc
auto map_range(ContainerTy &&C, FuncTy F)
Definition: STLExtras.h:377
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1664
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:1873
auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition: Sequence.h:305
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
Description of the encoding of one expression Op.