1 | //=--------- COFFLinkGraphBuilder.cpp - COFF LinkGraph builder ----------===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Generic COFF LinkGraph building code. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | #include "COFFLinkGraphBuilder.h" |
13 | |
14 | #include <memory> |
15 | |
16 | #define DEBUG_TYPE "jitlink" |
17 | |
18 | static const char *CommonSectionName = "__common" ; |
19 | |
20 | namespace llvm { |
21 | namespace jitlink { |
22 | |
23 | static Triple createTripleWithCOFFFormat(Triple T) { |
24 | T.setObjectFormat(Triple::COFF); |
25 | return T; |
26 | } |
27 | |
28 | COFFLinkGraphBuilder::COFFLinkGraphBuilder( |
29 | const object::COFFObjectFile &Obj, |
30 | std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT, |
31 | SubtargetFeatures Features, |
32 | LinkGraph::GetEdgeKindNameFunction GetEdgeKindName) |
33 | : Obj(Obj), |
34 | G(std::make_unique<LinkGraph>(args: Obj.getFileName().str(), args: std::move(SSP), |
35 | args: createTripleWithCOFFFormat(T: std::move(TT)), |
36 | args: std::move(Features), |
37 | args: std::move(GetEdgeKindName))) { |
38 | LLVM_DEBUG({ |
39 | dbgs() << "Created COFFLinkGraphBuilder for \"" << Obj.getFileName() |
40 | << "\"\n" ; |
41 | }); |
42 | } |
43 | |
44 | COFFLinkGraphBuilder::~COFFLinkGraphBuilder() = default; |
45 | |
46 | uint64_t COFFLinkGraphBuilder::getSectionSize(const object::COFFObjectFile &Obj, |
47 | const object::coff_section *Sec) { |
48 | // Consider the difference between executable form and object form. |
49 | // More information is inside COFFObjectFile::getSectionSize |
50 | if (Obj.getDOSHeader()) |
51 | return std::min(a: Sec->VirtualSize, b: Sec->SizeOfRawData); |
52 | return Sec->SizeOfRawData; |
53 | } |
54 | |
55 | uint64_t |
56 | COFFLinkGraphBuilder::getSectionAddress(const object::COFFObjectFile &Obj, |
57 | const object::coff_section *Section) { |
58 | return Section->VirtualAddress + Obj.getImageBase(); |
59 | } |
60 | |
61 | bool COFFLinkGraphBuilder::isComdatSection( |
62 | const object::coff_section *Section) { |
63 | return Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT; |
64 | } |
65 | |
66 | Section &COFFLinkGraphBuilder::getCommonSection() { |
67 | if (!CommonSection) |
68 | CommonSection = &G->createSection(Name: CommonSectionName, |
69 | Prot: orc::MemProt::Read | orc::MemProt::Write); |
70 | return *CommonSection; |
71 | } |
72 | |
73 | Expected<std::unique_ptr<LinkGraph>> COFFLinkGraphBuilder::buildGraph() { |
74 | if (!Obj.isRelocatableObject()) |
75 | return make_error<JITLinkError>(Args: "Object is not a relocatable COFF file" ); |
76 | |
77 | if (auto Err = graphifySections()) |
78 | return std::move(Err); |
79 | |
80 | if (auto Err = graphifySymbols()) |
81 | return std::move(Err); |
82 | |
83 | if (auto Err = addRelocations()) |
84 | return std::move(Err); |
85 | |
86 | return std::move(G); |
87 | } |
88 | |
89 | StringRef |
90 | COFFLinkGraphBuilder::getCOFFSectionName(COFFSectionIndex SectionIndex, |
91 | const object::coff_section *Sec, |
92 | object::COFFSymbolRef Sym) { |
93 | switch (SectionIndex) { |
94 | case COFF::IMAGE_SYM_UNDEFINED: { |
95 | if (Sym.getValue()) |
96 | return "(common)" ; |
97 | else |
98 | return "(external)" ; |
99 | } |
100 | case COFF::IMAGE_SYM_ABSOLUTE: |
101 | return "(absolute)" ; |
102 | case COFF::IMAGE_SYM_DEBUG: { |
103 | // Used with .file symbol |
104 | return "(debug)" ; |
105 | } |
106 | default: { |
107 | // Non reserved regular section numbers |
108 | if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(Sec)) |
109 | return *SecNameOrErr; |
110 | } |
111 | } |
112 | return "" ; |
113 | } |
114 | |
115 | Error COFFLinkGraphBuilder::graphifySections() { |
116 | LLVM_DEBUG(dbgs() << " Creating graph sections...\n" ); |
117 | |
118 | GraphBlocks.resize(new_size: Obj.getNumberOfSections() + 1); |
119 | // For each section... |
120 | for (COFFSectionIndex SecIndex = 1; |
121 | SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections()); |
122 | SecIndex++) { |
123 | Expected<const object::coff_section *> Sec = Obj.getSection(index: SecIndex); |
124 | if (!Sec) |
125 | return Sec.takeError(); |
126 | |
127 | StringRef SectionName; |
128 | if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(Sec: *Sec)) |
129 | SectionName = *SecNameOrErr; |
130 | |
131 | // FIXME: Skip debug info sections |
132 | if (SectionName == ".voltbl" ) { |
133 | LLVM_DEBUG({ |
134 | dbgs() << " " |
135 | << "Skipping section \"" << SectionName << "\"\n" ; |
136 | }); |
137 | continue; |
138 | } |
139 | |
140 | LLVM_DEBUG({ |
141 | dbgs() << " " |
142 | << "Creating section for \"" << SectionName << "\"\n" ; |
143 | }); |
144 | |
145 | // Get the section's memory protection flags. |
146 | orc::MemProt Prot = orc::MemProt::Read; |
147 | if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE) |
148 | Prot |= orc::MemProt::Exec; |
149 | if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_READ) |
150 | Prot |= orc::MemProt::Read; |
151 | if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_WRITE) |
152 | Prot |= orc::MemProt::Write; |
153 | |
154 | // Look for existing sections first. |
155 | auto *GraphSec = G->findSectionByName(Name: SectionName); |
156 | if (!GraphSec) { |
157 | GraphSec = &G->createSection(Name: SectionName, Prot); |
158 | if ((*Sec)->Characteristics & COFF::IMAGE_SCN_LNK_REMOVE) |
159 | GraphSec->setMemLifetime(orc::MemLifetime::NoAlloc); |
160 | } |
161 | if (GraphSec->getMemProt() != Prot) |
162 | return make_error<JITLinkError>(Args: "MemProt should match" ); |
163 | |
164 | Block *B = nullptr; |
165 | if ((*Sec)->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) |
166 | B = &G->createZeroFillBlock( |
167 | Parent&: *GraphSec, Size: getSectionSize(Obj, Sec: *Sec), |
168 | Address: orc::ExecutorAddr(getSectionAddress(Obj, Section: *Sec)), |
169 | Alignment: (*Sec)->getAlignment(), AlignmentOffset: 0); |
170 | else { |
171 | ArrayRef<uint8_t> Data; |
172 | if (auto Err = Obj.getSectionContents(Sec: *Sec, Res&: Data)) |
173 | return Err; |
174 | |
175 | auto CharData = ArrayRef<char>( |
176 | reinterpret_cast<const char *>(Data.data()), Data.size()); |
177 | |
178 | if (SectionName == getDirectiveSectionName()) |
179 | if (auto Err = handleDirectiveSection( |
180 | Str: StringRef(CharData.data(), CharData.size()))) |
181 | return Err; |
182 | |
183 | B = &G->createContentBlock( |
184 | Parent&: *GraphSec, Content: CharData, Address: orc::ExecutorAddr(getSectionAddress(Obj, Section: *Sec)), |
185 | Alignment: (*Sec)->getAlignment(), AlignmentOffset: 0); |
186 | } |
187 | |
188 | setGraphBlock(SecIndex, B); |
189 | } |
190 | |
191 | return Error::success(); |
192 | } |
193 | |
194 | Error COFFLinkGraphBuilder::graphifySymbols() { |
195 | LLVM_DEBUG(dbgs() << " Creating graph symbols...\n" ); |
196 | |
197 | SymbolSets.resize(new_size: Obj.getNumberOfSections() + 1); |
198 | PendingComdatExports.resize(new_size: Obj.getNumberOfSections() + 1); |
199 | GraphSymbols.resize(new_size: Obj.getNumberOfSymbols()); |
200 | |
201 | for (COFFSymbolIndex SymIndex = 0; |
202 | SymIndex < static_cast<COFFSymbolIndex>(Obj.getNumberOfSymbols()); |
203 | SymIndex++) { |
204 | Expected<object::COFFSymbolRef> Sym = Obj.getSymbol(index: SymIndex); |
205 | if (!Sym) |
206 | return Sym.takeError(); |
207 | |
208 | StringRef SymbolName; |
209 | if (Expected<StringRef> SymNameOrErr = Obj.getSymbolName(Symbol: *Sym)) |
210 | SymbolName = *SymNameOrErr; |
211 | |
212 | COFFSectionIndex SectionIndex = Sym->getSectionNumber(); |
213 | const object::coff_section *Sec = nullptr; |
214 | |
215 | if (!COFF::isReservedSectionNumber(SectionNumber: SectionIndex)) { |
216 | auto SecOrErr = Obj.getSection(index: SectionIndex); |
217 | if (!SecOrErr) |
218 | return make_error<JITLinkError>( |
219 | Args: "Invalid COFF section number:" + formatv(Fmt: "{0:d}: " , Vals&: SectionIndex) + |
220 | " (" + toString(E: SecOrErr.takeError()) + ")" ); |
221 | Sec = *SecOrErr; |
222 | } |
223 | auto InternedSymbolName = G->intern(SymbolName: std::move(SymbolName)); |
224 | |
225 | // Create jitlink symbol |
226 | jitlink::Symbol *GSym = nullptr; |
227 | if (Sym->isFileRecord()) |
228 | LLVM_DEBUG({ |
229 | dbgs() << " " << SymIndex << ": Skipping FileRecord symbol \"" |
230 | << InternedSymbolName << "\" in " |
231 | << getCOFFSectionName(SectionIndex, Sec, *Sym) |
232 | << " (index: " << SectionIndex << ") \n" ; |
233 | }); |
234 | else if (Sym->isUndefined()) { |
235 | GSym = createExternalSymbol(SymIndex, SymbolName: InternedSymbolName, Symbol: *Sym, Section: Sec); |
236 | } else if (Sym->isWeakExternal()) { |
237 | auto *WeakExternal = Sym->getAux<object::coff_aux_weak_external>(); |
238 | COFFSymbolIndex TagIndex = WeakExternal->TagIndex; |
239 | uint32_t Characteristics = WeakExternal->Characteristics; |
240 | WeakExternalRequests.push_back( |
241 | x: {.Alias: SymIndex, .Target: TagIndex, .Characteristics: Characteristics, .SymbolName: SymbolName}); |
242 | } else { |
243 | Expected<jitlink::Symbol *> NewGSym = |
244 | createDefinedSymbol(SymIndex, SymbolName: InternedSymbolName, Symbol: *Sym, Section: Sec); |
245 | if (!NewGSym) |
246 | return NewGSym.takeError(); |
247 | GSym = *NewGSym; |
248 | if (GSym) { |
249 | LLVM_DEBUG({ |
250 | dbgs() << " " << SymIndex |
251 | << ": Creating defined graph symbol for COFF symbol \"" |
252 | << InternedSymbolName << "\" in " |
253 | << getCOFFSectionName(SectionIndex, Sec, *Sym) |
254 | << " (index: " << SectionIndex << ") \n" ; |
255 | dbgs() << " " << *GSym << "\n" ; |
256 | }); |
257 | } |
258 | } |
259 | |
260 | // Register the symbol |
261 | if (GSym) |
262 | setGraphSymbol(SecIndex: SectionIndex, SymIndex, Sym&: *GSym); |
263 | SymIndex += Sym->getNumberOfAuxSymbols(); |
264 | } |
265 | |
266 | if (auto Err = flushWeakAliasRequests()) |
267 | return Err; |
268 | |
269 | if (auto Err = handleAlternateNames()) |
270 | return Err; |
271 | |
272 | if (auto Err = calculateImplicitSizeOfSymbols()) |
273 | return Err; |
274 | |
275 | return Error::success(); |
276 | } |
277 | |
278 | Error COFFLinkGraphBuilder::handleDirectiveSection(StringRef Str) { |
279 | auto Parsed = DirectiveParser.parse(Str); |
280 | if (!Parsed) |
281 | return Parsed.takeError(); |
282 | for (auto *Arg : *Parsed) { |
283 | StringRef S = Arg->getValue(); |
284 | switch (Arg->getOption().getID()) { |
285 | case COFF_OPT_alternatename: { |
286 | StringRef From, To; |
287 | std::tie(args&: From, args&: To) = S.split(Separator: '='); |
288 | if (From.empty() || To.empty()) |
289 | return make_error<JITLinkError>( |
290 | Args: "Invalid COFF /alternatename directive" ); |
291 | AlternateNames[G->intern(SymbolName: From)] = G->intern(SymbolName: To); |
292 | break; |
293 | } |
294 | case COFF_OPT_incl: { |
295 | auto Symbol = &G->addExternalSymbol(Name: S, Size: 0, IsWeaklyReferenced: false); |
296 | Symbol->setLive(true); |
297 | ExternalSymbols[Symbol->getName()] = Symbol; |
298 | break; |
299 | } |
300 | case COFF_OPT_export: |
301 | break; |
302 | default: { |
303 | LLVM_DEBUG({ |
304 | dbgs() << "Unknown coff directive: " << Arg->getSpelling() << "\n" ; |
305 | }); |
306 | break; |
307 | } |
308 | } |
309 | } |
310 | return Error::success(); |
311 | } |
312 | |
313 | Error COFFLinkGraphBuilder::flushWeakAliasRequests() { |
314 | // Export the weak external symbols and alias it |
315 | for (auto &WeakExternal : WeakExternalRequests) { |
316 | if (auto *Target = getGraphSymbol(SymIndex: WeakExternal.Target)) { |
317 | Expected<object::COFFSymbolRef> AliasSymbol = |
318 | Obj.getSymbol(index: WeakExternal.Alias); |
319 | if (!AliasSymbol) |
320 | return AliasSymbol.takeError(); |
321 | |
322 | // FIXME: IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY and |
323 | // IMAGE_WEAK_EXTERN_SEARCH_LIBRARY are handled in the same way. |
324 | Scope S = |
325 | WeakExternal.Characteristics == COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS |
326 | ? Scope::Default |
327 | : Scope::Local; |
328 | |
329 | auto NewSymbol = createAliasSymbol(SymbolName: G->intern(SymbolName: WeakExternal.SymbolName), |
330 | L: Linkage::Weak, S, Target&: *Target); |
331 | if (!NewSymbol) |
332 | return NewSymbol.takeError(); |
333 | setGraphSymbol(SecIndex: AliasSymbol->getSectionNumber(), SymIndex: WeakExternal.Alias, |
334 | Sym&: **NewSymbol); |
335 | LLVM_DEBUG({ |
336 | dbgs() << " " << WeakExternal.Alias |
337 | << ": Creating weak external symbol for COFF symbol \"" |
338 | << WeakExternal.SymbolName << "\" in section " |
339 | << AliasSymbol->getSectionNumber() << "\n" ; |
340 | dbgs() << " " << **NewSymbol << "\n" ; |
341 | }); |
342 | } else |
343 | return make_error<JITLinkError>(Args: "Weak symbol alias requested but actual " |
344 | "symbol not found for symbol " + |
345 | formatv(Fmt: "{0:d}" , Vals&: WeakExternal.Alias)); |
346 | } |
347 | return Error::success(); |
348 | } |
349 | |
350 | Error COFFLinkGraphBuilder::handleAlternateNames() { |
351 | for (auto &KeyValue : AlternateNames) { |
352 | auto DefinedSymbolName = KeyValue.second; |
353 | auto ExternalSymbolsName = KeyValue.first; |
354 | if (DefinedSymbols.count(Val: DefinedSymbolName) && |
355 | ExternalSymbols.count(Val: ExternalSymbolsName)) { |
356 | auto *Target = DefinedSymbols[DefinedSymbolName]; |
357 | auto *Alias = ExternalSymbols[ExternalSymbolsName]; |
358 | G->makeDefined(Sym&: *Alias, Content&: Target->getBlock(), Offset: Target->getOffset(), |
359 | Size: Target->getSize(), L: Linkage::Weak, S: Scope::Local, IsLive: false); |
360 | } |
361 | } |
362 | return Error::success(); |
363 | } |
364 | |
365 | Symbol *COFFLinkGraphBuilder::createExternalSymbol( |
366 | COFFSymbolIndex SymIndex, orc::SymbolStringPtr SymbolName, |
367 | object::COFFSymbolRef Symbol, const object::coff_section *Section) { |
368 | llvm::jitlink::Symbol *Sym = nullptr; |
369 | if (auto It = ExternalSymbols.find(Val: SymbolName); It == ExternalSymbols.end()) { |
370 | Sym = &G->addExternalSymbol(Name: *SymbolName, Size: Symbol.getValue(), IsWeaklyReferenced: false); |
371 | ExternalSymbols[Sym->getName()] = Sym; |
372 | } else { |
373 | Sym = It->second; |
374 | } |
375 | |
376 | LLVM_DEBUG({ |
377 | dbgs() << " " << SymIndex |
378 | << ": Creating external graph symbol for COFF symbol \"" |
379 | << Sym->getName() << "\" in " |
380 | << getCOFFSectionName(Symbol.getSectionNumber(), Section, Symbol) |
381 | << " (index: " << Symbol.getSectionNumber() << ") \n" ; |
382 | }); |
383 | return Sym; |
384 | } |
385 | |
386 | Expected<Symbol *> |
387 | COFFLinkGraphBuilder::createAliasSymbol(orc::SymbolStringPtr SymbolName, |
388 | Linkage L, Scope S, Symbol &Target) { |
389 | if (!Target.isDefined()) { |
390 | // FIXME: Support this when there's a way to handle this. |
391 | return make_error<JITLinkError>(Args: "Weak external symbol with external " |
392 | "symbol as alternative not supported." ); |
393 | } |
394 | return &G->addDefinedSymbol(Content&: Target.getBlock(), Offset: Target.getOffset(), Name: SymbolName, |
395 | Size: Target.getSize(), L, S, IsCallable: Target.isCallable(), |
396 | IsLive: false); |
397 | } |
398 | |
399 | // In COFF, most of the defined symbols don't contain the size information. |
400 | // Hence, we calculate the "implicit" size of symbol by taking the delta of |
401 | // offsets of consecutive symbols within a block. We maintain a balanced tree |
402 | // set of symbols sorted by offset per each block in order to achieve |
403 | // logarithmic time complexity of sorted symbol insertion. Symbol is inserted to |
404 | // the set once it's processed in graphifySymbols. In this function, we iterate |
405 | // each collected symbol in sorted order and calculate the implicit size. |
406 | Error COFFLinkGraphBuilder::calculateImplicitSizeOfSymbols() { |
407 | for (COFFSectionIndex SecIndex = 1; |
408 | SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections()); |
409 | SecIndex++) { |
410 | auto &SymbolSet = SymbolSets[SecIndex]; |
411 | if (SymbolSet.empty()) |
412 | continue; |
413 | jitlink::Block *B = getGraphBlock(SecIndex); |
414 | orc::ExecutorAddrDiff LastOffset = B->getSize(); |
415 | orc::ExecutorAddrDiff LastDifferentOffset = B->getSize(); |
416 | orc::ExecutorAddrDiff LastSize = 0; |
417 | for (auto It = SymbolSet.rbegin(); It != SymbolSet.rend(); It++) { |
418 | orc::ExecutorAddrDiff Offset = It->first; |
419 | jitlink::Symbol *Symbol = It->second; |
420 | orc::ExecutorAddrDiff CandSize; |
421 | // Last offset can be same when aliasing happened |
422 | if (Symbol->getOffset() == LastOffset) |
423 | CandSize = LastSize; |
424 | else |
425 | CandSize = LastOffset - Offset; |
426 | |
427 | LLVM_DEBUG({ |
428 | if (Offset + Symbol->getSize() > LastDifferentOffset) |
429 | dbgs() << " Overlapping symbol range generated for the following " |
430 | "symbol:" |
431 | << "\n" |
432 | << " " << *Symbol << "\n" ; |
433 | }); |
434 | (void)LastDifferentOffset; |
435 | if (LastOffset != Offset) |
436 | LastDifferentOffset = Offset; |
437 | LastSize = CandSize; |
438 | LastOffset = Offset; |
439 | if (Symbol->getSize()) { |
440 | // Non empty symbol can happen in COMDAT symbol. |
441 | // We don't consider the possibility of overlapping symbol range that |
442 | // could be introduced by disparity between inferred symbol size and |
443 | // defined symbol size because symbol size information is currently only |
444 | // used by jitlink-check where we have control to not make overlapping |
445 | // ranges. |
446 | continue; |
447 | } |
448 | |
449 | LLVM_DEBUG({ |
450 | if (!CandSize) |
451 | dbgs() << " Empty implicit symbol size generated for the following " |
452 | "symbol:" |
453 | << "\n" |
454 | << " " << *Symbol << "\n" ; |
455 | }); |
456 | |
457 | Symbol->setSize(CandSize); |
458 | } |
459 | } |
460 | return Error::success(); |
461 | } |
462 | |
463 | Expected<Symbol *> COFFLinkGraphBuilder::createDefinedSymbol( |
464 | COFFSymbolIndex SymIndex, orc::SymbolStringPtr SymbolName, |
465 | object::COFFSymbolRef Symbol, const object::coff_section *Section) { |
466 | |
467 | if (Symbol.isCommon()) { |
468 | // FIXME: correct alignment |
469 | return &G->addDefinedSymbol( |
470 | Content&: G->createZeroFillBlock(Parent&: getCommonSection(), Size: Symbol.getValue(), |
471 | Address: orc::ExecutorAddr(), Alignment: Symbol.getValue(), AlignmentOffset: 0), |
472 | Offset: 0, Name: SymbolName, Size: Symbol.getValue(), L: Linkage::Weak, S: Scope::Default, |
473 | IsCallable: false, IsLive: false); |
474 | } |
475 | |
476 | if (Symbol.isAbsolute()) |
477 | return &G->addAbsoluteSymbol(Name: SymbolName, |
478 | Address: orc::ExecutorAddr(Symbol.getValue()), Size: 0, |
479 | L: Linkage::Strong, S: Scope::Local, IsLive: false); |
480 | |
481 | if (llvm::COFF::isReservedSectionNumber(SectionNumber: Symbol.getSectionNumber())) |
482 | return make_error<JITLinkError>( |
483 | Args: "Reserved section number used in regular symbol " + |
484 | formatv(Fmt: "{0:d}" , Vals&: SymIndex)); |
485 | |
486 | Block *B = getGraphBlock(SecIndex: Symbol.getSectionNumber()); |
487 | if (!B) { |
488 | LLVM_DEBUG({ |
489 | dbgs() << " " << SymIndex |
490 | << ": Skipping graph symbol since section was not created for " |
491 | "COFF symbol \"" |
492 | << SymbolName << "\" in section " << Symbol.getSectionNumber() |
493 | << "\n" ; |
494 | }); |
495 | return nullptr; |
496 | } |
497 | |
498 | if (Symbol.isExternal()) { |
499 | // This is not a comdat sequence, export the symbol as it is |
500 | if (!isComdatSection(Section)) { |
501 | auto GSym = &G->addDefinedSymbol( |
502 | Content&: *B, Offset: Symbol.getValue(), Name: SymbolName, Size: 0, L: Linkage::Strong, S: Scope::Default, |
503 | IsCallable: Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, IsLive: false); |
504 | DefinedSymbols[SymbolName] = GSym; |
505 | return GSym; |
506 | } else { |
507 | if (!PendingComdatExports[Symbol.getSectionNumber()]) |
508 | return make_error<JITLinkError>(Args: "No pending COMDAT export for symbol " + |
509 | formatv(Fmt: "{0:d}" , Vals&: SymIndex)); |
510 | |
511 | return exportCOMDATSymbol(SymIndex, SymbolName, Symbol); |
512 | } |
513 | } |
514 | |
515 | if (Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC || |
516 | Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_LABEL) { |
517 | const object::coff_aux_section_definition *Definition = |
518 | Symbol.getSectionDefinition(); |
519 | if (!Definition || !isComdatSection(Section)) { |
520 | // Handle typical static symbol |
521 | return &G->addDefinedSymbol( |
522 | Content&: *B, Offset: Symbol.getValue(), Name: SymbolName, Size: 0, L: Linkage::Strong, S: Scope::Local, |
523 | IsCallable: Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, IsLive: false); |
524 | } |
525 | if (Definition->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { |
526 | auto Target = Definition->getNumber(IsBigObj: Symbol.isBigObj()); |
527 | auto GSym = &G->addDefinedSymbol( |
528 | Content&: *B, Offset: Symbol.getValue(), Name: SymbolName, Size: 0, L: Linkage::Strong, S: Scope::Local, |
529 | IsCallable: Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, IsLive: false); |
530 | getGraphBlock(SecIndex: Target)->addEdge(K: Edge::KeepAlive, Offset: 0, Target&: *GSym, Addend: 0); |
531 | return GSym; |
532 | } |
533 | if (PendingComdatExports[Symbol.getSectionNumber()]) |
534 | return make_error<JITLinkError>( |
535 | Args: "COMDAT export request already exists before symbol " + |
536 | formatv(Fmt: "{0:d}" , Vals&: SymIndex)); |
537 | return createCOMDATExportRequest(SymIndex, Symbol, Definition); |
538 | } |
539 | return make_error<JITLinkError>(Args: "Unsupported storage class " + |
540 | formatv(Fmt: "{0:d}" , Vals: Symbol.getStorageClass()) + |
541 | " in symbol " + formatv(Fmt: "{0:d}" , Vals&: SymIndex)); |
542 | } |
543 | |
544 | // COMDAT handling: |
545 | // When IMAGE_SCN_LNK_COMDAT flag is set in the flags of a section, |
546 | // the section is called a COMDAT section. It contains two symbols |
547 | // in a sequence that specifes the behavior. First symbol is the section |
548 | // symbol which contains the size and name of the section. It also contains |
549 | // selection type that specifies how duplicate of the symbol is handled. |
550 | // Second symbol is COMDAT symbol which usually defines the external name and |
551 | // data type. |
552 | // |
553 | // Since two symbols always come in a specific order, we initiate pending COMDAT |
554 | // export request when we encounter the first symbol and actually exports it |
555 | // when we process the second symbol. |
556 | // |
557 | // Process the first symbol of COMDAT sequence. |
558 | Expected<Symbol *> COFFLinkGraphBuilder::createCOMDATExportRequest( |
559 | COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol, |
560 | const object::coff_aux_section_definition *Definition) { |
561 | Linkage L = Linkage::Strong; |
562 | switch (Definition->Selection) { |
563 | case COFF::IMAGE_COMDAT_SELECT_NODUPLICATES: { |
564 | L = Linkage::Strong; |
565 | break; |
566 | } |
567 | case COFF::IMAGE_COMDAT_SELECT_ANY: { |
568 | L = Linkage::Weak; |
569 | break; |
570 | } |
571 | case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH: |
572 | case COFF::IMAGE_COMDAT_SELECT_SAME_SIZE: { |
573 | // FIXME: Implement size/content validation when LinkGraph is able to |
574 | // handle this. |
575 | L = Linkage::Weak; |
576 | break; |
577 | } |
578 | case COFF::IMAGE_COMDAT_SELECT_LARGEST: { |
579 | // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST properly when LinkGraph is |
580 | // able to handle this. |
581 | LLVM_DEBUG({ |
582 | dbgs() << " " << SymIndex |
583 | << ": Partially supported IMAGE_COMDAT_SELECT_LARGEST was used" |
584 | " in section " |
585 | << Symbol.getSectionNumber() << " (size: " << Definition->Length |
586 | << ")\n" ; |
587 | }); |
588 | L = Linkage::Weak; |
589 | break; |
590 | } |
591 | case COFF::IMAGE_COMDAT_SELECT_NEWEST: { |
592 | // Even link.exe doesn't support this selection properly. |
593 | return make_error<JITLinkError>( |
594 | Args: "IMAGE_COMDAT_SELECT_NEWEST is not supported." ); |
595 | } |
596 | default: { |
597 | return make_error<JITLinkError>(Args: "Invalid comdat selection type: " + |
598 | formatv(Fmt: "{0:d}" , Vals: Definition->Selection)); |
599 | } |
600 | } |
601 | PendingComdatExports[Symbol.getSectionNumber()] = {.SymbolIndex: SymIndex, .Linkage: L, |
602 | .Size: Definition->Length}; |
603 | return nullptr; |
604 | } |
605 | |
606 | // Process the second symbol of COMDAT sequence. |
607 | Expected<Symbol *> |
608 | COFFLinkGraphBuilder::exportCOMDATSymbol(COFFSymbolIndex SymIndex, |
609 | orc::SymbolStringPtr SymbolName, |
610 | object::COFFSymbolRef Symbol) { |
611 | Block *B = getGraphBlock(SecIndex: Symbol.getSectionNumber()); |
612 | auto &PendingComdatExport = PendingComdatExports[Symbol.getSectionNumber()]; |
613 | // NOTE: ComdatDef->Length is the size of "section" not size of symbol. |
614 | // We use zero symbol size to not reach out of bound of block when symbol |
615 | // offset is non-zero. |
616 | auto GSym = &G->addDefinedSymbol( |
617 | Content&: *B, Offset: Symbol.getValue(), Name: SymbolName, Size: 0, L: PendingComdatExport->Linkage, |
618 | S: Scope::Default, IsCallable: Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, |
619 | IsLive: false); |
620 | LLVM_DEBUG({ |
621 | dbgs() << " " << SymIndex |
622 | << ": Exporting COMDAT graph symbol for COFF symbol \"" << SymbolName |
623 | << "\" in section " << Symbol.getSectionNumber() << "\n" ; |
624 | dbgs() << " " << *GSym << "\n" ; |
625 | }); |
626 | setGraphSymbol(SecIndex: Symbol.getSectionNumber(), SymIndex: PendingComdatExport->SymbolIndex, |
627 | Sym&: *GSym); |
628 | DefinedSymbols[SymbolName] = GSym; |
629 | PendingComdatExport = std::nullopt; |
630 | return GSym; |
631 | } |
632 | |
633 | Symbol *GetImageBaseSymbol::operator()(LinkGraph &G) { |
634 | if (ImageBase) |
635 | return *ImageBase; |
636 | |
637 | auto IBN = G.intern(SymbolName: ImageBaseName); |
638 | ImageBase = G.findExternalSymbolByName(Name: IBN); |
639 | if (*ImageBase) |
640 | return *ImageBase; |
641 | ImageBase = G.findAbsoluteSymbolByName(Name: IBN); |
642 | if (*ImageBase) |
643 | return *ImageBase; |
644 | ImageBase = G.findDefinedSymbolByName(Name: IBN); |
645 | if (*ImageBase) |
646 | return *ImageBase; |
647 | |
648 | return nullptr; |
649 | } |
650 | |
651 | } // namespace jitlink |
652 | } // namespace llvm |
653 | |