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), G(std::make_unique<LinkGraph>(
57 std::string(Obj.getFileName()), std::move(SSP),
58 std::move(TT), std::move(Features), getPointerSize(Obj),
59 getEndianness(Obj), 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
107unsigned
108MachOLinkGraphBuilder::getPointerSize(const object::MachOObjectFile &Obj) {
109 return Obj.is64Bit() ? 8 : 4;
110}
111
113MachOLinkGraphBuilder::getEndianness(const object::MachOObjectFile &Obj) {
116}
117
118Section &MachOLinkGraphBuilder::getCommonSection() {
119 if (!CommonSection)
120 CommonSection = &G->createSection(CommonSectionName,
122 return *CommonSection;
123}
124
125Error MachOLinkGraphBuilder::createNormalizedSections() {
126 // Build normalized sections. Verifies that section data is in-range (for
127 // sections with content) and that address ranges are non-overlapping.
128
129 LLVM_DEBUG(dbgs() << "Creating normalized sections...\n");
130
131 for (auto &SecRef : Obj.sections()) {
132 NormalizedSection NSec;
133 uint32_t DataOffset = 0;
134
135 auto SecIndex = Obj.getSectionIndex(SecRef.getRawDataRefImpl());
136
137 if (Obj.is64Bit()) {
138 const MachO::section_64 &Sec64 =
139 Obj.getSection64(SecRef.getRawDataRefImpl());
140
141 memcpy(&NSec.SectName, &Sec64.sectname, 16);
142 NSec.SectName[16] = '\0';
143 memcpy(&NSec.SegName, Sec64.segname, 16);
144 NSec.SegName[16] = '\0';
145
146 NSec.Address = orc::ExecutorAddr(Sec64.addr);
147 NSec.Size = Sec64.size;
148 NSec.Alignment = 1ULL << Sec64.align;
149 NSec.Flags = Sec64.flags;
150 DataOffset = Sec64.offset;
151 } else {
152 const MachO::section &Sec32 = Obj.getSection(SecRef.getRawDataRefImpl());
153
154 memcpy(&NSec.SectName, &Sec32.sectname, 16);
155 NSec.SectName[16] = '\0';
156 memcpy(&NSec.SegName, Sec32.segname, 16);
157 NSec.SegName[16] = '\0';
158
159 NSec.Address = orc::ExecutorAddr(Sec32.addr);
160 NSec.Size = Sec32.size;
161 NSec.Alignment = 1ULL << Sec32.align;
162 NSec.Flags = Sec32.flags;
163 DataOffset = Sec32.offset;
164 }
165
166 LLVM_DEBUG({
167 dbgs() << " " << NSec.SegName << "," << NSec.SectName << ": "
168 << formatv("{0:x16}", NSec.Address) << " -- "
169 << formatv("{0:x16}", NSec.Address + NSec.Size)
170 << ", align: " << NSec.Alignment << ", index: " << SecIndex
171 << "\n";
172 });
173
174 // Get the section data if any.
175 if (!isZeroFillSection(NSec)) {
176 if (DataOffset + NSec.Size > Obj.getData().size())
177 return make_error<JITLinkError>(
178 "Section data extends past end of file");
179
180 NSec.Data = Obj.getData().data() + DataOffset;
181 }
182
183 // Get prot flags.
184 // FIXME: Make sure this test is correct (it's probably missing cases
185 // as-is).
186 orc::MemProt Prot;
187 if (NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS)
189 else
191
192 auto FullyQualifiedName =
193 G->allocateContent(StringRef(NSec.SegName) + "," + NSec.SectName);
194 NSec.GraphSection = &G->createSection(
195 StringRef(FullyQualifiedName.data(), FullyQualifiedName.size()), Prot);
196
197 // TODO: Are there any other criteria for NoAlloc lifetime?
198 if (NSec.Flags & MachO::S_ATTR_DEBUG)
199 NSec.GraphSection->setMemLifetime(orc::MemLifetime::NoAlloc);
200
201 IndexToSection.insert(std::make_pair(SecIndex, std::move(NSec)));
202 }
203
204 std::vector<NormalizedSection *> Sections;
205 Sections.reserve(IndexToSection.size());
206 for (auto &KV : IndexToSection)
207 Sections.push_back(&KV.second);
208
209 // If we didn't end up creating any sections then bail out. The code below
210 // assumes that we have at least one section.
211 if (Sections.empty())
212 return Error::success();
213
214 llvm::sort(Sections,
215 [](const NormalizedSection *LHS, const NormalizedSection *RHS) {
216 assert(LHS && RHS && "Null section?");
217 if (LHS->Address != RHS->Address)
218 return LHS->Address < RHS->Address;
219 return LHS->Size < RHS->Size;
220 });
221
222 for (unsigned I = 0, E = Sections.size() - 1; I != E; ++I) {
223 auto &Cur = *Sections[I];
224 auto &Next = *Sections[I + 1];
225 if (Next.Address < Cur.Address + Cur.Size)
226 return make_error<JITLinkError>(
227 "Address range for section " +
228 formatv("\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Cur.SegName,
229 Cur.SectName, Cur.Address, Cur.Address + Cur.Size) +
230 "overlaps section \"" + Next.SegName + "/" + Next.SectName + "\"" +
231 formatv("\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Next.SegName,
232 Next.SectName, Next.Address, Next.Address + Next.Size));
233 }
234
235 return Error::success();
236}
237
238Error MachOLinkGraphBuilder::createNormalizedSymbols() {
239 LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n");
240
241 for (auto &SymRef : Obj.symbols()) {
242
243 unsigned SymbolIndex = Obj.getSymbolIndex(SymRef.getRawDataRefImpl());
245 uint32_t NStrX;
247 uint8_t Sect;
249
250 if (Obj.is64Bit()) {
251 const MachO::nlist_64 &NL64 =
252 Obj.getSymbol64TableEntry(SymRef.getRawDataRefImpl());
253 Value = NL64.n_value;
254 NStrX = NL64.n_strx;
255 Type = NL64.n_type;
256 Sect = NL64.n_sect;
257 Desc = NL64.n_desc;
258 } else {
259 const MachO::nlist &NL32 =
260 Obj.getSymbolTableEntry(SymRef.getRawDataRefImpl());
261 Value = NL32.n_value;
262 NStrX = NL32.n_strx;
263 Type = NL32.n_type;
264 Sect = NL32.n_sect;
265 Desc = NL32.n_desc;
266 }
267
268 // Skip stabs.
269 // FIXME: Are there other symbols we should be skipping?
270 if (Type & MachO::N_STAB)
271 continue;
272
273 std::optional<StringRef> Name;
274 if (NStrX) {
275 if (auto NameOrErr = SymRef.getName())
276 Name = *NameOrErr;
277 else
278 return NameOrErr.takeError();
279 } else if (Type & MachO::N_EXT)
280 return make_error<JITLinkError>("Symbol at index " +
281 formatv("{0}", SymbolIndex) +
282 " has no name (string table index 0), "
283 "but N_EXT bit is set");
284
285 LLVM_DEBUG({
286 dbgs() << " ";
287 if (!Name)
288 dbgs() << "<anonymous symbol>";
289 else
290 dbgs() << *Name;
291 dbgs() << ": value = " << formatv("{0:x16}", Value)
292 << ", type = " << formatv("{0:x2}", Type)
293 << ", desc = " << formatv("{0:x4}", Desc) << ", sect = ";
294 if (Sect)
295 dbgs() << static_cast<unsigned>(Sect - 1);
296 else
297 dbgs() << "none";
298 dbgs() << "\n";
299 });
300
301 // If this symbol has a section, verify that the addresses line up.
302 if (Sect != 0) {
303 auto NSec = findSectionByIndex(Sect - 1);
304 if (!NSec)
305 return NSec.takeError();
306
307 if (orc::ExecutorAddr(Value) < NSec->Address ||
308 orc::ExecutorAddr(Value) > NSec->Address + NSec->Size)
309 return make_error<JITLinkError>("Address " + formatv("{0:x}", Value) +
310 " for symbol " + *Name +
311 " does not fall within section");
312
313 if (!NSec->GraphSection) {
314 LLVM_DEBUG({
315 dbgs() << " Skipping: Symbol is in section " << NSec->SegName << "/"
316 << NSec->SectName
317 << " which has no associated graph section.\n";
318 });
319 continue;
320 }
321 }
322
323 IndexToSymbol[SymbolIndex] = &createNormalizedSymbol(
324 Name, Value, Type, Sect, Desc, getLinkage(Desc), getScope(*Name, Type));
325 }
326
327 return Error::success();
328}
329
330void MachOLinkGraphBuilder::addSectionStartSymAndBlock(
331 unsigned SecIndex, Section &GraphSec, orc::ExecutorAddr Address,
332 const char *Data, orc::ExecutorAddrDiff Size, uint32_t Alignment,
333 bool IsLive) {
334 Block &B =
335 Data ? G->createContentBlock(GraphSec, ArrayRef<char>(Data, Size),
336 Address, Alignment, 0)
337 : G->createZeroFillBlock(GraphSec, Size, Address, Alignment, 0);
338 auto &Sym = G->addAnonymousSymbol(B, 0, Size, false, IsLive);
339 auto SecI = IndexToSection.find(SecIndex);
340 assert(SecI != IndexToSection.end() && "SecIndex invalid");
341 auto &NSec = SecI->second;
342 assert(!NSec.CanonicalSymbols.count(Sym.getAddress()) &&
343 "Anonymous block start symbol clashes with existing symbol address");
344 NSec.CanonicalSymbols[Sym.getAddress()] = &Sym;
345}
346
347Error MachOLinkGraphBuilder::graphifyRegularSymbols() {
348
349 LLVM_DEBUG(dbgs() << "Creating graph symbols...\n");
350
351 /// We only have 256 section indexes: Use a vector rather than a map.
352 std::vector<std::vector<NormalizedSymbol *>> SecIndexToSymbols;
353 SecIndexToSymbols.resize(256);
354
355 // Create commons, externs, and absolutes, and partition all other symbols by
356 // section.
357 for (auto &KV : IndexToSymbol) {
358 auto &NSym = *KV.second;
359
360 switch (NSym.Type & MachO::N_TYPE) {
361 case MachO::N_UNDF:
362 if (NSym.Value) {
363 if (!NSym.Name)
364 return make_error<JITLinkError>("Anonymous common symbol at index " +
365 Twine(KV.first));
366 NSym.GraphSymbol = &G->addDefinedSymbol(
367 G->createZeroFillBlock(getCommonSection(),
368 orc::ExecutorAddrDiff(NSym.Value),
369 orc::ExecutorAddr(),
370 1ull << MachO::GET_COMM_ALIGN(NSym.Desc), 0),
371 0, *NSym.Name, orc::ExecutorAddrDiff(NSym.Value), Linkage::Weak,
372 NSym.S, false, NSym.Desc & MachO::N_NO_DEAD_STRIP);
373 } else {
374 if (!NSym.Name)
375 return make_error<JITLinkError>("Anonymous external symbol at "
376 "index " +
377 Twine(KV.first));
378 NSym.GraphSymbol = &G->addExternalSymbol(
379 *NSym.Name, 0, (NSym.Desc & MachO::N_WEAK_REF) != 0);
380 }
381 break;
382 case MachO::N_ABS:
383 if (!NSym.Name)
384 return make_error<JITLinkError>("Anonymous absolute symbol at index " +
385 Twine(KV.first));
386 NSym.GraphSymbol = &G->addAbsoluteSymbol(
387 *NSym.Name, orc::ExecutorAddr(NSym.Value), 0, Linkage::Strong,
388 getScope(*NSym.Name, NSym.Type), NSym.Desc & MachO::N_NO_DEAD_STRIP);
389 break;
390 case MachO::N_SECT:
391 SecIndexToSymbols[NSym.Sect - 1].push_back(&NSym);
392 break;
393 case MachO::N_PBUD:
394 return make_error<JITLinkError>(
395 "Unupported N_PBUD symbol " +
396 (NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) +
397 " at index " + Twine(KV.first));
398 case MachO::N_INDR:
399 return make_error<JITLinkError>(
400 "Unupported N_INDR symbol " +
401 (NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) +
402 " at index " + Twine(KV.first));
403 default:
404 return make_error<JITLinkError>(
405 "Unrecognized symbol type " + Twine(NSym.Type & MachO::N_TYPE) +
406 " for symbol " +
407 (NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) +
408 " at index " + Twine(KV.first));
409 }
410 }
411
412 // Loop over sections performing regular graphification for those that
413 // don't have custom parsers.
414 for (auto &KV : IndexToSection) {
415 auto SecIndex = KV.first;
416 auto &NSec = KV.second;
417
418 if (!NSec.GraphSection) {
419 LLVM_DEBUG({
420 dbgs() << " " << NSec.SegName << "/" << NSec.SectName
421 << " has no graph section. Skipping.\n";
422 });
423 continue;
424 }
425
426 // Skip sections with custom parsers.
427 if (CustomSectionParserFunctions.count(NSec.GraphSection->getName())) {
428 LLVM_DEBUG({
429 dbgs() << " Skipping section " << NSec.GraphSection->getName()
430 << " as it has a custom parser.\n";
431 });
432 continue;
433 } else if ((NSec.Flags & MachO::SECTION_TYPE) ==
435 if (auto Err = graphifyCStringSection(
436 NSec, std::move(SecIndexToSymbols[SecIndex])))
437 return Err;
438 continue;
439 } else
440 LLVM_DEBUG({
441 dbgs() << " Graphifying regular section "
442 << NSec.GraphSection->getName() << "...\n";
443 });
444
445 bool SectionIsNoDeadStrip = NSec.Flags & MachO::S_ATTR_NO_DEAD_STRIP;
446 bool SectionIsText = NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS;
447
448 auto &SecNSymStack = SecIndexToSymbols[SecIndex];
449
450 // If this section is non-empty but there are no symbols covering it then
451 // create one block and anonymous symbol to cover the entire section.
452 if (SecNSymStack.empty()) {
453 if (NSec.Size > 0) {
454 LLVM_DEBUG({
455 dbgs() << " Section non-empty, but contains no symbols. "
456 "Creating anonymous block to cover "
457 << formatv("{0:x16}", NSec.Address) << " -- "
458 << formatv("{0:x16}", NSec.Address + NSec.Size) << "\n";
459 });
460 addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address,
461 NSec.Data, NSec.Size, NSec.Alignment,
462 SectionIsNoDeadStrip);
463 } else
464 LLVM_DEBUG({
465 dbgs() << " Section empty and contains no symbols. Skipping.\n";
466 });
467 continue;
468 }
469
470 // Sort the symbol stack in by address, alt-entry status, scope, and name.
471 // We sort in reverse order so that symbols will be visited in the right
472 // order when we pop off the stack below.
473 llvm::sort(SecNSymStack, [](const NormalizedSymbol *LHS,
474 const NormalizedSymbol *RHS) {
475 if (LHS->Value != RHS->Value)
476 return LHS->Value > RHS->Value;
478 return isAltEntry(*RHS);
479 if (LHS->S != RHS->S)
480 return static_cast<uint8_t>(LHS->S) < static_cast<uint8_t>(RHS->S);
481 return LHS->Name < RHS->Name;
482 });
483
484 // The first symbol in a section can not be an alt-entry symbol.
485 if (!SecNSymStack.empty() && isAltEntry(*SecNSymStack.back()))
486 return make_error<JITLinkError>(
487 "First symbol in " + NSec.GraphSection->getName() + " is alt-entry");
488
489 // If the section is non-empty but there is no symbol covering the start
490 // address then add an anonymous one.
491 if (orc::ExecutorAddr(SecNSymStack.back()->Value) != NSec.Address) {
492 auto AnonBlockSize =
493 orc::ExecutorAddr(SecNSymStack.back()->Value) - NSec.Address;
494 LLVM_DEBUG({
495 dbgs() << " Section start not covered by symbol. "
496 << "Creating anonymous block to cover [ " << NSec.Address
497 << " -- " << (NSec.Address + AnonBlockSize) << " ]\n";
498 });
499 addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address,
500 NSec.Data, AnonBlockSize, NSec.Alignment,
501 SectionIsNoDeadStrip);
502 }
503
504 // Visit section symbols in order by popping off the reverse-sorted stack,
505 // building graph symbols as we go.
506 //
507 // If MH_SUBSECTIONS_VIA_SYMBOLS is set we'll build a block for each
508 // alt-entry chain.
509 //
510 // If MH_SUBSECTIONS_VIA_SYMBOLS is not set then we'll just build one block
511 // for the whole section.
512 while (!SecNSymStack.empty()) {
513 SmallVector<NormalizedSymbol *, 8> BlockSyms;
514
515 // Get the symbols in this alt-entry chain, or the whole section (if
516 // !SubsectionsViaSymbols).
517 BlockSyms.push_back(SecNSymStack.back());
518 SecNSymStack.pop_back();
519 while (!SecNSymStack.empty() &&
520 (isAltEntry(*SecNSymStack.back()) ||
521 SecNSymStack.back()->Value == BlockSyms.back()->Value ||
522 !SubsectionsViaSymbols)) {
523 BlockSyms.push_back(SecNSymStack.back());
524 SecNSymStack.pop_back();
525 }
526
527 // BlockNSyms now contains the block symbols in reverse canonical order.
528 auto BlockStart = orc::ExecutorAddr(BlockSyms.front()->Value);
529 orc::ExecutorAddr BlockEnd =
530 SecNSymStack.empty() ? NSec.Address + NSec.Size
531 : orc::ExecutorAddr(SecNSymStack.back()->Value);
532 orc::ExecutorAddrDiff BlockOffset = BlockStart - NSec.Address;
533 orc::ExecutorAddrDiff BlockSize = BlockEnd - BlockStart;
534
535 LLVM_DEBUG({
536 dbgs() << " Creating block for " << formatv("{0:x16}", BlockStart)
537 << " -- " << formatv("{0:x16}", BlockEnd) << ": "
538 << NSec.GraphSection->getName() << " + "
539 << formatv("{0:x16}", BlockOffset) << " with "
540 << BlockSyms.size() << " symbol(s)...\n";
541 });
542
543 Block &B =
544 NSec.Data
545 ? G->createContentBlock(
546 *NSec.GraphSection,
547 ArrayRef<char>(NSec.Data + BlockOffset, BlockSize),
548 BlockStart, NSec.Alignment, BlockStart % NSec.Alignment)
549 : G->createZeroFillBlock(*NSec.GraphSection, BlockSize,
550 BlockStart, NSec.Alignment,
551 BlockStart % NSec.Alignment);
552
553 std::optional<orc::ExecutorAddr> LastCanonicalAddr;
554 auto SymEnd = BlockEnd;
555 while (!BlockSyms.empty()) {
556 auto &NSym = *BlockSyms.back();
557 BlockSyms.pop_back();
558
559 bool SymLive =
560 (NSym.Desc & MachO::N_NO_DEAD_STRIP) || SectionIsNoDeadStrip;
561
562 auto &Sym = createStandardGraphSymbol(
563 NSym, B, SymEnd - orc::ExecutorAddr(NSym.Value), SectionIsText,
564 SymLive, LastCanonicalAddr != orc::ExecutorAddr(NSym.Value));
565
566 if (LastCanonicalAddr != Sym.getAddress()) {
567 if (LastCanonicalAddr)
568 SymEnd = *LastCanonicalAddr;
569 LastCanonicalAddr = Sym.getAddress();
570 }
571 }
572 }
573 }
574
575 return Error::success();
576}
577
578Symbol &MachOLinkGraphBuilder::createStandardGraphSymbol(NormalizedSymbol &NSym,
579 Block &B, size_t Size,
580 bool IsText,
581 bool IsNoDeadStrip,
582 bool IsCanonical) {
583
584 LLVM_DEBUG({
585 dbgs() << " " << formatv("{0:x16}", NSym.Value) << " -- "
586 << formatv("{0:x16}", NSym.Value + Size) << ": ";
587 if (!NSym.Name)
588 dbgs() << "<anonymous symbol>";
589 else
590 dbgs() << *NSym.Name;
591 if (IsText)
592 dbgs() << " [text]";
593 if (IsNoDeadStrip)
594 dbgs() << " [no-dead-strip]";
595 if (!IsCanonical)
596 dbgs() << " [non-canonical]";
597 dbgs() << "\n";
598 });
599
600 auto SymOffset = orc::ExecutorAddr(NSym.Value) - B.getAddress();
601 auto &Sym =
602 NSym.Name
603 ? G->addDefinedSymbol(B, SymOffset, *NSym.Name, Size, NSym.L, NSym.S,
604 IsText, IsNoDeadStrip)
605 : G->addAnonymousSymbol(B, SymOffset, Size, IsText, IsNoDeadStrip);
606 NSym.GraphSymbol = &Sym;
607
608 if (IsCanonical)
609 setCanonicalSymbol(getSectionByIndex(NSym.Sect - 1), Sym);
610
611 return Sym;
612}
613
614Error MachOLinkGraphBuilder::graphifySectionsWithCustomParsers() {
615 // Graphify special sections.
616 for (auto &KV : IndexToSection) {
617 auto &NSec = KV.second;
618
619 // Skip non-graph sections.
620 if (!NSec.GraphSection)
621 continue;
622
623 auto HI = CustomSectionParserFunctions.find(NSec.GraphSection->getName());
624 if (HI != CustomSectionParserFunctions.end()) {
625 auto &Parse = HI->second;
626 if (auto Err = Parse(NSec))
627 return Err;
628 }
629 }
630
631 return Error::success();
632}
633
634Error MachOLinkGraphBuilder::graphifyCStringSection(
635 NormalizedSection &NSec, std::vector<NormalizedSymbol *> NSyms) {
636 assert(NSec.GraphSection && "C string literal section missing graph section");
637 assert(NSec.Data && "C string literal section has no data");
638
639 LLVM_DEBUG({
640 dbgs() << " Graphifying C-string literal section "
641 << NSec.GraphSection->getName() << "\n";
642 });
643
644 if (NSec.Data[NSec.Size - 1] != '\0')
645 return make_error<JITLinkError>("C string literal section " +
646 NSec.GraphSection->getName() +
647 " does not end with null terminator");
648
649 /// Sort into reverse order to use as a stack.
650 llvm::sort(NSyms,
651 [](const NormalizedSymbol *LHS, const NormalizedSymbol *RHS) {
652 if (LHS->Value != RHS->Value)
653 return LHS->Value > RHS->Value;
654 if (LHS->L != RHS->L)
655 return LHS->L > RHS->L;
656 if (LHS->S != RHS->S)
657 return LHS->S > RHS->S;
658 if (RHS->Name) {
659 if (!LHS->Name)
660 return true;
661 return *LHS->Name > *RHS->Name;
662 }
663 return false;
664 });
665
666 bool SectionIsNoDeadStrip = NSec.Flags & MachO::S_ATTR_NO_DEAD_STRIP;
667 bool SectionIsText = NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS;
668 orc::ExecutorAddrDiff BlockStart = 0;
669
670 // Scan section for null characters.
671 for (size_t I = 0; I != NSec.Size; ++I) {
672 if (NSec.Data[I] == '\0') {
673 size_t BlockSize = I + 1 - BlockStart;
674 // Create a block for this null terminated string.
675 auto &B = G->createContentBlock(*NSec.GraphSection,
676 {NSec.Data + BlockStart, BlockSize},
677 NSec.Address + BlockStart, NSec.Alignment,
678 BlockStart % NSec.Alignment);
679
680 LLVM_DEBUG({
681 dbgs() << " Created block " << B.getRange()
682 << ", align = " << B.getAlignment()
683 << ", align-ofs = " << B.getAlignmentOffset() << " for \"";
684 for (size_t J = 0; J != std::min(B.getSize(), size_t(16)); ++J)
685 switch (B.getContent()[J]) {
686 case '\0': break;
687 case '\n': dbgs() << "\\n"; break;
688 case '\t': dbgs() << "\\t"; break;
689 default: dbgs() << B.getContent()[J]; break;
690 }
691 if (B.getSize() > 16)
692 dbgs() << "...";
693 dbgs() << "\"\n";
694 });
695
696 // If there's no symbol at the start of this block then create one.
697 if (NSyms.empty() ||
698 orc::ExecutorAddr(NSyms.back()->Value) != B.getAddress()) {
699 auto &S = G->addAnonymousSymbol(B, 0, BlockSize, false, false);
700 setCanonicalSymbol(NSec, S);
701 LLVM_DEBUG({
702 dbgs() << " Adding symbol for c-string block " << B.getRange()
703 << ": <anonymous symbol> at offset 0\n";
704 });
705 }
706
707 // Process any remaining symbols that point into this block.
708 auto LastCanonicalAddr = B.getAddress() + BlockSize;
709 while (!NSyms.empty() && orc::ExecutorAddr(NSyms.back()->Value) <
710 B.getAddress() + BlockSize) {
711 auto &NSym = *NSyms.back();
712 size_t SymSize = (B.getAddress() + BlockSize) -
713 orc::ExecutorAddr(NSyms.back()->Value);
714 bool SymLive =
715 (NSym.Desc & MachO::N_NO_DEAD_STRIP) || SectionIsNoDeadStrip;
716
717 bool IsCanonical = false;
718 if (LastCanonicalAddr != orc::ExecutorAddr(NSym.Value)) {
719 IsCanonical = true;
720 LastCanonicalAddr = orc::ExecutorAddr(NSym.Value);
721 }
722
723 auto &Sym = createStandardGraphSymbol(NSym, B, SymSize, SectionIsText,
724 SymLive, IsCanonical);
725 (void)Sym;
726 LLVM_DEBUG({
727 dbgs() << " Adding symbol for c-string block " << B.getRange()
728 << ": "
729 << (Sym.hasName() ? *Sym.getName() : "<anonymous symbol>")
730 << " at offset " << formatv("{0:x}", Sym.getOffset()) << "\n";
731 });
732
733 NSyms.pop_back();
734 }
735
736 BlockStart += BlockSize;
737 }
738 }
739
740 assert(llvm::all_of(NSec.GraphSection->blocks(),
741 [](Block *B) { return isCStringBlock(*B); }) &&
742 "All blocks in section should hold single c-strings");
743
744 return Error::success();
745}
746
748 auto *CUSec = G.findSectionByName(CompactUnwindSectionName);
749 if (!CUSec)
750 return Error::success();
751
752 if (!G.getTargetTriple().isOSBinFormatMachO())
753 return make_error<JITLinkError>(
754 "Error linking " + G.getName() +
755 ": compact unwind splitting not supported on non-macho target " +
756 G.getTargetTriple().str());
757
758 unsigned CURecordSize = 0;
759 unsigned PersonalityEdgeOffset = 0;
760 unsigned LSDAEdgeOffset = 0;
761 switch (G.getTargetTriple().getArch()) {
762 case Triple::aarch64:
763 case Triple::x86_64:
764 // 64-bit compact-unwind record format:
765 // Range start: 8 bytes.
766 // Range size: 4 bytes.
767 // CU encoding: 4 bytes.
768 // Personality: 8 bytes.
769 // LSDA: 8 bytes.
770 CURecordSize = 32;
771 PersonalityEdgeOffset = 16;
772 LSDAEdgeOffset = 24;
773 break;
774 default:
775 return make_error<JITLinkError>(
776 "Error linking " + G.getName() +
777 ": compact unwind splitting not supported on " +
778 G.getTargetTriple().getArchName());
779 }
780
781 std::vector<Block *> OriginalBlocks(CUSec->blocks().begin(),
782 CUSec->blocks().end());
783 LLVM_DEBUG({
784 dbgs() << "In " << G.getName() << " splitting compact unwind section "
785 << CompactUnwindSectionName << " containing "
786 << OriginalBlocks.size() << " initial blocks...\n";
787 });
788
789 while (!OriginalBlocks.empty()) {
790 auto *B = OriginalBlocks.back();
791 OriginalBlocks.pop_back();
792
793 if (B->getSize() == 0) {
794 LLVM_DEBUG({
795 dbgs() << " Skipping empty block at "
796 << formatv("{0:x16}", B->getAddress()) << "\n";
797 });
798 continue;
799 }
800
801 unsigned NumBlocks = B->getSize() / CURecordSize;
802
803 LLVM_DEBUG({
804 dbgs() << " Splitting block at " << formatv("{0:x16}", B->getAddress())
805 << " into " << NumBlocks << " compact unwind record(s)\n";
806 });
807
808 if (B->getSize() % CURecordSize)
809 return make_error<JITLinkError>(
810 "Error splitting compact unwind record in " + G.getName() +
811 ": block at " + formatv("{0:x}", B->getAddress()) + " has size " +
812 formatv("{0:x}", B->getSize()) +
813 " (not a multiple of CU record size of " +
814 formatv("{0:x}", CURecordSize) + ")");
815
816 auto Blocks =
817 G.splitBlock(*B, map_range(seq(1U, NumBlocks), [=](Edge::OffsetT Idx) {
818 return Idx * CURecordSize;
819 }));
820
821 for (auto *CURec : Blocks) {
822 bool AddedKeepAlive = false;
823
824 for (auto &E : CURec->edges()) {
825 if (E.getOffset() == 0) {
826 LLVM_DEBUG({
827 dbgs() << " Updating compact unwind record at "
828 << CURec->getAddress() << " to point to "
829 << (E.getTarget().hasName() ? *E.getTarget().getName()
830 : StringRef())
831 << " (at " << E.getTarget().getAddress() << ")\n";
832 });
833
834 if (E.getTarget().isExternal())
835 return make_error<JITLinkError>(
836 "Error adding keep-alive edge for compact unwind record at " +
837 formatv("{0:x}", CURec->getAddress()) + ": target " +
838 *E.getTarget().getName() + " is an external symbol");
839 auto &TgtBlock = E.getTarget().getBlock();
840 auto &CURecSym =
841 G.addAnonymousSymbol(*CURec, 0, CURecordSize, false, false);
842 TgtBlock.addEdge(Edge::KeepAlive, 0, CURecSym, 0);
843 AddedKeepAlive = true;
844 } else if (E.getOffset() != PersonalityEdgeOffset &&
845 E.getOffset() != LSDAEdgeOffset)
846 return make_error<JITLinkError>(
847 "Unexpected edge at offset " + formatv("{0:x}", E.getOffset()) +
848 " in compact unwind record at " +
849 formatv("{0:x}", CURec->getAddress()));
850 }
851
852 if (!AddedKeepAlive)
853 return make_error<JITLinkError>(
854 "Error adding keep-alive edge for compact unwind record at " +
855 formatv("{0:x}", CURec->getAddress()) +
856 ": no outgoing target edge at offset 0");
857 }
858 }
859
860 return Error::success();
861}
862
863} // end namespace jitlink
864} // 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
static std::optional< TypeSize > getPointerSize(const Value *V, const DataLayout &DL, const TargetLibraryInfo &TLI, const Function *F)
#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
bool isLittleEndian() const
Definition: Binary.h:155
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
@ 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
endianness
Definition: bit.h:70
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.