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
.startswith("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() ? support::little
: support::big
;
114 Section
&MachOLinkGraphBuilder::getCommonSection() {
116 CommonSection
= &G
->createSection(CommonSectionName
,
117 orc::MemProt::Read
| orc::MemProt::Write
);
118 return *CommonSection
;
121 Error
MachOLinkGraphBuilder::createNormalizedSections() {
122 // Build normalized sections. Verifies that section data is in-range (for
123 // sections with content) and that address ranges are non-overlapping.
125 LLVM_DEBUG(dbgs() << "Creating normalized sections...\n");
127 for (auto &SecRef
: Obj
.sections()) {
128 NormalizedSection NSec
;
129 uint32_t DataOffset
= 0;
131 auto SecIndex
= Obj
.getSectionIndex(SecRef
.getRawDataRefImpl());
134 const MachO::section_64
&Sec64
=
135 Obj
.getSection64(SecRef
.getRawDataRefImpl());
137 memcpy(&NSec
.SectName
, &Sec64
.sectname
, 16);
138 NSec
.SectName
[16] = '\0';
139 memcpy(&NSec
.SegName
, Sec64
.segname
, 16);
140 NSec
.SegName
[16] = '\0';
142 NSec
.Address
= orc::ExecutorAddr(Sec64
.addr
);
143 NSec
.Size
= Sec64
.size
;
144 NSec
.Alignment
= 1ULL << Sec64
.align
;
145 NSec
.Flags
= Sec64
.flags
;
146 DataOffset
= Sec64
.offset
;
148 const MachO::section
&Sec32
= Obj
.getSection(SecRef
.getRawDataRefImpl());
150 memcpy(&NSec
.SectName
, &Sec32
.sectname
, 16);
151 NSec
.SectName
[16] = '\0';
152 memcpy(&NSec
.SegName
, Sec32
.segname
, 16);
153 NSec
.SegName
[16] = '\0';
155 NSec
.Address
= orc::ExecutorAddr(Sec32
.addr
);
156 NSec
.Size
= Sec32
.size
;
157 NSec
.Alignment
= 1ULL << Sec32
.align
;
158 NSec
.Flags
= Sec32
.flags
;
159 DataOffset
= Sec32
.offset
;
163 dbgs() << " " << NSec
.SegName
<< "," << NSec
.SectName
<< ": "
164 << formatv("{0:x16}", NSec
.Address
) << " -- "
165 << formatv("{0:x16}", NSec
.Address
+ NSec
.Size
)
166 << ", align: " << NSec
.Alignment
<< ", index: " << SecIndex
170 // Get the section data if any.
171 if (!isZeroFillSection(NSec
)) {
172 if (DataOffset
+ NSec
.Size
> Obj
.getData().size())
173 return make_error
<JITLinkError
>(
174 "Section data extends past end of file");
176 NSec
.Data
= Obj
.getData().data() + DataOffset
;
180 // FIXME: Make sure this test is correct (it's probably missing cases
183 if (NSec
.Flags
& MachO::S_ATTR_PURE_INSTRUCTIONS
)
184 Prot
= orc::MemProt::Read
| orc::MemProt::Exec
;
186 Prot
= orc::MemProt::Read
| orc::MemProt::Write
;
188 auto FullyQualifiedName
=
189 G
->allocateContent(StringRef(NSec
.SegName
) + "," + NSec
.SectName
);
190 NSec
.GraphSection
= &G
->createSection(
191 StringRef(FullyQualifiedName
.data(), FullyQualifiedName
.size()), Prot
);
193 // TODO: Are there any other criteria for NoAlloc lifetime?
194 if (NSec
.Flags
& MachO::S_ATTR_DEBUG
)
195 NSec
.GraphSection
->setMemLifetimePolicy(orc::MemLifetimePolicy::NoAlloc
);
197 IndexToSection
.insert(std::make_pair(SecIndex
, std::move(NSec
)));
200 std::vector
<NormalizedSection
*> Sections
;
201 Sections
.reserve(IndexToSection
.size());
202 for (auto &KV
: IndexToSection
)
203 Sections
.push_back(&KV
.second
);
205 // If we didn't end up creating any sections then bail out. The code below
206 // assumes that we have at least one section.
207 if (Sections
.empty())
208 return Error::success();
211 [](const NormalizedSection
*LHS
, const NormalizedSection
*RHS
) {
212 assert(LHS
&& RHS
&& "Null section?");
213 if (LHS
->Address
!= RHS
->Address
)
214 return LHS
->Address
< RHS
->Address
;
215 return LHS
->Size
< RHS
->Size
;
218 for (unsigned I
= 0, E
= Sections
.size() - 1; I
!= E
; ++I
) {
219 auto &Cur
= *Sections
[I
];
220 auto &Next
= *Sections
[I
+ 1];
221 if (Next
.Address
< Cur
.Address
+ Cur
.Size
)
222 return make_error
<JITLinkError
>(
223 "Address range for section " +
224 formatv("\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Cur
.SegName
,
225 Cur
.SectName
, Cur
.Address
, Cur
.Address
+ Cur
.Size
) +
226 "overlaps section \"" + Next
.SegName
+ "/" + Next
.SectName
+ "\"" +
227 formatv("\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Next
.SegName
,
228 Next
.SectName
, Next
.Address
, Next
.Address
+ Next
.Size
));
231 return Error::success();
234 Error
MachOLinkGraphBuilder::createNormalizedSymbols() {
235 LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n");
237 for (auto &SymRef
: Obj
.symbols()) {
239 unsigned SymbolIndex
= Obj
.getSymbolIndex(SymRef
.getRawDataRefImpl());
247 const MachO::nlist_64
&NL64
=
248 Obj
.getSymbol64TableEntry(SymRef
.getRawDataRefImpl());
249 Value
= NL64
.n_value
;
255 const MachO::nlist
&NL32
=
256 Obj
.getSymbolTableEntry(SymRef
.getRawDataRefImpl());
257 Value
= NL32
.n_value
;
265 // FIXME: Are there other symbols we should be skipping?
266 if (Type
& MachO::N_STAB
)
269 std::optional
<StringRef
> Name
;
271 if (auto NameOrErr
= SymRef
.getName())
274 return NameOrErr
.takeError();
275 } else if (Type
& MachO::N_EXT
)
276 return make_error
<JITLinkError
>("Symbol at index " +
277 formatv("{0}", SymbolIndex
) +
278 " has no name (string table index 0), "
279 "but N_EXT bit is set");
284 dbgs() << "<anonymous symbol>";
287 dbgs() << ": value = " << formatv("{0:x16}", Value
)
288 << ", type = " << formatv("{0:x2}", Type
)
289 << ", desc = " << formatv("{0:x4}", Desc
) << ", sect = ";
291 dbgs() << static_cast<unsigned>(Sect
- 1);
297 // If this symbol has a section, verify that the addresses line up.
299 auto NSec
= findSectionByIndex(Sect
- 1);
301 return NSec
.takeError();
303 if (orc::ExecutorAddr(Value
) < NSec
->Address
||
304 orc::ExecutorAddr(Value
) > NSec
->Address
+ NSec
->Size
)
305 return make_error
<JITLinkError
>("Address " + formatv("{0:x}", Value
) +
306 " for symbol " + *Name
+
307 " does not fall within section");
309 if (!NSec
->GraphSection
) {
311 dbgs() << " Skipping: Symbol is in section " << NSec
->SegName
<< "/"
313 << " which has no associated graph section.\n";
319 IndexToSymbol
[SymbolIndex
] =
320 &createNormalizedSymbol(*Name
, Value
, Type
, Sect
, Desc
,
321 getLinkage(Desc
), getScope(*Name
, Type
));
324 return Error::success();
327 void MachOLinkGraphBuilder::addSectionStartSymAndBlock(
328 unsigned SecIndex
, Section
&GraphSec
, orc::ExecutorAddr Address
,
329 const char *Data
, orc::ExecutorAddrDiff Size
, uint32_t Alignment
,
332 Data
? G
->createContentBlock(GraphSec
, ArrayRef
<char>(Data
, Size
),
333 Address
, Alignment
, 0)
334 : G
->createZeroFillBlock(GraphSec
, Size
, Address
, Alignment
, 0);
335 auto &Sym
= G
->addAnonymousSymbol(B
, 0, Size
, false, IsLive
);
336 auto SecI
= IndexToSection
.find(SecIndex
);
337 assert(SecI
!= IndexToSection
.end() && "SecIndex invalid");
338 auto &NSec
= SecI
->second
;
339 assert(!NSec
.CanonicalSymbols
.count(Sym
.getAddress()) &&
340 "Anonymous block start symbol clashes with existing symbol address");
341 NSec
.CanonicalSymbols
[Sym
.getAddress()] = &Sym
;
344 Error
MachOLinkGraphBuilder::graphifyRegularSymbols() {
346 LLVM_DEBUG(dbgs() << "Creating graph symbols...\n");
348 /// We only have 256 section indexes: Use a vector rather than a map.
349 std::vector
<std::vector
<NormalizedSymbol
*>> SecIndexToSymbols
;
350 SecIndexToSymbols
.resize(256);
352 // Create commons, externs, and absolutes, and partition all other symbols by
354 for (auto &KV
: IndexToSymbol
) {
355 auto &NSym
= *KV
.second
;
357 switch (NSym
.Type
& MachO::N_TYPE
) {
361 return make_error
<JITLinkError
>("Anonymous common symbol at index " +
363 NSym
.GraphSymbol
= &G
->addDefinedSymbol(
364 G
->createZeroFillBlock(getCommonSection(),
365 orc::ExecutorAddrDiff(NSym
.Value
),
367 1ull << MachO::GET_COMM_ALIGN(NSym
.Desc
), 0),
368 0, *NSym
.Name
, orc::ExecutorAddrDiff(NSym
.Value
), Linkage::Strong
,
369 NSym
.S
, false, NSym
.Desc
& MachO::N_NO_DEAD_STRIP
);
372 return make_error
<JITLinkError
>("Anonymous external symbol at "
375 NSym
.GraphSymbol
= &G
->addExternalSymbol(
376 *NSym
.Name
, 0, (NSym
.Desc
& MachO::N_WEAK_REF
) != 0);
381 return make_error
<JITLinkError
>("Anonymous absolute symbol at index " +
383 NSym
.GraphSymbol
= &G
->addAbsoluteSymbol(
384 *NSym
.Name
, orc::ExecutorAddr(NSym
.Value
), 0, Linkage::Strong
,
385 getScope(*NSym
.Name
, NSym
.Type
), NSym
.Desc
& MachO::N_NO_DEAD_STRIP
);
388 SecIndexToSymbols
[NSym
.Sect
- 1].push_back(&NSym
);
391 return make_error
<JITLinkError
>(
392 "Unupported N_PBUD symbol " +
393 (NSym
.Name
? ("\"" + *NSym
.Name
+ "\"") : Twine("<anon>")) +
394 " at index " + Twine(KV
.first
));
396 return make_error
<JITLinkError
>(
397 "Unupported N_INDR symbol " +
398 (NSym
.Name
? ("\"" + *NSym
.Name
+ "\"") : Twine("<anon>")) +
399 " at index " + Twine(KV
.first
));
401 return make_error
<JITLinkError
>(
402 "Unrecognized symbol type " + Twine(NSym
.Type
& MachO::N_TYPE
) +
404 (NSym
.Name
? ("\"" + *NSym
.Name
+ "\"") : Twine("<anon>")) +
405 " at index " + Twine(KV
.first
));
409 // Loop over sections performing regular graphification for those that
410 // don't have custom parsers.
411 for (auto &KV
: IndexToSection
) {
412 auto SecIndex
= KV
.first
;
413 auto &NSec
= KV
.second
;
415 if (!NSec
.GraphSection
) {
417 dbgs() << " " << NSec
.SegName
<< "/" << NSec
.SectName
418 << " has no graph section. Skipping.\n";
423 // Skip sections with custom parsers.
424 if (CustomSectionParserFunctions
.count(NSec
.GraphSection
->getName())) {
426 dbgs() << " Skipping section " << NSec
.GraphSection
->getName()
427 << " as it has a custom parser.\n";
430 } else if ((NSec
.Flags
& MachO::SECTION_TYPE
) ==
431 MachO::S_CSTRING_LITERALS
) {
432 if (auto Err
= graphifyCStringSection(
433 NSec
, std::move(SecIndexToSymbols
[SecIndex
])))
438 dbgs() << " Graphifying regular section "
439 << NSec
.GraphSection
->getName() << "...\n";
442 bool SectionIsNoDeadStrip
= NSec
.Flags
& MachO::S_ATTR_NO_DEAD_STRIP
;
443 bool SectionIsText
= NSec
.Flags
& MachO::S_ATTR_PURE_INSTRUCTIONS
;
445 auto &SecNSymStack
= SecIndexToSymbols
[SecIndex
];
447 // If this section is non-empty but there are no symbols covering it then
448 // create one block and anonymous symbol to cover the entire section.
449 if (SecNSymStack
.empty()) {
452 dbgs() << " Section non-empty, but contains no symbols. "
453 "Creating anonymous block to cover "
454 << formatv("{0:x16}", NSec
.Address
) << " -- "
455 << formatv("{0:x16}", NSec
.Address
+ NSec
.Size
) << "\n";
457 addSectionStartSymAndBlock(SecIndex
, *NSec
.GraphSection
, NSec
.Address
,
458 NSec
.Data
, NSec
.Size
, NSec
.Alignment
,
459 SectionIsNoDeadStrip
);
462 dbgs() << " Section empty and contains no symbols. Skipping.\n";
467 // Sort the symbol stack in by address, alt-entry status, scope, and name.
468 // We sort in reverse order so that symbols will be visited in the right
469 // order when we pop off the stack below.
470 llvm::sort(SecNSymStack
, [](const NormalizedSymbol
*LHS
,
471 const NormalizedSymbol
*RHS
) {
472 if (LHS
->Value
!= RHS
->Value
)
473 return LHS
->Value
> RHS
->Value
;
474 if (isAltEntry(*LHS
) != isAltEntry(*RHS
))
475 return isAltEntry(*RHS
);
476 if (LHS
->S
!= RHS
->S
)
477 return static_cast<uint8_t>(LHS
->S
) < static_cast<uint8_t>(RHS
->S
);
478 return LHS
->Name
< RHS
->Name
;
481 // The first symbol in a section can not be an alt-entry symbol.
482 if (!SecNSymStack
.empty() && isAltEntry(*SecNSymStack
.back()))
483 return make_error
<JITLinkError
>(
484 "First symbol in " + NSec
.GraphSection
->getName() + " is alt-entry");
486 // If the section is non-empty but there is no symbol covering the start
487 // address then add an anonymous one.
488 if (orc::ExecutorAddr(SecNSymStack
.back()->Value
) != NSec
.Address
) {
490 orc::ExecutorAddr(SecNSymStack
.back()->Value
) - NSec
.Address
;
492 dbgs() << " Section start not covered by symbol. "
493 << "Creating anonymous block to cover [ " << NSec
.Address
494 << " -- " << (NSec
.Address
+ AnonBlockSize
) << " ]\n";
496 addSectionStartSymAndBlock(SecIndex
, *NSec
.GraphSection
, NSec
.Address
,
497 NSec
.Data
, AnonBlockSize
, NSec
.Alignment
,
498 SectionIsNoDeadStrip
);
501 // Visit section symbols in order by popping off the reverse-sorted stack,
502 // building graph symbols as we go.
504 // If MH_SUBSECTIONS_VIA_SYMBOLS is set we'll build a block for each
507 // If MH_SUBSECTIONS_VIA_SYMBOLS is not set then we'll just build one block
508 // for the whole section.
509 while (!SecNSymStack
.empty()) {
510 SmallVector
<NormalizedSymbol
*, 8> BlockSyms
;
512 // Get the symbols in this alt-entry chain, or the whole section (if
513 // !SubsectionsViaSymbols).
514 BlockSyms
.push_back(SecNSymStack
.back());
515 SecNSymStack
.pop_back();
516 while (!SecNSymStack
.empty() &&
517 (isAltEntry(*SecNSymStack
.back()) ||
518 SecNSymStack
.back()->Value
== BlockSyms
.back()->Value
||
519 !SubsectionsViaSymbols
)) {
520 BlockSyms
.push_back(SecNSymStack
.back());
521 SecNSymStack
.pop_back();
524 // BlockNSyms now contains the block symbols in reverse canonical order.
525 auto BlockStart
= orc::ExecutorAddr(BlockSyms
.front()->Value
);
526 orc::ExecutorAddr BlockEnd
=
527 SecNSymStack
.empty() ? NSec
.Address
+ NSec
.Size
528 : orc::ExecutorAddr(SecNSymStack
.back()->Value
);
529 orc::ExecutorAddrDiff BlockOffset
= BlockStart
- NSec
.Address
;
530 orc::ExecutorAddrDiff BlockSize
= BlockEnd
- BlockStart
;
533 dbgs() << " Creating block for " << formatv("{0:x16}", BlockStart
)
534 << " -- " << formatv("{0:x16}", BlockEnd
) << ": "
535 << NSec
.GraphSection
->getName() << " + "
536 << formatv("{0:x16}", BlockOffset
) << " with "
537 << BlockSyms
.size() << " symbol(s)...\n";
542 ? G
->createContentBlock(
544 ArrayRef
<char>(NSec
.Data
+ BlockOffset
, BlockSize
),
545 BlockStart
, NSec
.Alignment
, BlockStart
% NSec
.Alignment
)
546 : G
->createZeroFillBlock(*NSec
.GraphSection
, BlockSize
,
547 BlockStart
, NSec
.Alignment
,
548 BlockStart
% NSec
.Alignment
);
550 std::optional
<orc::ExecutorAddr
> LastCanonicalAddr
;
551 auto SymEnd
= BlockEnd
;
552 while (!BlockSyms
.empty()) {
553 auto &NSym
= *BlockSyms
.back();
554 BlockSyms
.pop_back();
557 (NSym
.Desc
& MachO::N_NO_DEAD_STRIP
) || SectionIsNoDeadStrip
;
559 auto &Sym
= createStandardGraphSymbol(
560 NSym
, B
, SymEnd
- orc::ExecutorAddr(NSym
.Value
), SectionIsText
,
561 SymLive
, LastCanonicalAddr
!= orc::ExecutorAddr(NSym
.Value
));
563 if (LastCanonicalAddr
!= Sym
.getAddress()) {
564 if (LastCanonicalAddr
)
565 SymEnd
= *LastCanonicalAddr
;
566 LastCanonicalAddr
= Sym
.getAddress();
572 return Error::success();
575 Symbol
&MachOLinkGraphBuilder::createStandardGraphSymbol(NormalizedSymbol
&NSym
,
576 Block
&B
, size_t Size
,
582 dbgs() << " " << formatv("{0:x16}", NSym
.Value
) << " -- "
583 << formatv("{0:x16}", NSym
.Value
+ Size
) << ": ";
585 dbgs() << "<anonymous symbol>";
591 dbgs() << " [no-dead-strip]";
593 dbgs() << " [non-canonical]";
597 auto SymOffset
= orc::ExecutorAddr(NSym
.Value
) - B
.getAddress();
600 ? G
->addDefinedSymbol(B
, SymOffset
, *NSym
.Name
, Size
, NSym
.L
, NSym
.S
,
601 IsText
, IsNoDeadStrip
)
602 : G
->addAnonymousSymbol(B
, SymOffset
, Size
, IsText
, IsNoDeadStrip
);
603 NSym
.GraphSymbol
= &Sym
;
606 setCanonicalSymbol(getSectionByIndex(NSym
.Sect
- 1), Sym
);
611 Error
MachOLinkGraphBuilder::graphifySectionsWithCustomParsers() {
612 // Graphify special sections.
613 for (auto &KV
: IndexToSection
) {
614 auto &NSec
= KV
.second
;
616 // Skip non-graph sections.
617 if (!NSec
.GraphSection
)
620 auto HI
= CustomSectionParserFunctions
.find(NSec
.GraphSection
->getName());
621 if (HI
!= CustomSectionParserFunctions
.end()) {
622 auto &Parse
= HI
->second
;
623 if (auto Err
= Parse(NSec
))
628 return Error::success();
631 Error
MachOLinkGraphBuilder::graphifyCStringSection(
632 NormalizedSection
&NSec
, std::vector
<NormalizedSymbol
*> NSyms
) {
633 assert(NSec
.GraphSection
&& "C string literal section missing graph section");
634 assert(NSec
.Data
&& "C string literal section has no data");
637 dbgs() << " Graphifying C-string literal section "
638 << NSec
.GraphSection
->getName() << "\n";
641 if (NSec
.Data
[NSec
.Size
- 1] != '\0')
642 return make_error
<JITLinkError
>("C string literal section " +
643 NSec
.GraphSection
->getName() +
644 " does not end with null terminator");
646 /// Sort into reverse order to use as a stack.
648 [](const NormalizedSymbol
*LHS
, const NormalizedSymbol
*RHS
) {
649 if (LHS
->Value
!= RHS
->Value
)
650 return LHS
->Value
> RHS
->Value
;
651 if (LHS
->L
!= RHS
->L
)
652 return LHS
->L
> RHS
->L
;
653 if (LHS
->S
!= RHS
->S
)
654 return LHS
->S
> RHS
->S
;
658 return *LHS
->Name
> *RHS
->Name
;
663 bool SectionIsNoDeadStrip
= NSec
.Flags
& MachO::S_ATTR_NO_DEAD_STRIP
;
664 bool SectionIsText
= NSec
.Flags
& MachO::S_ATTR_PURE_INSTRUCTIONS
;
665 orc::ExecutorAddrDiff BlockStart
= 0;
667 // Scan section for null characters.
668 for (size_t I
= 0; I
!= NSec
.Size
; ++I
) {
669 if (NSec
.Data
[I
] == '\0') {
670 size_t BlockSize
= I
+ 1 - BlockStart
;
671 // Create a block for this null terminated string.
672 auto &B
= G
->createContentBlock(*NSec
.GraphSection
,
673 {NSec
.Data
+ BlockStart
, BlockSize
},
674 NSec
.Address
+ BlockStart
, NSec
.Alignment
,
675 BlockStart
% NSec
.Alignment
);
678 dbgs() << " Created block " << B
.getRange()
679 << ", align = " << B
.getAlignment()
680 << ", align-ofs = " << B
.getAlignmentOffset() << " for \"";
681 for (size_t J
= 0; J
!= std::min(B
.getSize(), size_t(16)); ++J
)
682 switch (B
.getContent()[J
]) {
684 case '\n': dbgs() << "\\n"; break;
685 case '\t': dbgs() << "\\t"; break;
686 default: dbgs() << B
.getContent()[J
]; break;
688 if (B
.getSize() > 16)
693 // If there's no symbol at the start of this block then create one.
695 orc::ExecutorAddr(NSyms
.back()->Value
) != B
.getAddress()) {
696 auto &S
= G
->addAnonymousSymbol(B
, 0, BlockSize
, false, false);
697 setCanonicalSymbol(NSec
, S
);
699 dbgs() << " Adding symbol for c-string block " << B
.getRange()
700 << ": <anonymous symbol> at offset 0\n";
704 // Process any remaining symbols that point into this block.
705 auto LastCanonicalAddr
= B
.getAddress() + BlockSize
;
706 while (!NSyms
.empty() && orc::ExecutorAddr(NSyms
.back()->Value
) <
707 B
.getAddress() + BlockSize
) {
708 auto &NSym
= *NSyms
.back();
709 size_t SymSize
= (B
.getAddress() + BlockSize
) -
710 orc::ExecutorAddr(NSyms
.back()->Value
);
712 (NSym
.Desc
& MachO::N_NO_DEAD_STRIP
) || SectionIsNoDeadStrip
;
714 bool IsCanonical
= false;
715 if (LastCanonicalAddr
!= orc::ExecutorAddr(NSym
.Value
)) {
717 LastCanonicalAddr
= orc::ExecutorAddr(NSym
.Value
);
720 auto &Sym
= createStandardGraphSymbol(NSym
, B
, SymSize
, SectionIsText
,
721 SymLive
, IsCanonical
);
724 dbgs() << " Adding symbol for c-string block " << B
.getRange()
726 << (Sym
.hasName() ? Sym
.getName() : "<anonymous symbol>")
727 << " at offset " << formatv("{0:x}", Sym
.getOffset()) << "\n";
733 BlockStart
+= BlockSize
;
737 assert(llvm::all_of(NSec
.GraphSection
->blocks(),
738 [](Block
*B
) { return isCStringBlock(*B
); }) &&
739 "All blocks in section should hold single c-strings");
741 return Error::success();
744 Error
CompactUnwindSplitter::operator()(LinkGraph
&G
) {
745 auto *CUSec
= G
.findSectionByName(CompactUnwindSectionName
);
747 return Error::success();
749 if (!G
.getTargetTriple().isOSBinFormatMachO())
750 return make_error
<JITLinkError
>(
751 "Error linking " + G
.getName() +
752 ": compact unwind splitting not supported on non-macho target " +
753 G
.getTargetTriple().str());
755 unsigned CURecordSize
= 0;
756 unsigned PersonalityEdgeOffset
= 0;
757 unsigned LSDAEdgeOffset
= 0;
758 switch (G
.getTargetTriple().getArch()) {
759 case Triple::aarch64
:
761 // 64-bit compact-unwind record format:
762 // Range start: 8 bytes.
763 // Range size: 4 bytes.
764 // CU encoding: 4 bytes.
765 // Personality: 8 bytes.
768 PersonalityEdgeOffset
= 16;
772 return make_error
<JITLinkError
>(
773 "Error linking " + G
.getName() +
774 ": compact unwind splitting not supported on " +
775 G
.getTargetTriple().getArchName());
778 std::vector
<Block
*> OriginalBlocks(CUSec
->blocks().begin(),
779 CUSec
->blocks().end());
781 dbgs() << "In " << G
.getName() << " splitting compact unwind section "
782 << CompactUnwindSectionName
<< " containing "
783 << OriginalBlocks
.size() << " initial blocks...\n";
786 while (!OriginalBlocks
.empty()) {
787 auto *B
= OriginalBlocks
.back();
788 OriginalBlocks
.pop_back();
790 if (B
->getSize() == 0) {
792 dbgs() << " Skipping empty block at "
793 << formatv("{0:x16}", B
->getAddress()) << "\n";
799 dbgs() << " Splitting block at " << formatv("{0:x16}", B
->getAddress())
800 << " into " << (B
->getSize() / CURecordSize
)
801 << " compact unwind record(s)\n";
804 if (B
->getSize() % CURecordSize
)
805 return make_error
<JITLinkError
>(
806 "Error splitting compact unwind record in " + G
.getName() +
807 ": block at " + formatv("{0:x}", B
->getAddress()) + " has size " +
808 formatv("{0:x}", B
->getSize()) +
809 " (not a multiple of CU record size of " +
810 formatv("{0:x}", CURecordSize
) + ")");
812 unsigned NumBlocks
= B
->getSize() / CURecordSize
;
813 LinkGraph::SplitBlockCache C
;
815 for (unsigned I
= 0; I
!= NumBlocks
; ++I
) {
816 auto &CURec
= G
.splitBlock(*B
, CURecordSize
, &C
);
817 bool AddedKeepAlive
= false;
819 for (auto &E
: CURec
.edges()) {
820 if (E
.getOffset() == 0) {
822 dbgs() << " Updating compact unwind record at "
823 << formatv("{0:x16}", CURec
.getAddress()) << " to point to "
824 << (E
.getTarget().hasName() ? E
.getTarget().getName()
826 << " (at " << formatv("{0:x16}", E
.getTarget().getAddress())
830 if (E
.getTarget().isExternal())
831 return make_error
<JITLinkError
>(
832 "Error adding keep-alive edge for compact unwind record at " +
833 formatv("{0:x}", CURec
.getAddress()) + ": target " +
834 E
.getTarget().getName() + " is an external symbol");
835 auto &TgtBlock
= E
.getTarget().getBlock();
837 G
.addAnonymousSymbol(CURec
, 0, CURecordSize
, false, false);
838 TgtBlock
.addEdge(Edge::KeepAlive
, 0, CURecSym
, 0);
839 AddedKeepAlive
= true;
840 } else if (E
.getOffset() != PersonalityEdgeOffset
&&
841 E
.getOffset() != LSDAEdgeOffset
)
842 return make_error
<JITLinkError
>("Unexpected edge at offset " +
843 formatv("{0:x}", E
.getOffset()) +
844 " in compact unwind record at " +
845 formatv("{0:x}", CURec
.getAddress()));
849 return make_error
<JITLinkError
>(
850 "Error adding keep-alive edge for compact unwind record at " +
851 formatv("{0:x}", CURec
.getAddress()) +
852 ": no outgoing target edge at offset 0");
855 return Error::success();
858 } // end namespace jitlink
859 } // end namespace llvm