1 //=--------- MachOLinkGraphBuilder.cpp - MachO LinkGraph builder ----------===//
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
7 //===----------------------------------------------------------------------===//
9 // Generic MachO LinkGraph building code.
11 //===----------------------------------------------------------------------===//
13 #include "MachOLinkGraphBuilder.h"
16 #define DEBUG_TYPE "jitlink"
18 static const char *CommonSectionName
= "__common";
23 MachOLinkGraphBuilder::~MachOLinkGraphBuilder() = default;
25 Expected
<std::unique_ptr
<LinkGraph
>> MachOLinkGraphBuilder::buildGraph() {
27 // We only operate on relocatable objects.
28 if (!Obj
.isRelocatableObject())
29 return make_error
<JITLinkError
>("Object is not a relocatable MachO");
31 if (auto Err
= createNormalizedSections())
32 return std::move(Err
);
34 if (auto Err
= createNormalizedSymbols())
35 return std::move(Err
);
37 if (auto Err
= graphifyRegularSymbols())
38 return std::move(Err
);
40 if (auto Err
= graphifySectionsWithCustomParsers())
41 return std::move(Err
);
43 if (auto Err
= addRelocations())
44 return std::move(Err
);
49 MachOLinkGraphBuilder::MachOLinkGraphBuilder(
50 const object::MachOObjectFile
&Obj
, Triple TT
, SubtargetFeatures Features
,
51 LinkGraph::GetEdgeKindNameFunction GetEdgeKindName
)
53 G(std::make_unique
<LinkGraph
>(std::string(Obj
.getFileName()),
54 std::move(TT
), std::move(Features
),
55 getPointerSize(Obj
), getEndianness(Obj
),
56 std::move(GetEdgeKindName
))) {
57 auto &MachHeader
= Obj
.getHeader64();
58 SubsectionsViaSymbols
= MachHeader
.flags
& MachO::MH_SUBSECTIONS_VIA_SYMBOLS
;
61 void MachOLinkGraphBuilder::addCustomSectionParser(
62 StringRef SectionName
, SectionParserFunction Parser
) {
63 assert(!CustomSectionParserFunctions
.count(SectionName
) &&
64 "Custom parser for this section already exists");
65 CustomSectionParserFunctions
[SectionName
] = std::move(Parser
);
68 Linkage
MachOLinkGraphBuilder::getLinkage(uint16_t Desc
) {
69 if ((Desc
& MachO::N_WEAK_DEF
) || (Desc
& MachO::N_WEAK_REF
))
71 return Linkage::Strong
;
74 Scope
MachOLinkGraphBuilder::getScope(StringRef Name
, uint8_t Type
) {
75 if (Type
& MachO::N_EXT
) {
76 if ((Type
& MachO::N_PEXT
) || Name
.starts_with("l"))
79 return Scope::Default
;
84 bool MachOLinkGraphBuilder::isAltEntry(const NormalizedSymbol
&NSym
) {
85 return NSym
.Desc
& MachO::N_ALT_ENTRY
;
88 bool MachOLinkGraphBuilder::isDebugSection(const NormalizedSection
&NSec
) {
89 return (NSec
.Flags
& MachO::S_ATTR_DEBUG
&&
90 strcmp(NSec
.SegName
, "__DWARF") == 0);
93 bool MachOLinkGraphBuilder::isZeroFillSection(const NormalizedSection
&NSec
) {
94 switch (NSec
.Flags
& MachO::SECTION_TYPE
) {
95 case MachO::S_ZEROFILL
:
96 case MachO::S_GB_ZEROFILL
:
97 case MachO::S_THREAD_LOCAL_ZEROFILL
:
105 MachOLinkGraphBuilder::getPointerSize(const object::MachOObjectFile
&Obj
) {
106 return Obj
.is64Bit() ? 8 : 4;
110 MachOLinkGraphBuilder::getEndianness(const object::MachOObjectFile
&Obj
) {
111 return Obj
.isLittleEndian() ? llvm::endianness::little
112 : llvm::endianness::big
;
115 Section
&MachOLinkGraphBuilder::getCommonSection() {
117 CommonSection
= &G
->createSection(CommonSectionName
,
118 orc::MemProt::Read
| orc::MemProt::Write
);
119 return *CommonSection
;
122 Error
MachOLinkGraphBuilder::createNormalizedSections() {
123 // Build normalized sections. Verifies that section data is in-range (for
124 // sections with content) and that address ranges are non-overlapping.
126 LLVM_DEBUG(dbgs() << "Creating normalized sections...\n");
128 for (auto &SecRef
: Obj
.sections()) {
129 NormalizedSection NSec
;
130 uint32_t DataOffset
= 0;
132 auto SecIndex
= Obj
.getSectionIndex(SecRef
.getRawDataRefImpl());
135 const MachO::section_64
&Sec64
=
136 Obj
.getSection64(SecRef
.getRawDataRefImpl());
138 memcpy(&NSec
.SectName
, &Sec64
.sectname
, 16);
139 NSec
.SectName
[16] = '\0';
140 memcpy(&NSec
.SegName
, Sec64
.segname
, 16);
141 NSec
.SegName
[16] = '\0';
143 NSec
.Address
= orc::ExecutorAddr(Sec64
.addr
);
144 NSec
.Size
= Sec64
.size
;
145 NSec
.Alignment
= 1ULL << Sec64
.align
;
146 NSec
.Flags
= Sec64
.flags
;
147 DataOffset
= Sec64
.offset
;
149 const MachO::section
&Sec32
= Obj
.getSection(SecRef
.getRawDataRefImpl());
151 memcpy(&NSec
.SectName
, &Sec32
.sectname
, 16);
152 NSec
.SectName
[16] = '\0';
153 memcpy(&NSec
.SegName
, Sec32
.segname
, 16);
154 NSec
.SegName
[16] = '\0';
156 NSec
.Address
= orc::ExecutorAddr(Sec32
.addr
);
157 NSec
.Size
= Sec32
.size
;
158 NSec
.Alignment
= 1ULL << Sec32
.align
;
159 NSec
.Flags
= Sec32
.flags
;
160 DataOffset
= Sec32
.offset
;
164 dbgs() << " " << NSec
.SegName
<< "," << NSec
.SectName
<< ": "
165 << formatv("{0:x16}", NSec
.Address
) << " -- "
166 << formatv("{0:x16}", NSec
.Address
+ NSec
.Size
)
167 << ", align: " << NSec
.Alignment
<< ", index: " << SecIndex
171 // Get the section data if any.
172 if (!isZeroFillSection(NSec
)) {
173 if (DataOffset
+ NSec
.Size
> Obj
.getData().size())
174 return make_error
<JITLinkError
>(
175 "Section data extends past end of file");
177 NSec
.Data
= Obj
.getData().data() + DataOffset
;
181 // FIXME: Make sure this test is correct (it's probably missing cases
184 if (NSec
.Flags
& MachO::S_ATTR_PURE_INSTRUCTIONS
)
185 Prot
= orc::MemProt::Read
| orc::MemProt::Exec
;
187 Prot
= orc::MemProt::Read
| orc::MemProt::Write
;
189 auto FullyQualifiedName
=
190 G
->allocateContent(StringRef(NSec
.SegName
) + "," + NSec
.SectName
);
191 NSec
.GraphSection
= &G
->createSection(
192 StringRef(FullyQualifiedName
.data(), FullyQualifiedName
.size()), Prot
);
194 // TODO: Are there any other criteria for NoAlloc lifetime?
195 if (NSec
.Flags
& MachO::S_ATTR_DEBUG
)
196 NSec
.GraphSection
->setMemLifetime(orc::MemLifetime::NoAlloc
);
198 IndexToSection
.insert(std::make_pair(SecIndex
, std::move(NSec
)));
201 std::vector
<NormalizedSection
*> Sections
;
202 Sections
.reserve(IndexToSection
.size());
203 for (auto &KV
: IndexToSection
)
204 Sections
.push_back(&KV
.second
);
206 // If we didn't end up creating any sections then bail out. The code below
207 // assumes that we have at least one section.
208 if (Sections
.empty())
209 return Error::success();
212 [](const NormalizedSection
*LHS
, const NormalizedSection
*RHS
) {
213 assert(LHS
&& RHS
&& "Null section?");
214 if (LHS
->Address
!= RHS
->Address
)
215 return LHS
->Address
< RHS
->Address
;
216 return LHS
->Size
< RHS
->Size
;
219 for (unsigned I
= 0, E
= Sections
.size() - 1; I
!= E
; ++I
) {
220 auto &Cur
= *Sections
[I
];
221 auto &Next
= *Sections
[I
+ 1];
222 if (Next
.Address
< Cur
.Address
+ Cur
.Size
)
223 return make_error
<JITLinkError
>(
224 "Address range for section " +
225 formatv("\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Cur
.SegName
,
226 Cur
.SectName
, Cur
.Address
, Cur
.Address
+ Cur
.Size
) +
227 "overlaps section \"" + Next
.SegName
+ "/" + Next
.SectName
+ "\"" +
228 formatv("\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Next
.SegName
,
229 Next
.SectName
, Next
.Address
, Next
.Address
+ Next
.Size
));
232 return Error::success();
235 Error
MachOLinkGraphBuilder::createNormalizedSymbols() {
236 LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n");
238 for (auto &SymRef
: Obj
.symbols()) {
240 unsigned SymbolIndex
= Obj
.getSymbolIndex(SymRef
.getRawDataRefImpl());
248 const MachO::nlist_64
&NL64
=
249 Obj
.getSymbol64TableEntry(SymRef
.getRawDataRefImpl());
250 Value
= NL64
.n_value
;
256 const MachO::nlist
&NL32
=
257 Obj
.getSymbolTableEntry(SymRef
.getRawDataRefImpl());
258 Value
= NL32
.n_value
;
266 // FIXME: Are there other symbols we should be skipping?
267 if (Type
& MachO::N_STAB
)
270 std::optional
<StringRef
> Name
;
272 if (auto NameOrErr
= SymRef
.getName())
275 return NameOrErr
.takeError();
276 } else if (Type
& MachO::N_EXT
)
277 return make_error
<JITLinkError
>("Symbol at index " +
278 formatv("{0}", SymbolIndex
) +
279 " has no name (string table index 0), "
280 "but N_EXT bit is set");
285 dbgs() << "<anonymous symbol>";
288 dbgs() << ": value = " << formatv("{0:x16}", Value
)
289 << ", type = " << formatv("{0:x2}", Type
)
290 << ", desc = " << formatv("{0:x4}", Desc
) << ", sect = ";
292 dbgs() << static_cast<unsigned>(Sect
- 1);
298 // If this symbol has a section, verify that the addresses line up.
300 auto NSec
= findSectionByIndex(Sect
- 1);
302 return NSec
.takeError();
304 if (orc::ExecutorAddr(Value
) < NSec
->Address
||
305 orc::ExecutorAddr(Value
) > NSec
->Address
+ NSec
->Size
)
306 return make_error
<JITLinkError
>("Address " + formatv("{0:x}", Value
) +
307 " for symbol " + *Name
+
308 " does not fall within section");
310 if (!NSec
->GraphSection
) {
312 dbgs() << " Skipping: Symbol is in section " << NSec
->SegName
<< "/"
314 << " which has no associated graph section.\n";
320 IndexToSymbol
[SymbolIndex
] =
321 &createNormalizedSymbol(*Name
, Value
, Type
, Sect
, Desc
,
322 getLinkage(Desc
), getScope(*Name
, Type
));
325 return Error::success();
328 void MachOLinkGraphBuilder::addSectionStartSymAndBlock(
329 unsigned SecIndex
, Section
&GraphSec
, orc::ExecutorAddr Address
,
330 const char *Data
, orc::ExecutorAddrDiff Size
, uint32_t Alignment
,
333 Data
? G
->createContentBlock(GraphSec
, ArrayRef
<char>(Data
, Size
),
334 Address
, Alignment
, 0)
335 : G
->createZeroFillBlock(GraphSec
, Size
, Address
, Alignment
, 0);
336 auto &Sym
= G
->addAnonymousSymbol(B
, 0, Size
, false, IsLive
);
337 auto SecI
= IndexToSection
.find(SecIndex
);
338 assert(SecI
!= IndexToSection
.end() && "SecIndex invalid");
339 auto &NSec
= SecI
->second
;
340 assert(!NSec
.CanonicalSymbols
.count(Sym
.getAddress()) &&
341 "Anonymous block start symbol clashes with existing symbol address");
342 NSec
.CanonicalSymbols
[Sym
.getAddress()] = &Sym
;
345 Error
MachOLinkGraphBuilder::graphifyRegularSymbols() {
347 LLVM_DEBUG(dbgs() << "Creating graph symbols...\n");
349 /// We only have 256 section indexes: Use a vector rather than a map.
350 std::vector
<std::vector
<NormalizedSymbol
*>> SecIndexToSymbols
;
351 SecIndexToSymbols
.resize(256);
353 // Create commons, externs, and absolutes, and partition all other symbols by
355 for (auto &KV
: IndexToSymbol
) {
356 auto &NSym
= *KV
.second
;
358 switch (NSym
.Type
& MachO::N_TYPE
) {
362 return make_error
<JITLinkError
>("Anonymous common symbol at index " +
364 NSym
.GraphSymbol
= &G
->addDefinedSymbol(
365 G
->createZeroFillBlock(getCommonSection(),
366 orc::ExecutorAddrDiff(NSym
.Value
),
368 1ull << MachO::GET_COMM_ALIGN(NSym
.Desc
), 0),
369 0, *NSym
.Name
, orc::ExecutorAddrDiff(NSym
.Value
), Linkage::Strong
,
370 NSym
.S
, false, NSym
.Desc
& MachO::N_NO_DEAD_STRIP
);
373 return make_error
<JITLinkError
>("Anonymous external symbol at "
376 NSym
.GraphSymbol
= &G
->addExternalSymbol(
377 *NSym
.Name
, 0, (NSym
.Desc
& MachO::N_WEAK_REF
) != 0);
382 return make_error
<JITLinkError
>("Anonymous absolute symbol at index " +
384 NSym
.GraphSymbol
= &G
->addAbsoluteSymbol(
385 *NSym
.Name
, orc::ExecutorAddr(NSym
.Value
), 0, Linkage::Strong
,
386 getScope(*NSym
.Name
, NSym
.Type
), NSym
.Desc
& MachO::N_NO_DEAD_STRIP
);
389 SecIndexToSymbols
[NSym
.Sect
- 1].push_back(&NSym
);
392 return make_error
<JITLinkError
>(
393 "Unupported N_PBUD symbol " +
394 (NSym
.Name
? ("\"" + *NSym
.Name
+ "\"") : Twine("<anon>")) +
395 " at index " + Twine(KV
.first
));
397 return make_error
<JITLinkError
>(
398 "Unupported N_INDR symbol " +
399 (NSym
.Name
? ("\"" + *NSym
.Name
+ "\"") : Twine("<anon>")) +
400 " at index " + Twine(KV
.first
));
402 return make_error
<JITLinkError
>(
403 "Unrecognized symbol type " + Twine(NSym
.Type
& MachO::N_TYPE
) +
405 (NSym
.Name
? ("\"" + *NSym
.Name
+ "\"") : Twine("<anon>")) +
406 " at index " + Twine(KV
.first
));
410 // Loop over sections performing regular graphification for those that
411 // don't have custom parsers.
412 for (auto &KV
: IndexToSection
) {
413 auto SecIndex
= KV
.first
;
414 auto &NSec
= KV
.second
;
416 if (!NSec
.GraphSection
) {
418 dbgs() << " " << NSec
.SegName
<< "/" << NSec
.SectName
419 << " has no graph section. Skipping.\n";
424 // Skip sections with custom parsers.
425 if (CustomSectionParserFunctions
.count(NSec
.GraphSection
->getName())) {
427 dbgs() << " Skipping section " << NSec
.GraphSection
->getName()
428 << " as it has a custom parser.\n";
431 } else if ((NSec
.Flags
& MachO::SECTION_TYPE
) ==
432 MachO::S_CSTRING_LITERALS
) {
433 if (auto Err
= graphifyCStringSection(
434 NSec
, std::move(SecIndexToSymbols
[SecIndex
])))
439 dbgs() << " Graphifying regular section "
440 << NSec
.GraphSection
->getName() << "...\n";
443 bool SectionIsNoDeadStrip
= NSec
.Flags
& MachO::S_ATTR_NO_DEAD_STRIP
;
444 bool SectionIsText
= NSec
.Flags
& MachO::S_ATTR_PURE_INSTRUCTIONS
;
446 auto &SecNSymStack
= SecIndexToSymbols
[SecIndex
];
448 // If this section is non-empty but there are no symbols covering it then
449 // create one block and anonymous symbol to cover the entire section.
450 if (SecNSymStack
.empty()) {
453 dbgs() << " Section non-empty, but contains no symbols. "
454 "Creating anonymous block to cover "
455 << formatv("{0:x16}", NSec
.Address
) << " -- "
456 << formatv("{0:x16}", NSec
.Address
+ NSec
.Size
) << "\n";
458 addSectionStartSymAndBlock(SecIndex
, *NSec
.GraphSection
, NSec
.Address
,
459 NSec
.Data
, NSec
.Size
, NSec
.Alignment
,
460 SectionIsNoDeadStrip
);
463 dbgs() << " Section empty and contains no symbols. Skipping.\n";
468 // Sort the symbol stack in by address, alt-entry status, scope, and name.
469 // We sort in reverse order so that symbols will be visited in the right
470 // order when we pop off the stack below.
471 llvm::sort(SecNSymStack
, [](const NormalizedSymbol
*LHS
,
472 const NormalizedSymbol
*RHS
) {
473 if (LHS
->Value
!= RHS
->Value
)
474 return LHS
->Value
> RHS
->Value
;
475 if (isAltEntry(*LHS
) != isAltEntry(*RHS
))
476 return isAltEntry(*RHS
);
477 if (LHS
->S
!= RHS
->S
)
478 return static_cast<uint8_t>(LHS
->S
) < static_cast<uint8_t>(RHS
->S
);
479 return LHS
->Name
< RHS
->Name
;
482 // The first symbol in a section can not be an alt-entry symbol.
483 if (!SecNSymStack
.empty() && isAltEntry(*SecNSymStack
.back()))
484 return make_error
<JITLinkError
>(
485 "First symbol in " + NSec
.GraphSection
->getName() + " is alt-entry");
487 // If the section is non-empty but there is no symbol covering the start
488 // address then add an anonymous one.
489 if (orc::ExecutorAddr(SecNSymStack
.back()->Value
) != NSec
.Address
) {
491 orc::ExecutorAddr(SecNSymStack
.back()->Value
) - NSec
.Address
;
493 dbgs() << " Section start not covered by symbol. "
494 << "Creating anonymous block to cover [ " << NSec
.Address
495 << " -- " << (NSec
.Address
+ AnonBlockSize
) << " ]\n";
497 addSectionStartSymAndBlock(SecIndex
, *NSec
.GraphSection
, NSec
.Address
,
498 NSec
.Data
, AnonBlockSize
, NSec
.Alignment
,
499 SectionIsNoDeadStrip
);
502 // Visit section symbols in order by popping off the reverse-sorted stack,
503 // building graph symbols as we go.
505 // If MH_SUBSECTIONS_VIA_SYMBOLS is set we'll build a block for each
508 // If MH_SUBSECTIONS_VIA_SYMBOLS is not set then we'll just build one block
509 // for the whole section.
510 while (!SecNSymStack
.empty()) {
511 SmallVector
<NormalizedSymbol
*, 8> BlockSyms
;
513 // Get the symbols in this alt-entry chain, or the whole section (if
514 // !SubsectionsViaSymbols).
515 BlockSyms
.push_back(SecNSymStack
.back());
516 SecNSymStack
.pop_back();
517 while (!SecNSymStack
.empty() &&
518 (isAltEntry(*SecNSymStack
.back()) ||
519 SecNSymStack
.back()->Value
== BlockSyms
.back()->Value
||
520 !SubsectionsViaSymbols
)) {
521 BlockSyms
.push_back(SecNSymStack
.back());
522 SecNSymStack
.pop_back();
525 // BlockNSyms now contains the block symbols in reverse canonical order.
526 auto BlockStart
= orc::ExecutorAddr(BlockSyms
.front()->Value
);
527 orc::ExecutorAddr BlockEnd
=
528 SecNSymStack
.empty() ? NSec
.Address
+ NSec
.Size
529 : orc::ExecutorAddr(SecNSymStack
.back()->Value
);
530 orc::ExecutorAddrDiff BlockOffset
= BlockStart
- NSec
.Address
;
531 orc::ExecutorAddrDiff BlockSize
= BlockEnd
- BlockStart
;
534 dbgs() << " Creating block for " << formatv("{0:x16}", BlockStart
)
535 << " -- " << formatv("{0:x16}", BlockEnd
) << ": "
536 << NSec
.GraphSection
->getName() << " + "
537 << formatv("{0:x16}", BlockOffset
) << " with "
538 << BlockSyms
.size() << " symbol(s)...\n";
543 ? G
->createContentBlock(
545 ArrayRef
<char>(NSec
.Data
+ BlockOffset
, BlockSize
),
546 BlockStart
, NSec
.Alignment
, BlockStart
% NSec
.Alignment
)
547 : G
->createZeroFillBlock(*NSec
.GraphSection
, BlockSize
,
548 BlockStart
, NSec
.Alignment
,
549 BlockStart
% NSec
.Alignment
);
551 std::optional
<orc::ExecutorAddr
> LastCanonicalAddr
;
552 auto SymEnd
= BlockEnd
;
553 while (!BlockSyms
.empty()) {
554 auto &NSym
= *BlockSyms
.back();
555 BlockSyms
.pop_back();
558 (NSym
.Desc
& MachO::N_NO_DEAD_STRIP
) || SectionIsNoDeadStrip
;
560 auto &Sym
= createStandardGraphSymbol(
561 NSym
, B
, SymEnd
- orc::ExecutorAddr(NSym
.Value
), SectionIsText
,
562 SymLive
, LastCanonicalAddr
!= orc::ExecutorAddr(NSym
.Value
));
564 if (LastCanonicalAddr
!= Sym
.getAddress()) {
565 if (LastCanonicalAddr
)
566 SymEnd
= *LastCanonicalAddr
;
567 LastCanonicalAddr
= Sym
.getAddress();
573 return Error::success();
576 Symbol
&MachOLinkGraphBuilder::createStandardGraphSymbol(NormalizedSymbol
&NSym
,
577 Block
&B
, size_t Size
,
583 dbgs() << " " << formatv("{0:x16}", NSym
.Value
) << " -- "
584 << formatv("{0:x16}", NSym
.Value
+ Size
) << ": ";
586 dbgs() << "<anonymous symbol>";
592 dbgs() << " [no-dead-strip]";
594 dbgs() << " [non-canonical]";
598 auto SymOffset
= orc::ExecutorAddr(NSym
.Value
) - B
.getAddress();
601 ? G
->addDefinedSymbol(B
, SymOffset
, *NSym
.Name
, Size
, NSym
.L
, NSym
.S
,
602 IsText
, IsNoDeadStrip
)
603 : G
->addAnonymousSymbol(B
, SymOffset
, Size
, IsText
, IsNoDeadStrip
);
604 NSym
.GraphSymbol
= &Sym
;
607 setCanonicalSymbol(getSectionByIndex(NSym
.Sect
- 1), Sym
);
612 Error
MachOLinkGraphBuilder::graphifySectionsWithCustomParsers() {
613 // Graphify special sections.
614 for (auto &KV
: IndexToSection
) {
615 auto &NSec
= KV
.second
;
617 // Skip non-graph sections.
618 if (!NSec
.GraphSection
)
621 auto HI
= CustomSectionParserFunctions
.find(NSec
.GraphSection
->getName());
622 if (HI
!= CustomSectionParserFunctions
.end()) {
623 auto &Parse
= HI
->second
;
624 if (auto Err
= Parse(NSec
))
629 return Error::success();
632 Error
MachOLinkGraphBuilder::graphifyCStringSection(
633 NormalizedSection
&NSec
, std::vector
<NormalizedSymbol
*> NSyms
) {
634 assert(NSec
.GraphSection
&& "C string literal section missing graph section");
635 assert(NSec
.Data
&& "C string literal section has no data");
638 dbgs() << " Graphifying C-string literal section "
639 << NSec
.GraphSection
->getName() << "\n";
642 if (NSec
.Data
[NSec
.Size
- 1] != '\0')
643 return make_error
<JITLinkError
>("C string literal section " +
644 NSec
.GraphSection
->getName() +
645 " does not end with null terminator");
647 /// Sort into reverse order to use as a stack.
649 [](const NormalizedSymbol
*LHS
, const NormalizedSymbol
*RHS
) {
650 if (LHS
->Value
!= RHS
->Value
)
651 return LHS
->Value
> RHS
->Value
;
652 if (LHS
->L
!= RHS
->L
)
653 return LHS
->L
> RHS
->L
;
654 if (LHS
->S
!= RHS
->S
)
655 return LHS
->S
> RHS
->S
;
659 return *LHS
->Name
> *RHS
->Name
;
664 bool SectionIsNoDeadStrip
= NSec
.Flags
& MachO::S_ATTR_NO_DEAD_STRIP
;
665 bool SectionIsText
= NSec
.Flags
& MachO::S_ATTR_PURE_INSTRUCTIONS
;
666 orc::ExecutorAddrDiff BlockStart
= 0;
668 // Scan section for null characters.
669 for (size_t I
= 0; I
!= NSec
.Size
; ++I
) {
670 if (NSec
.Data
[I
] == '\0') {
671 size_t BlockSize
= I
+ 1 - BlockStart
;
672 // Create a block for this null terminated string.
673 auto &B
= G
->createContentBlock(*NSec
.GraphSection
,
674 {NSec
.Data
+ BlockStart
, BlockSize
},
675 NSec
.Address
+ BlockStart
, NSec
.Alignment
,
676 BlockStart
% NSec
.Alignment
);
679 dbgs() << " Created block " << B
.getRange()
680 << ", align = " << B
.getAlignment()
681 << ", align-ofs = " << B
.getAlignmentOffset() << " for \"";
682 for (size_t J
= 0; J
!= std::min(B
.getSize(), size_t(16)); ++J
)
683 switch (B
.getContent()[J
]) {
685 case '\n': dbgs() << "\\n"; break;
686 case '\t': dbgs() << "\\t"; break;
687 default: dbgs() << B
.getContent()[J
]; break;
689 if (B
.getSize() > 16)
694 // If there's no symbol at the start of this block then create one.
696 orc::ExecutorAddr(NSyms
.back()->Value
) != B
.getAddress()) {
697 auto &S
= G
->addAnonymousSymbol(B
, 0, BlockSize
, false, false);
698 setCanonicalSymbol(NSec
, S
);
700 dbgs() << " Adding symbol for c-string block " << B
.getRange()
701 << ": <anonymous symbol> at offset 0\n";
705 // Process any remaining symbols that point into this block.
706 auto LastCanonicalAddr
= B
.getAddress() + BlockSize
;
707 while (!NSyms
.empty() && orc::ExecutorAddr(NSyms
.back()->Value
) <
708 B
.getAddress() + BlockSize
) {
709 auto &NSym
= *NSyms
.back();
710 size_t SymSize
= (B
.getAddress() + BlockSize
) -
711 orc::ExecutorAddr(NSyms
.back()->Value
);
713 (NSym
.Desc
& MachO::N_NO_DEAD_STRIP
) || SectionIsNoDeadStrip
;
715 bool IsCanonical
= false;
716 if (LastCanonicalAddr
!= orc::ExecutorAddr(NSym
.Value
)) {
718 LastCanonicalAddr
= orc::ExecutorAddr(NSym
.Value
);
721 auto &Sym
= createStandardGraphSymbol(NSym
, B
, SymSize
, SectionIsText
,
722 SymLive
, IsCanonical
);
725 dbgs() << " Adding symbol for c-string block " << B
.getRange()
727 << (Sym
.hasName() ? Sym
.getName() : "<anonymous symbol>")
728 << " at offset " << formatv("{0:x}", Sym
.getOffset()) << "\n";
734 BlockStart
+= BlockSize
;
738 assert(llvm::all_of(NSec
.GraphSection
->blocks(),
739 [](Block
*B
) { return isCStringBlock(*B
); }) &&
740 "All blocks in section should hold single c-strings");
742 return Error::success();
745 Error
CompactUnwindSplitter::operator()(LinkGraph
&G
) {
746 auto *CUSec
= G
.findSectionByName(CompactUnwindSectionName
);
748 return Error::success();
750 if (!G
.getTargetTriple().isOSBinFormatMachO())
751 return make_error
<JITLinkError
>(
752 "Error linking " + G
.getName() +
753 ": compact unwind splitting not supported on non-macho target " +
754 G
.getTargetTriple().str());
756 unsigned CURecordSize
= 0;
757 unsigned PersonalityEdgeOffset
= 0;
758 unsigned LSDAEdgeOffset
= 0;
759 switch (G
.getTargetTriple().getArch()) {
760 case Triple::aarch64
:
762 // 64-bit compact-unwind record format:
763 // Range start: 8 bytes.
764 // Range size: 4 bytes.
765 // CU encoding: 4 bytes.
766 // Personality: 8 bytes.
769 PersonalityEdgeOffset
= 16;
773 return make_error
<JITLinkError
>(
774 "Error linking " + G
.getName() +
775 ": compact unwind splitting not supported on " +
776 G
.getTargetTriple().getArchName());
779 std::vector
<Block
*> OriginalBlocks(CUSec
->blocks().begin(),
780 CUSec
->blocks().end());
782 dbgs() << "In " << G
.getName() << " splitting compact unwind section "
783 << CompactUnwindSectionName
<< " containing "
784 << OriginalBlocks
.size() << " initial blocks...\n";
787 while (!OriginalBlocks
.empty()) {
788 auto *B
= OriginalBlocks
.back();
789 OriginalBlocks
.pop_back();
791 if (B
->getSize() == 0) {
793 dbgs() << " Skipping empty block at "
794 << formatv("{0:x16}", B
->getAddress()) << "\n";
800 dbgs() << " Splitting block at " << formatv("{0:x16}", B
->getAddress())
801 << " into " << (B
->getSize() / CURecordSize
)
802 << " compact unwind record(s)\n";
805 if (B
->getSize() % CURecordSize
)
806 return make_error
<JITLinkError
>(
807 "Error splitting compact unwind record in " + G
.getName() +
808 ": block at " + formatv("{0:x}", B
->getAddress()) + " has size " +
809 formatv("{0:x}", B
->getSize()) +
810 " (not a multiple of CU record size of " +
811 formatv("{0:x}", CURecordSize
) + ")");
813 unsigned NumBlocks
= B
->getSize() / CURecordSize
;
814 LinkGraph::SplitBlockCache C
;
816 for (unsigned I
= 0; I
!= NumBlocks
; ++I
) {
817 auto &CURec
= G
.splitBlock(*B
, CURecordSize
, &C
);
818 bool AddedKeepAlive
= false;
820 for (auto &E
: CURec
.edges()) {
821 if (E
.getOffset() == 0) {
823 dbgs() << " Updating compact unwind record at "
824 << formatv("{0:x16}", CURec
.getAddress()) << " to point to "
825 << (E
.getTarget().hasName() ? E
.getTarget().getName()
827 << " (at " << formatv("{0:x16}", E
.getTarget().getAddress())
831 if (E
.getTarget().isExternal())
832 return make_error
<JITLinkError
>(
833 "Error adding keep-alive edge for compact unwind record at " +
834 formatv("{0:x}", CURec
.getAddress()) + ": target " +
835 E
.getTarget().getName() + " is an external symbol");
836 auto &TgtBlock
= E
.getTarget().getBlock();
838 G
.addAnonymousSymbol(CURec
, 0, CURecordSize
, false, false);
839 TgtBlock
.addEdge(Edge::KeepAlive
, 0, CURecSym
, 0);
840 AddedKeepAlive
= true;
841 } else if (E
.getOffset() != PersonalityEdgeOffset
&&
842 E
.getOffset() != LSDAEdgeOffset
)
843 return make_error
<JITLinkError
>("Unexpected edge at offset " +
844 formatv("{0:x}", E
.getOffset()) +
845 " in compact unwind record at " +
846 formatv("{0:x}", CURec
.getAddress()));
850 return make_error
<JITLinkError
>(
851 "Error adding keep-alive edge for compact unwind record at " +
852 formatv("{0:x}", CURec
.getAddress()) +
853 ": no outgoing target edge at offset 0");
856 return Error::success();
859 } // end namespace jitlink
860 } // end namespace llvm