16 #define DEBUG_TYPE "jitlink"
29 return make_error<JITLinkError>(
"Object is not a relocatable MachO");
31 if (
auto Err = createNormalizedSections())
34 if (
auto Err = createNormalizedSymbols())
37 if (
auto Err = graphifyRegularSymbols())
40 if (
auto Err = graphifySectionsWithCustomParsers())
55 getEndianness(Obj),
std::
move(GetEdgeKindName))) {
63 "Custom parser for this section already exists");
89 strcmp(NSec.
SegName,
"__DWARF") == 0);
113 Section &MachOLinkGraphBuilder::getCommonSection() {
117 return *CommonSection;
120 Error MachOLinkGraphBuilder::createNormalizedSections() {
126 for (
auto &SecRef : Obj.
sections()) {
127 NormalizedSection NSec;
133 const MachO::section_64 &Sec64 =
136 memcpy(&NSec.SectName, &Sec64.sectname, 16);
137 NSec.SectName[16] =
'\0';
138 memcpy(&NSec.SegName, Sec64.segname, 16);
139 NSec.SegName[16] =
'\0';
141 NSec.Address = orc::ExecutorAddr(Sec64.addr);
142 NSec.Size = Sec64.size;
143 NSec.Alignment = 1ULL << Sec64.align;
144 NSec.Flags = Sec64.flags;
145 DataOffset = Sec64.offset;
147 const MachO::section &Sec32 = Obj.
getSection(SecRef.getRawDataRefImpl());
149 memcpy(&NSec.SectName, &Sec32.sectname, 16);
150 NSec.SectName[16] =
'\0';
151 memcpy(&NSec.SegName, Sec32.segname, 16);
152 NSec.SegName[16] =
'\0';
154 NSec.Address = orc::ExecutorAddr(Sec32.addr);
155 NSec.Size = Sec32.size;
156 NSec.Alignment = 1ULL << Sec32.align;
157 NSec.Flags = Sec32.flags;
158 DataOffset = Sec32.offset;
162 dbgs() <<
" " << NSec.SegName <<
"," << NSec.SectName <<
": "
163 <<
formatv(
"{0:x16}", NSec.Address) <<
" -- "
164 <<
formatv(
"{0:x16}", NSec.Address + NSec.Size)
165 <<
", align: " << NSec.Alignment <<
", index: " << SecIndex
172 return make_error<JITLinkError>(
173 "Section data extends past end of file");
187 auto FullyQualifiedName =
188 G->allocateString(StringRef(NSec.SegName) +
"," + NSec.SectName);
189 NSec.GraphSection = &G->createSection(
190 StringRef(FullyQualifiedName.data(), FullyQualifiedName.size()), Prot);
192 IndexToSection.insert(std::make_pair(SecIndex,
std::move(NSec)));
195 std::vector<NormalizedSection *> Sections;
196 Sections.reserve(IndexToSection.size());
197 for (
auto &KV : IndexToSection)
198 Sections.push_back(&KV.second);
202 if (Sections.empty())
206 [](
const NormalizedSection *
LHS,
const NormalizedSection *
RHS) {
208 if (
LHS->Address !=
RHS->Address)
209 return LHS->Address <
RHS->Address;
210 return LHS->Size <
RHS->Size;
213 for (
unsigned I = 0,
E = Sections.size() - 1;
I !=
E; ++
I) {
214 auto &Cur = *Sections[
I];
215 auto &Next = *Sections[
I + 1];
216 if (Next.Address < Cur.Address + Cur.Size)
217 return make_error<JITLinkError>(
218 "Address range for section " +
219 formatv(
"\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Cur.SegName,
220 Cur.SectName, Cur.Address, Cur.Address + Cur.Size) +
221 "overlaps section \"" + Next.SegName +
"/" + Next.SectName +
"\"" +
222 formatv(
"\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Next.SegName,
223 Next.SectName, Next.Address, Next.Address + Next.Size));
229 Error MachOLinkGraphBuilder::createNormalizedSymbols() {
232 for (
auto &SymRef : Obj.
symbols()) {
234 unsigned SymbolIndex = Obj.
getSymbolIndex(SymRef.getRawDataRefImpl());
242 const MachO::nlist_64 &NL64 =
244 Value = NL64.n_value;
250 const MachO::nlist &NL32 =
252 Value = NL32.n_value;
264 std::optional<StringRef>
Name;
266 if (
auto NameOrErr = SymRef.getName())
269 return NameOrErr.takeError();
275 dbgs() <<
"<anonymous symbol>";
279 <<
", type = " <<
formatv(
"{0:x2}", Type)
280 <<
", desc = " <<
formatv(
"{0:x4}", Desc) <<
", sect = ";
282 dbgs() <<
static_cast<unsigned>(Sect - 1);
292 return NSec.takeError();
294 if (orc::ExecutorAddr(
Value) < NSec->Address ||
295 orc::ExecutorAddr(
Value) > NSec->Address + NSec->Size)
296 return make_error<JITLinkError>(
"Address " +
formatv(
"{0:x}",
Value) +
297 " for symbol " + *Name +
298 " does not fall within section");
300 if (!NSec->GraphSection) {
302 dbgs() <<
" Skipping: Symbol is in section " << NSec->SegName <<
"/"
304 <<
" which has no associated graph section.\n";
310 IndexToSymbol[SymbolIndex] =
318 void MachOLinkGraphBuilder::addSectionStartSymAndBlock(
319 unsigned SecIndex, Section &GraphSec, orc::ExecutorAddr Address,
323 Data ? G->createContentBlock(GraphSec, ArrayRef<char>(Data, Size),
324 Address, Alignment, 0)
325 : G->createZeroFillBlock(GraphSec, Size, Address, Alignment, 0);
326 auto &Sym = G->addAnonymousSymbol(
B, 0, Size,
false, IsLive);
327 auto SecI = IndexToSection.find(SecIndex);
328 assert(SecI != IndexToSection.end() &&
"SecIndex invalid");
329 auto &NSec = SecI->second;
330 assert(!NSec.CanonicalSymbols.count(Sym.getAddress()) &&
331 "Anonymous block start symbol clashes with existing symbol address");
332 NSec.CanonicalSymbols[Sym.getAddress()] = &Sym;
335 Error MachOLinkGraphBuilder::graphifyRegularSymbols() {
340 std::vector<std::vector<NormalizedSymbol *>> SecIndexToSymbols;
341 SecIndexToSymbols.resize(256);
345 for (
auto &KV : IndexToSymbol) {
346 auto &NSym = *KV.second;
352 return make_error<JITLinkError>(
"Anonymous common symbol at index " +
354 NSym.GraphSymbol = &G->addDefinedSymbol(
355 G->createZeroFillBlock(getCommonSection(),
363 return make_error<JITLinkError>(
"Anonymous external symbol at "
366 NSym.GraphSymbol = &G->addExternalSymbol(
372 return make_error<JITLinkError>(
"Anonymous absolute symbol at index " +
374 NSym.GraphSymbol = &G->addAbsoluteSymbol(
379 SecIndexToSymbols[NSym.Sect - 1].push_back(&NSym);
382 return make_error<JITLinkError>(
383 "Unupported N_PBUD symbol " +
384 (NSym.Name ? (
"\"" + *NSym.Name +
"\"") : Twine(
"<anon>")) +
385 " at index " + Twine(KV.first));
387 return make_error<JITLinkError>(
388 "Unupported N_INDR symbol " +
389 (NSym.Name ? (
"\"" + *NSym.Name +
"\"") : Twine(
"<anon>")) +
390 " at index " + Twine(KV.first));
392 return make_error<JITLinkError>(
393 "Unrecognized symbol type " + Twine(NSym.Type &
MachO::N_TYPE) +
395 (NSym.Name ? (
"\"" + *NSym.Name +
"\"") : Twine(
"<anon>")) +
396 " at index " + Twine(KV.first));
402 for (
auto &KV : IndexToSection) {
403 auto SecIndex = KV.first;
404 auto &NSec = KV.second;
406 if (!NSec.GraphSection) {
408 dbgs() <<
" " << NSec.SegName <<
"/" << NSec.SectName
409 <<
" has no graph section. Skipping.\n";
415 if (CustomSectionParserFunctions.
count(NSec.GraphSection->getName())) {
417 dbgs() <<
" Skipping section " << NSec.GraphSection->getName()
418 <<
" as it has a custom parser.\n";
423 if (
auto Err = graphifyCStringSection(
424 NSec,
std::move(SecIndexToSymbols[SecIndex])))
429 dbgs() <<
" Graphifying regular section "
430 << NSec.GraphSection->getName() <<
"...\n";
436 auto &SecNSymStack = SecIndexToSymbols[SecIndex];
440 if (SecNSymStack.empty()) {
443 dbgs() <<
" Section non-empty, but contains no symbols. "
444 "Creating anonymous block to cover "
445 <<
formatv(
"{0:x16}", NSec.Address) <<
" -- "
446 <<
formatv(
"{0:x16}", NSec.Address + NSec.Size) <<
"\n";
448 addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address,
449 NSec.Data, NSec.Size, NSec.Alignment,
450 SectionIsNoDeadStrip);
453 dbgs() <<
" Section empty and contains no symbols. Skipping.\n";
462 const NormalizedSymbol *
RHS) {
463 if (
LHS->Value !=
RHS->Value)
464 return LHS->Value >
RHS->Value;
468 return static_cast<uint8_t
>(
LHS->S) <
static_cast<uint8_t
>(
RHS->S);
469 return LHS->Name <
RHS->Name;
473 if (!SecNSymStack.empty() &&
isAltEntry(*SecNSymStack.back()))
474 return make_error<JITLinkError>(
475 "First symbol in " + NSec.GraphSection->getName() +
" is alt-entry");
479 if (orc::ExecutorAddr(SecNSymStack.back()->Value) != NSec.Address) {
481 orc::ExecutorAddr(SecNSymStack.back()->Value) - NSec.Address;
483 dbgs() <<
" Section start not covered by symbol. "
484 <<
"Creating anonymous block to cover [ " << NSec.Address
485 <<
" -- " << (NSec.Address + AnonBlockSize) <<
" ]\n";
487 addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address,
488 NSec.Data, AnonBlockSize, NSec.Alignment,
489 SectionIsNoDeadStrip);
500 while (!SecNSymStack.empty()) {
501 SmallVector<NormalizedSymbol *, 8> BlockSyms;
505 BlockSyms.push_back(SecNSymStack.back());
506 SecNSymStack.pop_back();
507 while (!SecNSymStack.empty() &&
509 SecNSymStack.back()->Value == BlockSyms.back()->Value ||
510 !SubsectionsViaSymbols)) {
511 BlockSyms.push_back(SecNSymStack.back());
512 SecNSymStack.pop_back();
516 auto BlockStart = orc::ExecutorAddr(BlockSyms.front()->Value);
517 orc::ExecutorAddr BlockEnd =
518 SecNSymStack.empty() ? NSec.Address + NSec.Size
519 : orc::ExecutorAddr(SecNSymStack.back()->Value);
524 dbgs() <<
" Creating block for " <<
formatv(
"{0:x16}", BlockStart)
525 <<
" -- " <<
formatv(
"{0:x16}", BlockEnd) <<
": "
526 << NSec.GraphSection->getName() <<
" + "
527 <<
formatv(
"{0:x16}", BlockOffset) <<
" with "
528 << BlockSyms.size() <<
" symbol(s)...\n";
533 ? G->createContentBlock(
535 ArrayRef<char>(NSec.Data + BlockOffset,
BlockSize),
536 BlockStart, NSec.Alignment, BlockStart % NSec.Alignment)
537 : G->createZeroFillBlock(*NSec.GraphSection,
BlockSize,
538 BlockStart, NSec.Alignment,
539 BlockStart % NSec.Alignment);
541 std::optional<orc::ExecutorAddr> LastCanonicalAddr;
542 auto SymEnd = BlockEnd;
543 while (!BlockSyms.empty()) {
544 auto &NSym = *BlockSyms.back();
545 BlockSyms.pop_back();
550 auto &Sym = createStandardGraphSymbol(
551 NSym,
B, SymEnd - orc::ExecutorAddr(NSym.Value), SectionIsText,
552 SymLive, LastCanonicalAddr != orc::ExecutorAddr(NSym.Value));
554 if (LastCanonicalAddr != Sym.getAddress()) {
555 if (LastCanonicalAddr)
556 SymEnd = *LastCanonicalAddr;
557 LastCanonicalAddr = Sym.getAddress();
566 Symbol &MachOLinkGraphBuilder::createStandardGraphSymbol(NormalizedSymbol &NSym,
567 Block &
B,
size_t Size,
573 dbgs() <<
" " <<
formatv(
"{0:x16}", NSym.Value) <<
" -- "
574 <<
formatv(
"{0:x16}", NSym.Value + Size) <<
": ";
576 dbgs() <<
"<anonymous symbol>";
582 dbgs() <<
" [no-dead-strip]";
584 dbgs() <<
" [non-canonical]";
588 auto SymOffset = orc::ExecutorAddr(NSym.Value) -
B.getAddress();
591 ? G->addDefinedSymbol(
B, SymOffset, *NSym.Name, Size, NSym.L, NSym.S,
592 IsText, IsNoDeadStrip)
593 : G->addAnonymousSymbol(
B, SymOffset, Size, IsText, IsNoDeadStrip);
594 NSym.GraphSymbol = &Sym;
602 Error MachOLinkGraphBuilder::graphifySectionsWithCustomParsers() {
604 for (
auto &KV : IndexToSection) {
605 auto &NSec = KV.second;
608 if (!NSec.GraphSection)
611 auto HI = CustomSectionParserFunctions.
find(NSec.GraphSection->getName());
612 if (
HI != CustomSectionParserFunctions.
end()) {
613 auto &Parse =
HI->second;
614 if (
auto Err = Parse(NSec))
622 Error MachOLinkGraphBuilder::graphifyCStringSection(
623 NormalizedSection &NSec, std::vector<NormalizedSymbol *> NSyms) {
624 assert(NSec.GraphSection &&
"C string literal section missing graph section");
625 assert(NSec.Data &&
"C string literal section has no data");
628 dbgs() <<
" Graphifying C-string literal section "
629 << NSec.GraphSection->getName() <<
"\n";
632 if (NSec.Data[NSec.Size - 1] !=
'\0')
633 return make_error<JITLinkError>(
"C string literal section " +
634 NSec.GraphSection->getName() +
635 " does not end with null terminator");
639 [](
const NormalizedSymbol *
LHS,
const NormalizedSymbol *
RHS) {
640 if (
LHS->Value !=
RHS->Value)
641 return LHS->Value >
RHS->Value;
649 return *LHS->Name > *RHS->Name;
659 for (
size_t I = 0;
I != NSec.Size; ++
I)
660 if (NSec.Data[
I] ==
'\0') {
663 auto &
B = G->createContentBlock(*NSec.GraphSection,
664 {NSec.Data + BlockStart, BlockSize},
665 NSec.Address + BlockStart, NSec.Alignment,
666 BlockStart % NSec.Alignment);
669 dbgs() <<
" Created block " <<
B.getRange()
670 <<
", align = " <<
B.getAlignment()
671 <<
", align-ofs = " <<
B.getAlignmentOffset() <<
" for \"";
672 for (
size_t J = 0; J !=
std::min(
B.getSize(),
size_t(16)); ++J)
673 switch (
B.getContent()[J]) {
675 case '\n':
dbgs() <<
"\\n";
break;
676 case '\t':
dbgs() <<
"\\t";
break;
677 default:
dbgs() <<
B.getContent()[J];
break;
679 if (
B.getSize() > 16)
686 orc::ExecutorAddr(NSyms.back()->Value) !=
B.getAddress()) {
687 auto &
S = G->addAnonymousSymbol(
B, 0,
BlockSize,
false,
false);
688 setCanonicalSymbol(NSec,
S);
690 dbgs() <<
" Adding symbol for c-string block " <<
B.getRange()
691 <<
": <anonymous symbol> at offset 0\n";
696 auto LastCanonicalAddr =
B.getAddress() +
BlockSize;
697 while (!NSyms.empty() && orc::ExecutorAddr(NSyms.back()->Value) <
699 auto &NSym = *NSyms.back();
700 size_t SymSize = (
B.getAddress() +
BlockSize) -
701 orc::ExecutorAddr(NSyms.back()->Value);
705 bool IsCanonical =
false;
706 if (LastCanonicalAddr != orc::ExecutorAddr(NSym.Value)) {
708 LastCanonicalAddr = orc::ExecutorAddr(NSym.Value);
711 auto &Sym = createStandardGraphSymbol(NSym,
B, SymSize, SectionIsText,
712 SymLive, IsCanonical);
715 dbgs() <<
" Adding symbol for c-string block " <<
B.getRange()
717 << (Sym.hasName() ? Sym.getName() :
"<anonymous symbol>")
718 <<
" at offset " <<
formatv(
"{0:x}", Sym.getOffset()) <<
"\n";
731 auto *CUSec =
G.findSectionByName(CompactUnwindSectionName);
735 if (!
G.getTargetTriple().isOSBinFormatMachO())
736 return make_error<JITLinkError>(
737 "Error linking " +
G.getName() +
738 ": compact unwind splitting not supported on non-macho target " +
739 G.getTargetTriple().str());
741 unsigned CURecordSize = 0;
742 unsigned PersonalityEdgeOffset = 0;
743 unsigned LSDAEdgeOffset = 0;
744 switch (
G.getTargetTriple().getArch()) {
754 PersonalityEdgeOffset = 16;
758 return make_error<JITLinkError>(
759 "Error linking " +
G.getName() +
760 ": compact unwind splitting not supported on " +
761 G.getTargetTriple().getArchName());
764 std::vector<Block *> OriginalBlocks(CUSec->blocks().begin(),
765 CUSec->blocks().end());
767 dbgs() <<
"In " <<
G.getName() <<
" splitting compact unwind section "
768 << CompactUnwindSectionName <<
" containing "
769 << OriginalBlocks.
size() <<
" initial blocks...\n";
772 while (!OriginalBlocks.empty()) {
773 auto *
B = OriginalBlocks.back();
774 OriginalBlocks.pop_back();
776 if (
B->getSize() == 0) {
778 dbgs() <<
" Skipping empty block at "
779 <<
formatv(
"{0:x16}",
B->getAddress()) <<
"\n";
785 dbgs() <<
" Splitting block at " <<
formatv(
"{0:x16}",
B->getAddress())
786 <<
" into " << (
B->getSize() / CURecordSize)
787 <<
" compact unwind record(s)\n";
790 if (
B->getSize() % CURecordSize)
791 return make_error<JITLinkError>(
792 "Error splitting compact unwind record in " +
G.getName() +
793 ": block at " +
formatv(
"{0:x}",
B->getAddress()) +
" has size " +
795 " (not a multiple of CU record size of " +
796 formatv(
"{0:x}", CURecordSize) +
")");
798 unsigned NumBlocks =
B->getSize() / CURecordSize;
801 for (
unsigned I = 0;
I != NumBlocks; ++
I) {
802 auto &CURec =
G.splitBlock(*
B, CURecordSize, &
C);
803 bool AddedKeepAlive =
false;
805 for (
auto &
E : CURec.edges()) {
806 if (
E.getOffset() == 0) {
808 dbgs() <<
" Updating compact unwind record at "
809 <<
formatv(
"{0:x16}", CURec.getAddress()) <<
" to point to "
810 << (
E.getTarget().hasName() ?
E.getTarget().getName()
812 <<
" (at " <<
formatv(
"{0:x16}",
E.getTarget().getAddress())
816 if (
E.getTarget().isExternal())
817 return make_error<JITLinkError>(
818 "Error adding keep-alive edge for compact unwind record at " +
819 formatv(
"{0:x}", CURec.getAddress()) +
": target " +
820 E.getTarget().getName() +
" is an external symbol");
821 auto &TgtBlock =
E.getTarget().getBlock();
823 G.addAnonymousSymbol(CURec, 0, CURecordSize,
false,
false);
825 AddedKeepAlive =
true;
826 }
else if (
E.getOffset() != PersonalityEdgeOffset &&
827 E.getOffset() != LSDAEdgeOffset)
828 return make_error<JITLinkError>(
"Unexpected edge at offset " +
830 " in compact unwind record at " +
831 formatv(
"{0:x}", CURec.getAddress()));
835 return make_error<JITLinkError>(
836 "Error adding keep-alive edge for compact unwind record at " +
837 formatv(
"{0:x}", CURec.getAddress()) +
838 ": no outgoing target edge at offset 0");