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 buliding code.
11 //===----------------------------------------------------------------------===//
13 #include "MachOLinkGraphBuilder.h"
15 #define DEBUG_TYPE "jitlink"
17 static const char *CommonSectionName
= "__common";
22 MachOLinkGraphBuilder::~MachOLinkGraphBuilder() {}
24 Expected
<std::unique_ptr
<LinkGraph
>> MachOLinkGraphBuilder::buildGraph() {
26 // Sanity check: we only operate on relocatable objects.
27 if (!Obj
.isRelocatableObject())
28 return make_error
<JITLinkError
>("Object is not a relocatable MachO");
30 if (auto Err
= createNormalizedSections())
31 return std::move(Err
);
33 if (auto Err
= createNormalizedSymbols())
34 return std::move(Err
);
36 if (auto Err
= graphifyRegularSymbols())
37 return std::move(Err
);
39 if (auto Err
= graphifySectionsWithCustomParsers())
40 return std::move(Err
);
42 if (auto Err
= addRelocations())
43 return std::move(Err
);
48 MachOLinkGraphBuilder::MachOLinkGraphBuilder(const object::MachOObjectFile
&Obj
)
50 G(std::make_unique
<LinkGraph
>(Obj
.getFileName(), getPointerSize(Obj
),
51 getEndianness(Obj
))) {}
53 void MachOLinkGraphBuilder::addCustomSectionParser(
54 StringRef SectionName
, SectionParserFunction Parser
) {
55 assert(!CustomSectionParserFunctions
.count(SectionName
) &&
56 "Custom parser for this section already exists");
57 CustomSectionParserFunctions
[SectionName
] = std::move(Parser
);
60 Linkage
MachOLinkGraphBuilder::getLinkage(uint16_t Desc
) {
61 if ((Desc
& MachO::N_WEAK_DEF
) || (Desc
& MachO::N_WEAK_REF
))
63 return Linkage::Strong
;
66 Scope
MachOLinkGraphBuilder::getScope(StringRef Name
, uint8_t Type
) {
67 if (Name
.startswith("l"))
69 if (Type
& MachO::N_PEXT
)
71 if (Type
& MachO::N_EXT
)
72 return Scope::Default
;
76 bool MachOLinkGraphBuilder::isAltEntry(const NormalizedSymbol
&NSym
) {
77 return NSym
.Desc
& MachO::N_ALT_ENTRY
;
81 MachOLinkGraphBuilder::getPointerSize(const object::MachOObjectFile
&Obj
) {
82 return Obj
.is64Bit() ? 8 : 4;
86 MachOLinkGraphBuilder::getEndianness(const object::MachOObjectFile
&Obj
) {
87 return Obj
.isLittleEndian() ? support::little
: support::big
;
90 Section
&MachOLinkGraphBuilder::getCommonSection() {
92 auto Prot
= static_cast<sys::Memory::ProtectionFlags
>(
93 sys::Memory::MF_READ
| sys::Memory::MF_WRITE
);
94 CommonSection
= &G
->createSection(CommonSectionName
, Prot
);
96 return *CommonSection
;
99 Error
MachOLinkGraphBuilder::createNormalizedSections() {
100 // Build normalized sections. Verifies that section data is in-range (for
101 // sections with content) and that address ranges are non-overlapping.
103 LLVM_DEBUG(dbgs() << "Creating normalized sections...\n");
105 for (auto &SecRef
: Obj
.sections()) {
106 NormalizedSection NSec
;
107 uint32_t DataOffset
= 0;
109 auto SecIndex
= Obj
.getSectionIndex(SecRef
.getRawDataRefImpl());
111 auto Name
= SecRef
.getName();
113 return Name
.takeError();
116 const MachO::section_64
&Sec64
=
117 Obj
.getSection64(SecRef
.getRawDataRefImpl());
119 NSec
.Address
= Sec64
.addr
;
120 NSec
.Size
= Sec64
.size
;
121 NSec
.Alignment
= 1ULL << Sec64
.align
;
122 NSec
.Flags
= Sec64
.flags
;
123 DataOffset
= Sec64
.offset
;
125 const MachO::section
&Sec32
= Obj
.getSection(SecRef
.getRawDataRefImpl());
126 NSec
.Address
= Sec32
.addr
;
127 NSec
.Size
= Sec32
.size
;
128 NSec
.Alignment
= 1ULL << Sec32
.align
;
129 NSec
.Flags
= Sec32
.flags
;
130 DataOffset
= Sec32
.offset
;
134 dbgs() << " " << *Name
<< ": " << formatv("{0:x16}", NSec
.Address
)
135 << " -- " << formatv("{0:x16}", NSec
.Address
+ NSec
.Size
)
136 << ", align: " << NSec
.Alignment
<< ", index: " << SecIndex
140 // Get the section data if any.
142 unsigned SectionType
= NSec
.Flags
& MachO::SECTION_TYPE
;
143 if (SectionType
!= MachO::S_ZEROFILL
&&
144 SectionType
!= MachO::S_GB_ZEROFILL
) {
146 if (DataOffset
+ NSec
.Size
> Obj
.getData().size())
147 return make_error
<JITLinkError
>(
148 "Section data extends past end of file");
150 NSec
.Data
= Obj
.getData().data() + DataOffset
;
155 // FIXME: Make sure this test is correct (it's probably missing cases
157 sys::Memory::ProtectionFlags Prot
;
158 if (NSec
.Flags
& MachO::S_ATTR_PURE_INSTRUCTIONS
)
159 Prot
= static_cast<sys::Memory::ProtectionFlags
>(sys::Memory::MF_READ
|
160 sys::Memory::MF_EXEC
);
162 Prot
= static_cast<sys::Memory::ProtectionFlags
>(sys::Memory::MF_READ
|
163 sys::Memory::MF_WRITE
);
165 NSec
.GraphSection
= &G
->createSection(*Name
, Prot
);
166 IndexToSection
.insert(std::make_pair(SecIndex
, std::move(NSec
)));
169 std::vector
<NormalizedSection
*> Sections
;
170 Sections
.reserve(IndexToSection
.size());
171 for (auto &KV
: IndexToSection
)
172 Sections
.push_back(&KV
.second
);
174 // If we didn't end up creating any sections then bail out. The code below
175 // assumes that we have at least one section.
176 if (Sections
.empty())
177 return Error::success();
180 [](const NormalizedSection
*LHS
, const NormalizedSection
*RHS
) {
181 assert(LHS
&& RHS
&& "Null section?");
182 return LHS
->Address
< RHS
->Address
;
185 for (unsigned I
= 0, E
= Sections
.size() - 1; I
!= E
; ++I
) {
186 auto &Cur
= *Sections
[I
];
187 auto &Next
= *Sections
[I
+ 1];
188 if (Next
.Address
< Cur
.Address
+ Cur
.Size
)
189 return make_error
<JITLinkError
>(
190 "Address range for section " + Cur
.GraphSection
->getName() +
191 formatv(" [ {0:x16} -- {1:x16} ] ", Cur
.Address
,
192 Cur
.Address
+ Cur
.Size
) +
194 formatv(" [ {0:x16} -- {1:x16} ] ", Next
.Address
,
195 Next
.Address
+ Next
.Size
));
198 return Error::success();
201 Error
MachOLinkGraphBuilder::createNormalizedSymbols() {
202 LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n");
204 for (auto &SymRef
: Obj
.symbols()) {
206 unsigned SymbolIndex
= Obj
.getSymbolIndex(SymRef
.getRawDataRefImpl());
214 const MachO::nlist_64
&NL64
=
215 Obj
.getSymbol64TableEntry(SymRef
.getRawDataRefImpl());
216 Value
= NL64
.n_value
;
222 const MachO::nlist
&NL32
=
223 Obj
.getSymbolTableEntry(SymRef
.getRawDataRefImpl());
224 Value
= NL32
.n_value
;
232 // FIXME: Are there other symbols we should be skipping?
233 if (Type
& MachO::N_STAB
)
236 Optional
<StringRef
> Name
;
238 if (auto NameOrErr
= SymRef
.getName())
241 return NameOrErr
.takeError();
247 dbgs() << "<anonymous symbol>";
250 dbgs() << ": value = " << formatv("{0:x16}", Value
)
251 << ", type = " << formatv("{0:x2}", Type
)
252 << ", desc = " << formatv("{0:x4}", Desc
) << ", sect = ";
254 dbgs() << static_cast<unsigned>(Sect
- 1);
260 // If this symbol has a section, sanity check that the addresses line up.
261 NormalizedSection
*NSec
= nullptr;
263 if (auto NSecOrErr
= findSectionByIndex(Sect
- 1))
266 return NSecOrErr
.takeError();
268 if (Value
< NSec
->Address
|| Value
> NSec
->Address
+ NSec
->Size
)
269 return make_error
<JITLinkError
>("Symbol address does not fall within "
273 IndexToSymbol
[SymbolIndex
] =
274 &createNormalizedSymbol(*Name
, Value
, Type
, Sect
, Desc
,
275 getLinkage(Type
), getScope(*Name
, Type
));
278 return Error::success();
281 void MachOLinkGraphBuilder::addSectionStartSymAndBlock(
282 Section
&GraphSec
, uint64_t Address
, const char *Data
, uint64_t Size
,
283 uint32_t Alignment
, bool IsLive
) {
285 Data
? G
->createContentBlock(GraphSec
, StringRef(Data
, Size
), Address
,
287 : G
->createZeroFillBlock(GraphSec
, Size
, Address
, Alignment
, 0);
288 auto &Sym
= G
->addAnonymousSymbol(B
, 0, Size
, false, IsLive
);
289 assert(!AddrToCanonicalSymbol
.count(Sym
.getAddress()) &&
290 "Anonymous block start symbol clashes with existing symbol address");
291 AddrToCanonicalSymbol
[Sym
.getAddress()] = &Sym
;
294 Error
MachOLinkGraphBuilder::graphifyRegularSymbols() {
296 LLVM_DEBUG(dbgs() << "Creating graph symbols...\n");
298 /// We only have 256 section indexes: Use a vector rather than a map.
299 std::vector
<std::vector
<NormalizedSymbol
*>> SecIndexToSymbols
;
300 SecIndexToSymbols
.resize(256);
302 // Create commons, externs, and absolutes, and partition all other symbols by
304 for (auto &KV
: IndexToSymbol
) {
305 auto &NSym
= *KV
.second
;
307 switch (NSym
.Type
& MachO::N_TYPE
) {
311 return make_error
<JITLinkError
>("Anonymous common symbol at index " +
313 NSym
.GraphSymbol
= &G
->addCommonSymbol(
314 *NSym
.Name
, NSym
.S
, getCommonSection(), NSym
.Value
, 0,
315 1ull << MachO::GET_COMM_ALIGN(NSym
.Desc
),
316 NSym
.Desc
& MachO::N_NO_DEAD_STRIP
);
319 return make_error
<JITLinkError
>("Anonymous external symbol at "
322 NSym
.GraphSymbol
= &G
->addExternalSymbol(*NSym
.Name
, 0);
327 return make_error
<JITLinkError
>("Anonymous absolute symbol at index " +
329 NSym
.GraphSymbol
= &G
->addAbsoluteSymbol(
330 *NSym
.Name
, NSym
.Value
, 0, Linkage::Strong
, Scope::Default
,
331 NSym
.Desc
& MachO::N_NO_DEAD_STRIP
);
334 SecIndexToSymbols
[NSym
.Sect
- 1].push_back(&NSym
);
337 return make_error
<JITLinkError
>(
338 "Unupported N_PBUD symbol " +
339 (NSym
.Name
? ("\"" + *NSym
.Name
+ "\"") : Twine("<anon>")) +
340 " at index " + Twine(KV
.first
));
342 return make_error
<JITLinkError
>(
343 "Unupported N_INDR symbol " +
344 (NSym
.Name
? ("\"" + *NSym
.Name
+ "\"") : Twine("<anon>")) +
345 " at index " + Twine(KV
.first
));
347 return make_error
<JITLinkError
>(
348 "Unrecognized symbol type " + Twine(NSym
.Type
& MachO::N_TYPE
) +
350 (NSym
.Name
? ("\"" + *NSym
.Name
+ "\"") : Twine("<anon>")) +
351 " at index " + Twine(KV
.first
));
355 // Loop over sections performing regular graphification for those that
356 // don't have custom parsers.
357 for (auto &KV
: IndexToSection
) {
358 auto SecIndex
= KV
.first
;
359 auto &NSec
= KV
.second
;
361 // Skip sections with custom parsers.
362 if (CustomSectionParserFunctions
.count(NSec
.GraphSection
->getName())) {
364 dbgs() << " Skipping section " << NSec
.GraphSection
->getName()
365 << " as it has a custom parser.\n";
370 dbgs() << " Processing section " << NSec
.GraphSection
->getName()
374 bool SectionIsNoDeadStrip
= NSec
.Flags
& MachO::S_ATTR_NO_DEAD_STRIP
;
375 bool SectionIsText
= NSec
.Flags
& MachO::S_ATTR_PURE_INSTRUCTIONS
;
377 auto &SecNSymStack
= SecIndexToSymbols
[SecIndex
];
379 // If this section is non-empty but there are no symbols covering it then
380 // create one block and anonymous symbol to cover the entire section.
381 if (SecNSymStack
.empty()) {
384 dbgs() << " Section non-empty, but contains no symbols. "
385 "Creating anonymous block to cover "
386 << formatv("{0:x16}", NSec
.Address
) << " -- "
387 << formatv("{0:x16}", NSec
.Address
+ NSec
.Size
) << "\n";
389 addSectionStartSymAndBlock(*NSec
.GraphSection
, NSec
.Address
, NSec
.Data
,
390 NSec
.Size
, NSec
.Alignment
,
391 SectionIsNoDeadStrip
);
394 dbgs() << " Section empty and contains no symbols. Skipping.\n";
399 // Sort the symbol stack in by address, alt-entry status, scope, and name.
400 // We sort in reverse order so that symbols will be visited in the right
401 // order when we pop off the stack below.
402 llvm::sort(SecNSymStack
, [](const NormalizedSymbol
*LHS
,
403 const NormalizedSymbol
*RHS
) {
404 if (LHS
->Value
!= RHS
->Value
)
405 return LHS
->Value
> RHS
->Value
;
406 if (isAltEntry(*LHS
) != isAltEntry(*RHS
))
407 return isAltEntry(*RHS
);
408 if (LHS
->S
!= RHS
->S
)
409 return static_cast<uint8_t>(LHS
->S
) < static_cast<uint8_t>(RHS
->S
);
410 return LHS
->Name
< RHS
->Name
;
413 // The first symbol in a section can not be an alt-entry symbol.
414 if (!SecNSymStack
.empty() && isAltEntry(*SecNSymStack
.back()))
415 return make_error
<JITLinkError
>(
416 "First symbol in " + NSec
.GraphSection
->getName() + " is alt-entry");
418 // If the section is non-empty but there is no symbol covering the start
419 // address then add an anonymous one.
420 if (SecNSymStack
.back()->Value
!= NSec
.Address
) {
421 auto AnonBlockSize
= SecNSymStack
.back()->Value
- NSec
.Address
;
423 dbgs() << " Section start not covered by symbol. "
424 << "Creating anonymous block to cover [ "
425 << formatv("{0:x16}", NSec
.Address
) << " -- "
426 << formatv("{0:x16}", NSec
.Address
+ AnonBlockSize
) << " ]\n";
428 addSectionStartSymAndBlock(*NSec
.GraphSection
, NSec
.Address
, NSec
.Data
,
429 AnonBlockSize
, NSec
.Alignment
,
430 SectionIsNoDeadStrip
);
433 // Visit section symbols in order by popping off the reverse-sorted stack,
434 // building blocks for each alt-entry chain and creating symbols as we go.
435 while (!SecNSymStack
.empty()) {
436 SmallVector
<NormalizedSymbol
*, 8> BlockSyms
;
438 BlockSyms
.push_back(SecNSymStack
.back());
439 SecNSymStack
.pop_back();
440 while (!SecNSymStack
.empty() &&
441 (isAltEntry(*SecNSymStack
.back()) ||
442 SecNSymStack
.back()->Value
== BlockSyms
.back()->Value
)) {
443 BlockSyms
.push_back(SecNSymStack
.back());
444 SecNSymStack
.pop_back();
447 // BlockNSyms now contains the block symbols in reverse canonical order.
448 JITTargetAddress BlockStart
= BlockSyms
.front()->Value
;
449 JITTargetAddress BlockEnd
= SecNSymStack
.empty()
450 ? NSec
.Address
+ NSec
.Size
451 : SecNSymStack
.back()->Value
;
452 JITTargetAddress BlockOffset
= BlockStart
- NSec
.Address
;
453 JITTargetAddress BlockSize
= BlockEnd
- BlockStart
;
456 dbgs() << " Creating block for " << formatv("{0:x16}", BlockStart
)
457 << " -- " << formatv("{0:x16}", BlockEnd
) << ": "
458 << NSec
.GraphSection
->getName() << " + "
459 << formatv("{0:x16}", BlockOffset
) << " with "
460 << BlockSyms
.size() << " symbol(s)...\n";
465 ? G
->createContentBlock(
467 StringRef(NSec
.Data
+ BlockOffset
, BlockSize
), BlockStart
,
468 NSec
.Alignment
, BlockStart
% NSec
.Alignment
)
469 : G
->createZeroFillBlock(*NSec
.GraphSection
, BlockSize
,
470 BlockStart
, NSec
.Alignment
,
471 BlockStart
% NSec
.Alignment
);
473 Optional
<JITTargetAddress
> LastCanonicalAddr
;
474 JITTargetAddress SymEnd
= BlockEnd
;
475 while (!BlockSyms
.empty()) {
476 auto &NSym
= *BlockSyms
.back();
477 BlockSyms
.pop_back();
480 (NSym
.Desc
& MachO::N_NO_DEAD_STRIP
) || SectionIsNoDeadStrip
;
483 dbgs() << " " << formatv("{0:x16}", NSym
.Value
) << " -- "
484 << formatv("{0:x16}", SymEnd
) << ": ";
486 dbgs() << "<anonymous symbol>";
490 dbgs() << " [no-dead-strip]";
491 if (LastCanonicalAddr
== NSym
.Value
)
492 dbgs() << " [non-canonical]";
498 ? G
->addDefinedSymbol(B
, NSym
.Value
- BlockStart
, *NSym
.Name
,
499 SymEnd
- NSym
.Value
, NSym
.L
, NSym
.S
,
500 SectionIsText
, SymLive
)
501 : G
->addAnonymousSymbol(B
, NSym
.Value
- BlockStart
,
502 SymEnd
- NSym
.Value
, SectionIsText
,
504 NSym
.GraphSymbol
= &Sym
;
505 if (LastCanonicalAddr
!= Sym
.getAddress()) {
506 if (LastCanonicalAddr
)
507 SymEnd
= *LastCanonicalAddr
;
508 LastCanonicalAddr
= Sym
.getAddress();
509 setCanonicalSymbol(Sym
);
515 return Error::success();
518 Error
MachOLinkGraphBuilder::graphifySectionsWithCustomParsers() {
519 // Graphify special sections.
520 for (auto &KV
: IndexToSection
) {
521 auto &NSec
= KV
.second
;
523 auto HI
= CustomSectionParserFunctions
.find(NSec
.GraphSection
->getName());
524 if (HI
!= CustomSectionParserFunctions
.end()) {
525 auto &Parse
= HI
->second
;
526 if (auto Err
= Parse(NSec
))
531 return Error::success();
534 } // end namespace jitlink
535 } // end namespace llvm