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 buliding code.
10 //
11 //===----------------------------------------------------------------------===//
12 #include "COFFLinkGraphBuilder.h"
13 
14 #define DEBUG_TYPE "jitlink"
15 
16 static const char *CommonSectionName = "__common";
17 
18 namespace llvm {
19 namespace jitlink {
20 
21 COFFLinkGraphBuilder::COFFLinkGraphBuilder(
22     const object::COFFObjectFile &Obj, Triple TT,
23     LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
24     : Obj(Obj),
25       G(std::make_unique<LinkGraph>(
26           Obj.getFileName().str(), Triple(std::move(TT)), getPointerSize(Obj),
27           getEndianness(Obj), std::move(GetEdgeKindName))) {
28   LLVM_DEBUG({
29     dbgs() << "Created COFFLinkGraphBuilder for \"" << Obj.getFileName()
30            << "\"\n";
31   });
32 }
33 
34 COFFLinkGraphBuilder::~COFFLinkGraphBuilder() = default;
35 
36 unsigned
37 COFFLinkGraphBuilder::getPointerSize(const object::COFFObjectFile &Obj) {
38   return Obj.getBytesInAddress();
39 }
40 
41 support::endianness
42 COFFLinkGraphBuilder::getEndianness(const object::COFFObjectFile &Obj) {
43   return Obj.isLittleEndian() ? support::little : support::big;
44 }
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(Sec->VirtualSize, 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 =
69         &G->createSection(CommonSectionName, MemProt::Read | MemProt::Write);
70   return *CommonSection;
71 }
72 
73 Expected<std::unique_ptr<LinkGraph>> COFFLinkGraphBuilder::buildGraph() {
74   if (!Obj.isRelocatableObject())
75     return make_error<JITLinkError>("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(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(SecIndex);
124     if (!Sec)
125       return Sec.takeError();
126 
127     StringRef SectionName;
128     if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(*Sec))
129       SectionName = *SecNameOrErr;
130 
131     bool IsDiscardable =
132         (*Sec)->Characteristics &
133         (COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_LNK_INFO);
134     if (IsDiscardable) {
135       LLVM_DEBUG(dbgs() << "    " << SecIndex << ": \"" << SectionName
136                         << "\" is discardable: "
137                            "No graph section will be created.\n");
138       continue;
139     }
140 
141     // FIXME: Skip debug info sections
142 
143     LLVM_DEBUG({
144       dbgs() << "    "
145              << "Creating section for \"" << SectionName << "\"\n";
146     });
147 
148     // Get the section's memory protection flags.
149     MemProt Prot = MemProt::None;
150     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE)
151       Prot |= MemProt::Exec;
152     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_READ)
153       Prot |= MemProt::Read;
154     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_WRITE)
155       Prot |= MemProt::Write;
156 
157     // Look for existing sections first.
158     auto *GraphSec = G->findSectionByName(SectionName);
159     if (!GraphSec)
160       GraphSec = &G->createSection(SectionName, Prot);
161     if (GraphSec->getMemProt() != Prot)
162       return make_error<JITLinkError>("MemProt should match");
163 
164     Block *B = nullptr;
165     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
166       B = &G->createZeroFillBlock(
167           *GraphSec, getSectionSize(Obj, *Sec),
168           orc::ExecutorAddr(getSectionAddress(Obj, *Sec)),
169           (*Sec)->getAlignment(), 0);
170     else {
171       ArrayRef<uint8_t> Data;
172       if (auto Err = Obj.getSectionContents(*Sec, Data))
173         return Err;
174 
175       B = &G->createContentBlock(
176           *GraphSec,
177           ArrayRef<char>(reinterpret_cast<const char *>(Data.data()),
178                          Data.size()),
179           orc::ExecutorAddr(getSectionAddress(Obj, *Sec)),
180           (*Sec)->getAlignment(), 0);
181     }
182 
183     setGraphBlock(SecIndex, B);
184   }
185 
186   return Error::success();
187 }
188 
189 Error COFFLinkGraphBuilder::graphifySymbols() {
190   LLVM_DEBUG(dbgs() << "  Creating graph symbols...\n");
191 
192   SymbolSets.resize(Obj.getNumberOfSections() + 1);
193   GraphSymbols.resize(Obj.getNumberOfSymbols());
194 
195   for (COFFSymbolIndex SymIndex = 0;
196        SymIndex < static_cast<COFFSymbolIndex>(Obj.getNumberOfSymbols());
197        SymIndex++) {
198     Expected<object::COFFSymbolRef> Sym = Obj.getSymbol(SymIndex);
199     if (!Sym)
200       return Sym.takeError();
201 
202     StringRef SymbolName;
203     if (Expected<StringRef> SymNameOrErr = Obj.getSymbolName(*Sym))
204       SymbolName = *SymNameOrErr;
205 
206     COFFSectionIndex SectionIndex = Sym->getSectionNumber();
207     const object::coff_section *Sec = nullptr;
208 
209     if (!COFF::isReservedSectionNumber(SectionIndex)) {
210       auto SecOrErr = Obj.getSection(SectionIndex);
211       if (!SecOrErr)
212         return make_error<JITLinkError>(
213             "Invalid COFF section number:" + formatv("{0:d}: ", SectionIndex) +
214             " (" + toString(SecOrErr.takeError()) + ")");
215       Sec = *SecOrErr;
216     }
217 
218     // Create jitlink symbol
219     jitlink::Symbol *GSym = nullptr;
220     if (Sym->isFileRecord())
221       LLVM_DEBUG({
222         dbgs() << "    " << SymIndex << ": Skipping FileRecord symbol \""
223                << SymbolName << "\" in "
224                << getCOFFSectionName(SectionIndex, Sec, *Sym)
225                << " (index: " << SectionIndex << ") \n";
226       });
227     else if (Sym->isUndefined()) {
228       LLVM_DEBUG({
229         dbgs() << "    " << SymIndex
230                << ": Creating external graph symbol for COFF symbol \""
231                << SymbolName << "\" in "
232                << getCOFFSectionName(SectionIndex, Sec, *Sym)
233                << " (index: " << SectionIndex << ") \n";
234       });
235       GSym =
236           &G->addExternalSymbol(SymbolName, Sym->getValue(), Linkage::Strong);
237     } else if (Sym->isWeakExternal()) {
238       COFFSymbolIndex TagIndex =
239           Sym->getAux<object::coff_aux_weak_external>()->TagIndex;
240       assert(Sym->getAux<object::coff_aux_weak_external>()->Characteristics !=
241                  COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY &&
242              "IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY is not supported.");
243       assert(Sym->getAux<object::coff_aux_weak_external>()->Characteristics !=
244                  COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY &&
245              "IMAGE_WEAK_EXTERN_SEARCH_LIBRARY is not supported.");
246       WeakAliasRequests.push_back({SymIndex, TagIndex, SymbolName});
247     } else {
248       Expected<jitlink::Symbol *> NewGSym =
249           createDefinedSymbol(SymIndex, SymbolName, *Sym, Sec);
250       if (!NewGSym)
251         return NewGSym.takeError();
252       GSym = *NewGSym;
253       if (GSym) {
254         LLVM_DEBUG({
255           dbgs() << "    " << SymIndex
256                  << ": Creating defined graph symbol for COFF symbol \""
257                  << SymbolName << "\" in "
258                  << getCOFFSectionName(SectionIndex, Sec, *Sym)
259                  << " (index: " << SectionIndex << ") \n";
260           dbgs() << "      " << *GSym << "\n";
261         });
262       }
263     }
264 
265     // Register the symbol
266     if (GSym)
267       setGraphSymbol(SectionIndex, SymIndex, *GSym);
268     SymIndex += Sym->getNumberOfAuxSymbols();
269   }
270 
271   if (auto Err = flushWeakAliasRequests())
272     return Err;
273 
274   if (auto Err = calculateImplicitSizeOfSymbols())
275     return Err;
276 
277   return Error::success();
278 }
279 
280 Error COFFLinkGraphBuilder::flushWeakAliasRequests() {
281   // Export the weak external symbols and alias it
282   for (auto &WeakAlias : WeakAliasRequests) {
283     if (auto *Target = getGraphSymbol(WeakAlias.Target)) {
284       Expected<object::COFFSymbolRef> AliasSymbol =
285           Obj.getSymbol(WeakAlias.Alias);
286       if (!AliasSymbol)
287         return AliasSymbol.takeError();
288 
289       // FIXME: Support this when there's a way to handle this.
290       if (!Target->isDefined())
291         return make_error<JITLinkError>("Weak external symbol with external "
292                                         "symbol as alternative not supported.");
293 
294       jitlink::Symbol *NewSymbol = &G->addDefinedSymbol(
295           Target->getBlock(), Target->getOffset(), WeakAlias.SymbolName,
296           Target->getSize(), Linkage::Weak, Scope::Default,
297           Target->isCallable(), false);
298       setGraphSymbol(AliasSymbol->getSectionNumber(), WeakAlias.Alias,
299                      *NewSymbol);
300       LLVM_DEBUG({
301         dbgs() << "    " << WeakAlias.Alias
302                << ": Creating weak external symbol for COFF symbol \""
303                << WeakAlias.SymbolName << "\" in section "
304                << AliasSymbol->getSectionNumber() << "\n";
305         dbgs() << "      " << *NewSymbol << "\n";
306       });
307     } else
308       return make_error<JITLinkError>("Weak symbol alias requested but actual "
309                                       "symbol not found for symbol " +
310                                       formatv("{0:d}", WeakAlias.Alias));
311   }
312   return Error::success();
313 }
314 
315 // In COFF, most of the defined symbols don't contain the size information.
316 // Hence, we calculate the "implicit" size of symbol by taking the delta of
317 // offsets of consecutive symbols within a block. We maintain a balanced tree
318 // set of symbols sorted by offset per each block in order to achieve
319 // logarithmic time complexity of sorted symbol insertion. Symbol is inserted to
320 // the set once it's processed in graphifySymbols. In this function, we iterate
321 // each collected symbol in sorted order and calculate the implicit size.
322 Error COFFLinkGraphBuilder::calculateImplicitSizeOfSymbols() {
323   for (COFFSectionIndex SecIndex = 1;
324        SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections());
325        SecIndex++) {
326     auto &SymbolSet = SymbolSets[SecIndex];
327     jitlink::Block *B = getGraphBlock(SecIndex);
328     orc::ExecutorAddrDiff LastOffset = B->getSize();
329     orc::ExecutorAddrDiff LastDifferentOffset = B->getSize();
330     orc::ExecutorAddrDiff LastSize = 0;
331     for (auto It = SymbolSet.rbegin(); It != SymbolSet.rend(); It++) {
332       orc::ExecutorAddrDiff Offset = It->first;
333       jitlink::Symbol *Symbol = It->second;
334       orc::ExecutorAddrDiff CandSize;
335       // Last offset can be same when aliasing happened
336       if (Symbol->getOffset() == LastOffset)
337         CandSize = LastSize;
338       else
339         CandSize = LastOffset - Offset;
340 
341       LLVM_DEBUG({
342         if (Offset + Symbol->getSize() > LastDifferentOffset)
343           dbgs() << "  Overlapping symbol range generated for the following "
344                     "symbol:"
345                  << "\n"
346                  << "    " << *Symbol << "\n";
347       });
348       (void)LastDifferentOffset;
349       if (LastOffset != Offset)
350         LastDifferentOffset = Offset;
351       LastSize = CandSize;
352       LastOffset = Offset;
353       if (Symbol->getSize()) {
354         // Non empty symbol can happen in COMDAT symbol.
355         // We don't consider the possibility of overlapping symbol range that
356         // could be introduced by disparity between inferred symbol size and
357         // defined symbol size because symbol size information is currently only
358         // used by jitlink-check where we have control to not make overlapping
359         // ranges.
360         continue;
361       }
362 
363       LLVM_DEBUG({
364         if (!CandSize)
365           dbgs() << "  Empty implicit symbol size generated for the following "
366                     "symbol:"
367                  << "\n"
368                  << "    " << *Symbol << "\n";
369       });
370 
371       Symbol->setSize(CandSize);
372     }
373   }
374   return Error::success();
375 }
376 
377 Expected<Symbol *> COFFLinkGraphBuilder::createDefinedSymbol(
378     COFFSymbolIndex SymIndex, StringRef SymbolName,
379     object::COFFSymbolRef Symbol, const object::coff_section *Section) {
380   if (Symbol.isCommon()) {
381     // FIXME: correct alignment
382     return &G->addCommonSymbol(SymbolName, Scope::Default, getCommonSection(),
383                                orc::ExecutorAddr(), Symbol.getValue(),
384                                Symbol.getValue(), false);
385   }
386   if (Symbol.isAbsolute())
387     return &G->addAbsoluteSymbol(SymbolName,
388                                  orc::ExecutorAddr(Symbol.getValue()), 0,
389                                  Linkage::Strong, Scope::Local, false);
390 
391   if (llvm::COFF::isReservedSectionNumber(Symbol.getSectionNumber()))
392     return make_error<JITLinkError>(
393         "Reserved section number used in regular symbol " +
394         formatv("{0:d}", SymIndex));
395 
396   Block *B = getGraphBlock(Symbol.getSectionNumber());
397   if (Symbol.isExternal()) {
398     // This is not a comdat sequence, export the symbol as it is
399     if (!isComdatSection(Section))
400       return &G->addDefinedSymbol(
401           *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Default,
402           Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
403     else {
404       if (!PendingComdatExport)
405         return make_error<JITLinkError>("No pending COMDAT export for symbol " +
406                                         formatv("{0:d}", SymIndex));
407       if (PendingComdatExport->SectionIndex != Symbol.getSectionNumber())
408         return make_error<JITLinkError>(
409             "COMDAT export section number mismatch for symbol " +
410             formatv("{0:d}", SymIndex));
411       return exportCOMDATSymbol(SymIndex, SymbolName, Symbol);
412     }
413   }
414 
415   if (Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC) {
416     const object::coff_aux_section_definition *Definition =
417         Symbol.getSectionDefinition();
418     if (!Definition || !isComdatSection(Section)) {
419       // Handle typical static symbol
420       return &G->addDefinedSymbol(
421           *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local,
422           Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
423     }
424     if (Definition->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
425       // FIXME: don't dead strip this when parent section is alive
426       return &G->addDefinedSymbol(
427           *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local,
428           Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
429     }
430     if (PendingComdatExport)
431       return make_error<JITLinkError>(
432           "COMDAT export request already exists before symbol " +
433           formatv("{0:d}", SymIndex));
434     return createCOMDATExportRequest(SymIndex, Symbol, Definition);
435   }
436   return make_error<JITLinkError>("Unsupported storage class " +
437                                   formatv("{0:d}", Symbol.getStorageClass()) +
438                                   " in symbol " + formatv("{0:d}", SymIndex));
439 }
440 
441 // COMDAT handling:
442 // When IMAGE_SCN_LNK_COMDAT flag is set in the flags of a section,
443 // the section is called a COMDAT section. It contains two symbols
444 // in a sequence that specifes the behavior. First symbol is the section
445 // symbol which contains the size and name of the section. It also contains
446 // selection type that specifies how duplicate of the symbol is handled.
447 // Second symbol is COMDAT symbol which usually defines the external name and
448 // data type.
449 //
450 // Since two symbols always come in a specific order, we initiate pending COMDAT
451 // export request when we encounter the first symbol and actually exports it
452 // when we process the second symbol.
453 //
454 // Process the first symbol of COMDAT sequence.
455 Expected<Symbol *> COFFLinkGraphBuilder::createCOMDATExportRequest(
456     COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol,
457     const object::coff_aux_section_definition *Definition) {
458   Block *B = getGraphBlock(Symbol.getSectionNumber());
459   Linkage L = Linkage::Strong;
460   switch (Definition->Selection) {
461   case COFF::IMAGE_COMDAT_SELECT_NODUPLICATES: {
462     L = Linkage::Strong;
463     break;
464   }
465   case COFF::IMAGE_COMDAT_SELECT_ANY: {
466     L = Linkage::Weak;
467     break;
468   }
469   case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH:
470   case COFF::IMAGE_COMDAT_SELECT_SAME_SIZE: {
471     // FIXME: Implement size/content validation when LinkGraph is able to
472     // handle this.
473     L = Linkage::Weak;
474     break;
475   }
476   case COFF::IMAGE_COMDAT_SELECT_LARGEST: {
477     // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST when LinkGraph is able to
478     // handle this.
479     return make_error<JITLinkError>(
480         "IMAGE_COMDAT_SELECT_LARGEST is not supported.");
481   }
482   case COFF::IMAGE_COMDAT_SELECT_NEWEST: {
483     // Even link.exe doesn't support this selection properly.
484     return make_error<JITLinkError>(
485         "IMAGE_COMDAT_SELECT_NEWEST is not supported.");
486   }
487   default: {
488     return make_error<JITLinkError>("Invalid comdat selection type: " +
489                                     formatv("{0:d}", Definition->Selection));
490   }
491   }
492   PendingComdatExport = {SymIndex, Symbol.getSectionNumber(), L};
493   return &G->addAnonymousSymbol(*B, Symbol.getValue(), Definition->Length,
494                                 false, false);
495 }
496 
497 // Process the second symbol of COMDAT sequence.
498 Expected<Symbol *>
499 COFFLinkGraphBuilder::exportCOMDATSymbol(COFFSymbolIndex SymIndex,
500                                          StringRef SymbolName,
501                                          object::COFFSymbolRef Symbol) {
502   COFFSymbolIndex TargetIndex = PendingComdatExport->SymbolIndex;
503   Linkage L = PendingComdatExport->Linkage;
504   jitlink::Symbol *Target = getGraphSymbol(TargetIndex);
505   assert(Target && "COMDAT leaader is invalid.");
506   assert((llvm::count_if(G->defined_symbols(),
507                          [&](const jitlink::Symbol *Sym) {
508                            return Sym->getName() == SymbolName;
509                          }) == 0) &&
510          "Duplicate defined symbol");
511   Target->setName(SymbolName);
512   Target->setLinkage(L);
513   Target->setCallable(Symbol.getComplexType() ==
514                       COFF::IMAGE_SYM_DTYPE_FUNCTION);
515   Target->setScope(Scope::Default);
516   LLVM_DEBUG({
517     dbgs() << "    " << SymIndex
518            << ": Exporting COMDAT graph symbol for COFF symbol \"" << SymbolName
519            << "\" in section " << Symbol.getSectionNumber() << "\n";
520     dbgs() << "      " << *Target << "\n";
521   });
522   PendingComdatExport = None;
523   return Target;
524 }
525 
526 } // namespace jitlink
527 } // namespace llvm