17#define DEBUG_TYPE "jitlink"
29 if (!Obj.isRelocatableObject())
32 if (
auto Err = createNormalizedSections())
33 return std::move(Err);
35 if (
auto Err = createNormalizedSymbols())
36 return std::move(Err);
38 if (
auto Err = graphifyRegularSymbols())
39 return std::move(Err);
41 if (
auto Err = graphifySectionsWithCustomParsers())
42 return std::move(Err);
45 return std::move(Err);
52 std::shared_ptr<orc::SymbolStringPool> SSP,
Triple TT,
59 auto &MachHeader = Obj.getHeader64();
66 "Custom parser for this section already exists");
67 CustomSectionParserFunctions[
SectionName] = std::move(Parser);
92 strcmp(NSec.
SegName,
"__DWARF") == 0);
106Section &MachOLinkGraphBuilder::getCommonSection() {
110 return *CommonSection;
113Error MachOLinkGraphBuilder::createNormalizedSections() {
119 for (
auto &SecRef : Obj.
sections()) {
120 NormalizedSection NSec;
129 memcpy(&NSec.SectName, &Sec64.
sectname, 16);
130 NSec.SectName[16] =
'\0';
131 memcpy(&NSec.SegName, Sec64.
segname, 16);
132 NSec.SegName[16] =
'\0';
135 NSec.Size = Sec64.
size;
136 NSec.Alignment = 1ULL << Sec64.
align;
137 NSec.Flags = Sec64.
flags;
138 DataOffset = Sec64.
offset;
140 const MachO::section &Sec32 = Obj.
getSection(SecRef.getRawDataRefImpl());
142 memcpy(&NSec.SectName, &Sec32.sectname, 16);
143 NSec.SectName[16] =
'\0';
144 memcpy(&NSec.SegName, Sec32.segname, 16);
145 NSec.SegName[16] =
'\0';
147 NSec.Address = orc::ExecutorAddr(Sec32.addr);
148 NSec.Size = Sec32.size;
149 NSec.Alignment = 1ULL << Sec32.align;
150 NSec.Flags = Sec32.flags;
151 DataOffset = Sec32.offset;
155 dbgs() <<
" " << NSec.SegName <<
"," << NSec.SectName <<
": "
156 <<
formatv(
"{0:x16}", NSec.Address) <<
" -- "
157 <<
formatv(
"{0:x16}", NSec.Address + NSec.Size)
158 <<
", align: " << NSec.Alignment <<
", index: " << SecIndex
164 if (DataOffset + NSec.Size > Obj.getData().size())
166 "Section data extends past end of file");
168 NSec.Data = Obj.getData().data() + DataOffset;
180 auto FullyQualifiedName =
181 G->allocateContent(StringRef(NSec.SegName) +
"," + NSec.SectName);
182 NSec.GraphSection = &G->createSection(
183 StringRef(FullyQualifiedName.data(), FullyQualifiedName.size()), Prot);
189 IndexToSection.insert(std::make_pair(SecIndex, std::move(NSec)));
192 std::vector<NormalizedSection *> Sections;
193 Sections.reserve(IndexToSection.size());
194 for (
auto &KV : IndexToSection)
195 Sections.push_back(&KV.second);
199 if (Sections.empty())
205 return std::tie(
LHS->Address,
LHS->Size) <
206 std::tie(
RHS->Address,
RHS->Size);
209 for (
unsigned I = 0,
E = Sections.size() - 1;
I !=
E; ++
I) {
210 auto &Cur = *Sections[
I];
211 auto &
Next = *Sections[
I + 1];
212 if (
Next.Address < Cur.Address + Cur.Size)
214 "Address range for section " +
215 formatv(
"\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Cur.SegName,
216 Cur.SectName, Cur.Address, Cur.Address + Cur.Size) +
217 "overlaps section \"" +
Next.SegName +
"/" +
Next.SectName +
"\"" +
218 formatv(
"\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ",
Next.SegName,
225Error MachOLinkGraphBuilder::createNormalizedSymbols() {
228 for (
auto &SymRef : Obj.symbols()) {
230 unsigned SymbolIndex = Obj.getSymbolIndex(SymRef.getRawDataRefImpl());
238 const MachO::nlist_64 &NL64 =
239 Obj.getSymbol64TableEntry(SymRef.getRawDataRefImpl());
240 Value = NL64.n_value;
246 const MachO::nlist &NL32 =
247 Obj.getSymbolTableEntry(SymRef.getRawDataRefImpl());
248 Value = NL32.n_value;
260 std::optional<StringRef>
Name;
262 if (
auto NameOrErr = SymRef.getName())
265 return NameOrErr.takeError();
269 " has no name (string table index 0), "
270 "but N_EXT bit is set");
275 dbgs() <<
"<anonymous symbol>";
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)
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";
317void MachOLinkGraphBuilder::addSectionStartSymAndBlock(
322 Data ? G->createContentBlock(GraphSec, ArrayRef<char>(
Data,
Size),
324 : G->createZeroFillBlock(GraphSec,
Size,
Address, Alignment, 0);
325 auto &Sym = G->addAnonymousSymbol(
B, 0,
Size,
false, IsLive);
326 auto SecI = IndexToSection.find(SecIndex);
327 assert(SecI != IndexToSection.end() &&
"SecIndex invalid");
328 auto &NSec = SecI->second;
329 assert(!NSec.CanonicalSymbols.count(Sym.getAddress()) &&
330 "Anonymous block start symbol clashes with existing symbol address");
331 NSec.CanonicalSymbols[Sym.getAddress()] = &Sym;
334Error MachOLinkGraphBuilder::graphifyRegularSymbols() {
339 std::vector<std::vector<NormalizedSymbol *>> SecIndexToSymbols;
340 SecIndexToSymbols.resize(256);
344 for (
auto &KV : IndexToSymbol) {
345 auto &NSym = *KV.second;
353 NSym.GraphSymbol = &G->addDefinedSymbol(
354 G->createZeroFillBlock(getCommonSection(),
365 NSym.GraphSymbol = &G->addExternalSymbol(
373 NSym.GraphSymbol = &G->addAbsoluteSymbol(
378 SecIndexToSymbols[NSym.Sect - 1].push_back(&NSym);
382 "Unupported N_PBUD symbol " +
383 (NSym.Name ? (
"\"" + *NSym.Name +
"\"") : Twine(
"<anon>")) +
384 " at index " + Twine(KV.first));
387 "Unupported N_INDR symbol " +
388 (NSym.Name ? (
"\"" + *NSym.Name +
"\"") : Twine(
"<anon>")) +
389 " at index " + Twine(KV.first));
392 "Unrecognized symbol type " + Twine(NSym.Type &
MachO::N_TYPE) +
394 (NSym.Name ? (
"\"" + *NSym.Name +
"\"") : Twine(
"<anon>")) +
395 " at index " + Twine(KV.first));
401 for (
auto &KV : IndexToSection) {
402 auto SecIndex = KV.first;
403 auto &NSec = KV.second;
405 if (!NSec.GraphSection) {
407 dbgs() <<
" " << NSec.SegName <<
"/" << NSec.SectName
408 <<
" has no graph section. Skipping.\n";
414 if (CustomSectionParserFunctions.count(NSec.GraphSection->getName())) {
416 dbgs() <<
" Skipping section " << NSec.GraphSection->getName()
417 <<
" as it has a custom parser.\n";
422 if (
auto Err = graphifyCStringSection(
423 NSec, std::move(SecIndexToSymbols[SecIndex])))
428 dbgs() <<
" Graphifying regular section "
429 << NSec.GraphSection->getName() <<
"...\n";
435 auto &SecNSymStack = SecIndexToSymbols[SecIndex];
439 if (SecNSymStack.empty()) {
442 dbgs() <<
" Section non-empty, but contains no symbols. "
443 "Creating anonymous block to cover "
444 <<
formatv(
"{0:x16}", NSec.Address) <<
" -- "
445 <<
formatv(
"{0:x16}", NSec.Address + NSec.Size) <<
"\n";
447 addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address,
448 NSec.Data, NSec.Size, NSec.Alignment,
449 SectionIsNoDeadStrip);
452 dbgs() <<
" Section empty and contains no symbols. Skipping.\n";
462 if (
LHS->Value !=
RHS->Value)
463 return LHS->Value >
RHS->Value;
467 return static_cast<uint8_t
>(
LHS->S) <
static_cast<uint8_t
>(
RHS->S);
468 return LHS->Name <
RHS->Name;
472 if (!SecNSymStack.empty() &&
isAltEntry(*SecNSymStack.back()))
474 "First symbol in " + NSec.GraphSection->getName() +
" is alt-entry");
478 if (orc::ExecutorAddr(SecNSymStack.back()->Value) != NSec.Address) {
480 orc::ExecutorAddr(SecNSymStack.back()->Value) - NSec.Address;
482 dbgs() <<
" Section start not covered by symbol. "
483 <<
"Creating anonymous block to cover [ " << NSec.Address
484 <<
" -- " << (NSec.Address + AnonBlockSize) <<
" ]\n";
486 addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address,
487 NSec.Data, AnonBlockSize, NSec.Alignment,
488 SectionIsNoDeadStrip);
499 while (!SecNSymStack.empty()) {
504 BlockSyms.push_back(SecNSymStack.back());
505 SecNSymStack.pop_back();
506 while (!SecNSymStack.empty() &&
508 SecNSymStack.back()->Value == BlockSyms.back()->Value ||
509 !SubsectionsViaSymbols)) {
510 BlockSyms.push_back(SecNSymStack.back());
511 SecNSymStack.pop_back();
515 auto BlockStart = orc::ExecutorAddr(BlockSyms.front()->Value);
516 orc::ExecutorAddr BlockEnd =
517 SecNSymStack.empty() ? NSec.Address + NSec.Size
518 : orc::ExecutorAddr(SecNSymStack.back()->Value);
523 dbgs() <<
" Creating block for " <<
formatv(
"{0:x16}", BlockStart)
524 <<
" -- " <<
formatv(
"{0:x16}", BlockEnd) <<
": "
525 << NSec.GraphSection->getName() <<
" + "
526 <<
formatv(
"{0:x16}", BlockOffset) <<
" with "
527 << BlockSyms.size() <<
" symbol(s)...\n";
532 ? G->createContentBlock(
534 ArrayRef<char>(NSec.Data + BlockOffset,
BlockSize),
535 BlockStart, NSec.Alignment, BlockStart % NSec.Alignment)
536 : G->createZeroFillBlock(*NSec.GraphSection,
BlockSize,
537 BlockStart, NSec.Alignment,
538 BlockStart % NSec.Alignment);
540 std::optional<orc::ExecutorAddr> LastCanonicalAddr;
541 auto SymEnd = BlockEnd;
542 while (!BlockSyms.empty()) {
543 auto &NSym = *BlockSyms.back();
544 BlockSyms.pop_back();
549 auto &Sym = createStandardGraphSymbol(
550 NSym,
B, SymEnd - orc::ExecutorAddr(NSym.Value), SectionIsText,
551 SymLive, LastCanonicalAddr != orc::ExecutorAddr(NSym.Value));
553 if (LastCanonicalAddr != Sym.getAddress()) {
554 if (LastCanonicalAddr)
555 SymEnd = *LastCanonicalAddr;
556 LastCanonicalAddr = Sym.getAddress();
565Symbol &MachOLinkGraphBuilder::createStandardGraphSymbol(NormalizedSymbol &NSym,
572 dbgs() <<
" " <<
formatv(
"{0:x16}", NSym.Value) <<
" -- "
575 dbgs() <<
"<anonymous symbol>";
577 dbgs() << *NSym.Name;
581 dbgs() <<
" [no-dead-strip]";
583 dbgs() <<
" [non-canonical]";
587 auto SymOffset = orc::ExecutorAddr(NSym.Value) -
B.
getAddress();
590 ? G->addDefinedSymbol(
B, SymOffset, *NSym.Name,
Size, NSym.L, NSym.S,
591 IsText, IsNoDeadStrip)
592 : G->addAnonymousSymbol(
B, SymOffset,
Size, IsText, IsNoDeadStrip);
593 NSym.GraphSymbol = &Sym;
601Error MachOLinkGraphBuilder::graphifySectionsWithCustomParsers() {
603 for (
auto &KV : IndexToSection) {
604 auto &NSec = KV.second;
607 if (!NSec.GraphSection)
610 auto HI = CustomSectionParserFunctions.find(NSec.GraphSection->getName());
611 if (HI != CustomSectionParserFunctions.end()) {
612 auto &Parse =
HI->second;
613 if (
auto Err = Parse(NSec))
621Error MachOLinkGraphBuilder::graphifyCStringSection(
622 NormalizedSection &NSec, std::vector<NormalizedSymbol *> NSyms) {
623 assert(NSec.GraphSection &&
"C string literal section missing graph section");
624 assert(NSec.Data &&
"C string literal section has no data");
627 dbgs() <<
" Graphifying C-string literal section "
628 << NSec.GraphSection->getName() <<
"\n";
631 if (NSec.Data[NSec.Size - 1] !=
'\0')
633 NSec.GraphSection->getName() +
634 " does not end with null terminator");
639 if (
LHS->Value !=
RHS->Value)
640 return LHS->Value >
RHS->Value;
648 return *
LHS->Name > *
RHS->Name;
658 for (
size_t I = 0;
I != NSec.Size; ++
I) {
659 if (NSec.Data[
I] ==
'\0') {
662 auto &
B = G->createContentBlock(*NSec.GraphSection,
663 {NSec.Data + BlockStart, BlockSize},
664 NSec.Address + BlockStart, NSec.Alignment,
665 BlockStart % NSec.Alignment);
668 dbgs() <<
" Created block " <<
B.getRange()
669 <<
", align = " <<
B.getAlignment()
670 <<
", align-ofs = " <<
B.getAlignmentOffset() <<
" for \"";
671 for (
size_t J = 0; J != std::min(
B.getSize(),
size_t(16)); ++J)
672 switch (
B.getContent()[J]) {
674 case '\n':
dbgs() <<
"\\n";
break;
675 case '\t':
dbgs() <<
"\\t";
break;
676 default:
dbgs() <<
B.getContent()[J];
break;
678 if (
B.getSize() > 16)
685 orc::ExecutorAddr(NSyms.back()->Value) !=
B.getAddress()) {
686 auto &S = G->addAnonymousSymbol(
B, 0,
BlockSize,
false,
false);
687 setCanonicalSymbol(NSec, S);
689 dbgs() <<
" Adding symbol for c-string block " <<
B.getRange()
690 <<
": <anonymous symbol> at offset 0\n";
695 auto LastCanonicalAddr =
B.getAddress() +
BlockSize;
696 while (!NSyms.empty() && orc::ExecutorAddr(NSyms.back()->Value) <
698 auto &NSym = *NSyms.back();
699 size_t SymSize = (
B.getAddress() +
BlockSize) -
700 orc::ExecutorAddr(NSyms.back()->Value);
704 bool IsCanonical =
false;
705 if (LastCanonicalAddr != orc::ExecutorAddr(NSym.Value)) {
707 LastCanonicalAddr = orc::ExecutorAddr(NSym.Value);
710 auto &Sym = createStandardGraphSymbol(NSym,
B, SymSize, SectionIsText,
711 SymLive, IsCanonical);
714 dbgs() <<
" Adding symbol for c-string block " <<
B.getRange()
716 << (Sym.hasName() ? *Sym.getName() :
"<anonymous symbol>")
717 <<
" at offset " <<
formatv(
"{0:x}", Sym.getOffset()) <<
"\n";
728 [](
Block *
B) { return isCStringBlock(*B); }) &&
729 "All blocks in section should hold single c-strings");
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static const char * CommonSectionName
static Expected< StringRef > getFileName(const DebugStringTableSubsectionRef &Strings, const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID)
static const int BlockSize
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Represent a constant reference to a string, i.e.
Manages the enabling and disabling of subtarget specific features.
Triple - Helper class for working with autoconf configuration names.
The instances of the Type class are immutable: once they are created, they are never changed.
An Addressable with content and edges.
const char *(*)(Edge::Kind) GetEdgeKindNameFunction
static bool isDebugSection(const NormalizedSection &NSec)
void addCustomSectionParser(StringRef SectionName, SectionParserFunction Parse)
virtual ~MachOLinkGraphBuilder()
virtual Error addRelocations()=0
std::function< Error(NormalizedSection &S)> SectionParserFunction
static Scope getScope(StringRef Name, uint8_t Type)
static bool isZeroFillSection(const NormalizedSection &NSec)
Expected< std::unique_ptr< LinkGraph > > buildGraph()
NormalizedSection & getSectionByIndex(unsigned Index)
Index is zero-based (MachO section indexes are usually one-based) and assumed to be in-range.
MachOLinkGraphBuilder(const object::MachOObjectFile &Obj, std::shared_ptr< orc::SymbolStringPool > SSP, Triple TT, SubtargetFeatures Features, LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
NormalizedSymbol & createNormalizedSymbol(ArgTs &&... Args)
Create a symbol.
static Linkage getLinkage(uint16_t Desc)
static bool isAltEntry(const NormalizedSymbol &NSym)
Expected< NormalizedSection & > findSectionByIndex(unsigned Index)
Try to get the section at the given index.
Represents an object file section.
orc::ExecutorAddr getAddress() const
Returns the address of this symbol.
Expected< SectionRef > getSection(unsigned SectionIndex) const
MachO::section_64 getSection64(DataRefImpl DRI) const
bool is64Bit() const override
uint64_t getSectionIndex(DataRefImpl Sec) const override
section_iterator_range sections() const
Represents an address in the executor process.
@ S_GB_ZEROFILL
S_GB_ZEROFILL - Zero fill on demand section (that can be larger than 4 gigabytes).
@ S_THREAD_LOCAL_ZEROFILL
S_THREAD_LOCAL_ZEROFILL - Thread local zerofill section.
@ S_CSTRING_LITERALS
S_CSTRING_LITERALS - Section with literal C strings.
@ S_ZEROFILL
S_ZEROFILL - Zero fill on demand section.
@ MH_SUBSECTIONS_VIA_SYMBOLS
uint8_t GET_COMM_ALIGN(uint16_t n_desc)
@ S_ATTR_DEBUG
S_ATTR_DEBUG - A debug section.
@ S_ATTR_NO_DEAD_STRIP
S_ATTR_NO_DEAD_STRIP - No dead stripping.
@ S_ATTR_PURE_INSTRUCTIONS
S_ATTR_PURE_INSTRUCTIONS - Section contains only true machine instructions.
Linkage
Describes symbol linkage. This can be used to resolve definition clashes.
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
MemProt
Describes Read/Write/Exec permissions for memory.
uint64_t ExecutorAddrDiff
@ NoAlloc
NoAlloc memory should not be allocated by the JITLinkMemoryManager at all.
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Implement std::hash so that hash_code can be used in STL containers.