xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp (revision 972a253a57b6f144b0e4a3e2080a2a0076ec55a0)
1753f127fSDimitry Andric //=--------- COFFLinkGraphBuilder.cpp - COFF LinkGraph builder ----------===//
2753f127fSDimitry Andric //
3753f127fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4753f127fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5753f127fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6753f127fSDimitry Andric //
7753f127fSDimitry Andric //===----------------------------------------------------------------------===//
8753f127fSDimitry Andric //
9753f127fSDimitry Andric // Generic COFF LinkGraph buliding code.
10753f127fSDimitry Andric //
11753f127fSDimitry Andric //===----------------------------------------------------------------------===//
12753f127fSDimitry Andric #include "COFFLinkGraphBuilder.h"
13753f127fSDimitry Andric 
14753f127fSDimitry Andric #define DEBUG_TYPE "jitlink"
15753f127fSDimitry Andric 
16753f127fSDimitry Andric static const char *CommonSectionName = "__common";
17753f127fSDimitry Andric 
18753f127fSDimitry Andric namespace llvm {
19753f127fSDimitry Andric namespace jitlink {
20753f127fSDimitry Andric 
21*972a253aSDimitry Andric static Triple createTripleWithCOFFFormat(Triple T) {
22*972a253aSDimitry Andric   T.setObjectFormat(Triple::COFF);
23*972a253aSDimitry Andric   return T;
24*972a253aSDimitry Andric }
25*972a253aSDimitry Andric 
26753f127fSDimitry Andric COFFLinkGraphBuilder::COFFLinkGraphBuilder(
27753f127fSDimitry Andric     const object::COFFObjectFile &Obj, Triple TT,
28753f127fSDimitry Andric     LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
29753f127fSDimitry Andric     : Obj(Obj),
30*972a253aSDimitry Andric       G(std::make_unique<LinkGraph>(Obj.getFileName().str(),
31*972a253aSDimitry Andric                                     createTripleWithCOFFFormat(TT),
32*972a253aSDimitry Andric                                     getPointerSize(Obj), getEndianness(Obj),
33*972a253aSDimitry Andric                                     std::move(GetEdgeKindName))) {
34753f127fSDimitry Andric   LLVM_DEBUG({
35753f127fSDimitry Andric     dbgs() << "Created COFFLinkGraphBuilder for \"" << Obj.getFileName()
36753f127fSDimitry Andric            << "\"\n";
37753f127fSDimitry Andric   });
38753f127fSDimitry Andric }
39753f127fSDimitry Andric 
40753f127fSDimitry Andric COFFLinkGraphBuilder::~COFFLinkGraphBuilder() = default;
41753f127fSDimitry Andric 
42753f127fSDimitry Andric unsigned
43753f127fSDimitry Andric COFFLinkGraphBuilder::getPointerSize(const object::COFFObjectFile &Obj) {
44753f127fSDimitry Andric   return Obj.getBytesInAddress();
45753f127fSDimitry Andric }
46753f127fSDimitry Andric 
47753f127fSDimitry Andric support::endianness
48753f127fSDimitry Andric COFFLinkGraphBuilder::getEndianness(const object::COFFObjectFile &Obj) {
49753f127fSDimitry Andric   return Obj.isLittleEndian() ? support::little : support::big;
50753f127fSDimitry Andric }
51753f127fSDimitry Andric 
52753f127fSDimitry Andric uint64_t COFFLinkGraphBuilder::getSectionSize(const object::COFFObjectFile &Obj,
53753f127fSDimitry Andric                                               const object::coff_section *Sec) {
54753f127fSDimitry Andric   // Consider the difference between executable form and object form.
55753f127fSDimitry Andric   // More information is inside COFFObjectFile::getSectionSize
56753f127fSDimitry Andric   if (Obj.getDOSHeader())
57753f127fSDimitry Andric     return std::min(Sec->VirtualSize, Sec->SizeOfRawData);
58753f127fSDimitry Andric   return Sec->SizeOfRawData;
59753f127fSDimitry Andric }
60753f127fSDimitry Andric 
61753f127fSDimitry Andric uint64_t
62753f127fSDimitry Andric COFFLinkGraphBuilder::getSectionAddress(const object::COFFObjectFile &Obj,
63753f127fSDimitry Andric                                         const object::coff_section *Section) {
64753f127fSDimitry Andric   return Section->VirtualAddress + Obj.getImageBase();
65753f127fSDimitry Andric }
66753f127fSDimitry Andric 
67753f127fSDimitry Andric bool COFFLinkGraphBuilder::isComdatSection(
68753f127fSDimitry Andric     const object::coff_section *Section) {
69753f127fSDimitry Andric   return Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT;
70753f127fSDimitry Andric }
71753f127fSDimitry Andric 
72753f127fSDimitry Andric Section &COFFLinkGraphBuilder::getCommonSection() {
73753f127fSDimitry Andric   if (!CommonSection)
74753f127fSDimitry Andric     CommonSection =
75753f127fSDimitry Andric         &G->createSection(CommonSectionName, MemProt::Read | MemProt::Write);
76753f127fSDimitry Andric   return *CommonSection;
77753f127fSDimitry Andric }
78753f127fSDimitry Andric 
79753f127fSDimitry Andric Expected<std::unique_ptr<LinkGraph>> COFFLinkGraphBuilder::buildGraph() {
80753f127fSDimitry Andric   if (!Obj.isRelocatableObject())
81753f127fSDimitry Andric     return make_error<JITLinkError>("Object is not a relocatable COFF file");
82753f127fSDimitry Andric 
83753f127fSDimitry Andric   if (auto Err = graphifySections())
84753f127fSDimitry Andric     return std::move(Err);
85753f127fSDimitry Andric 
86753f127fSDimitry Andric   if (auto Err = graphifySymbols())
87753f127fSDimitry Andric     return std::move(Err);
88753f127fSDimitry Andric 
89753f127fSDimitry Andric   if (auto Err = addRelocations())
90753f127fSDimitry Andric     return std::move(Err);
91753f127fSDimitry Andric 
92753f127fSDimitry Andric   return std::move(G);
93753f127fSDimitry Andric }
94753f127fSDimitry Andric 
95753f127fSDimitry Andric StringRef
96753f127fSDimitry Andric COFFLinkGraphBuilder::getCOFFSectionName(COFFSectionIndex SectionIndex,
97753f127fSDimitry Andric                                          const object::coff_section *Sec,
98753f127fSDimitry Andric                                          object::COFFSymbolRef Sym) {
99753f127fSDimitry Andric   switch (SectionIndex) {
100753f127fSDimitry Andric   case COFF::IMAGE_SYM_UNDEFINED: {
101753f127fSDimitry Andric     if (Sym.getValue())
102753f127fSDimitry Andric       return "(common)";
103753f127fSDimitry Andric     else
104753f127fSDimitry Andric       return "(external)";
105753f127fSDimitry Andric   }
106753f127fSDimitry Andric   case COFF::IMAGE_SYM_ABSOLUTE:
107753f127fSDimitry Andric     return "(absolute)";
108753f127fSDimitry Andric   case COFF::IMAGE_SYM_DEBUG: {
109753f127fSDimitry Andric     // Used with .file symbol
110753f127fSDimitry Andric     return "(debug)";
111753f127fSDimitry Andric   }
112753f127fSDimitry Andric   default: {
113753f127fSDimitry Andric     // Non reserved regular section numbers
114753f127fSDimitry Andric     if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(Sec))
115753f127fSDimitry Andric       return *SecNameOrErr;
116753f127fSDimitry Andric   }
117753f127fSDimitry Andric   }
118753f127fSDimitry Andric   return "";
119753f127fSDimitry Andric }
120753f127fSDimitry Andric 
121753f127fSDimitry Andric Error COFFLinkGraphBuilder::graphifySections() {
122753f127fSDimitry Andric   LLVM_DEBUG(dbgs() << "  Creating graph sections...\n");
123753f127fSDimitry Andric 
124753f127fSDimitry Andric   GraphBlocks.resize(Obj.getNumberOfSections() + 1);
125753f127fSDimitry Andric   // For each section...
126753f127fSDimitry Andric   for (COFFSectionIndex SecIndex = 1;
127753f127fSDimitry Andric        SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections());
128753f127fSDimitry Andric        SecIndex++) {
129753f127fSDimitry Andric     Expected<const object::coff_section *> Sec = Obj.getSection(SecIndex);
130753f127fSDimitry Andric     if (!Sec)
131753f127fSDimitry Andric       return Sec.takeError();
132753f127fSDimitry Andric 
133753f127fSDimitry Andric     StringRef SectionName;
134753f127fSDimitry Andric     if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(*Sec))
135753f127fSDimitry Andric       SectionName = *SecNameOrErr;
136753f127fSDimitry Andric 
137753f127fSDimitry Andric     // FIXME: Skip debug info sections
138753f127fSDimitry Andric 
139753f127fSDimitry Andric     LLVM_DEBUG({
140753f127fSDimitry Andric       dbgs() << "    "
141753f127fSDimitry Andric              << "Creating section for \"" << SectionName << "\"\n";
142753f127fSDimitry Andric     });
143753f127fSDimitry Andric 
144*972a253aSDimitry Andric     // FIXME: Revisit crash when dropping IMAGE_SCN_MEM_DISCARDABLE sections
145*972a253aSDimitry Andric 
146753f127fSDimitry Andric     // Get the section's memory protection flags.
147753f127fSDimitry Andric     MemProt Prot = MemProt::None;
148753f127fSDimitry Andric     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE)
149753f127fSDimitry Andric       Prot |= MemProt::Exec;
150753f127fSDimitry Andric     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_READ)
151753f127fSDimitry Andric       Prot |= MemProt::Read;
152753f127fSDimitry Andric     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_WRITE)
153753f127fSDimitry Andric       Prot |= MemProt::Write;
154753f127fSDimitry Andric 
155753f127fSDimitry Andric     // Look for existing sections first.
156753f127fSDimitry Andric     auto *GraphSec = G->findSectionByName(SectionName);
157753f127fSDimitry Andric     if (!GraphSec)
158753f127fSDimitry Andric       GraphSec = &G->createSection(SectionName, Prot);
159753f127fSDimitry Andric     if (GraphSec->getMemProt() != Prot)
160753f127fSDimitry Andric       return make_error<JITLinkError>("MemProt should match");
161753f127fSDimitry Andric 
162753f127fSDimitry Andric     Block *B = nullptr;
163753f127fSDimitry Andric     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
164753f127fSDimitry Andric       B = &G->createZeroFillBlock(
165753f127fSDimitry Andric           *GraphSec, getSectionSize(Obj, *Sec),
166753f127fSDimitry Andric           orc::ExecutorAddr(getSectionAddress(Obj, *Sec)),
167753f127fSDimitry Andric           (*Sec)->getAlignment(), 0);
168753f127fSDimitry Andric     else {
169753f127fSDimitry Andric       ArrayRef<uint8_t> Data;
170753f127fSDimitry Andric       if (auto Err = Obj.getSectionContents(*Sec, Data))
171753f127fSDimitry Andric         return Err;
172753f127fSDimitry Andric 
173753f127fSDimitry Andric       B = &G->createContentBlock(
174753f127fSDimitry Andric           *GraphSec,
175753f127fSDimitry Andric           ArrayRef<char>(reinterpret_cast<const char *>(Data.data()),
176753f127fSDimitry Andric                          Data.size()),
177753f127fSDimitry Andric           orc::ExecutorAddr(getSectionAddress(Obj, *Sec)),
178753f127fSDimitry Andric           (*Sec)->getAlignment(), 0);
179753f127fSDimitry Andric     }
180753f127fSDimitry Andric 
181753f127fSDimitry Andric     setGraphBlock(SecIndex, B);
182753f127fSDimitry Andric   }
183753f127fSDimitry Andric 
184753f127fSDimitry Andric   return Error::success();
185753f127fSDimitry Andric }
186753f127fSDimitry Andric 
187753f127fSDimitry Andric Error COFFLinkGraphBuilder::graphifySymbols() {
188753f127fSDimitry Andric   LLVM_DEBUG(dbgs() << "  Creating graph symbols...\n");
189753f127fSDimitry Andric 
190753f127fSDimitry Andric   SymbolSets.resize(Obj.getNumberOfSections() + 1);
191*972a253aSDimitry Andric   PendingComdatExports.resize(Obj.getNumberOfSections() + 1);
192753f127fSDimitry Andric   GraphSymbols.resize(Obj.getNumberOfSymbols());
193753f127fSDimitry Andric 
194753f127fSDimitry Andric   for (COFFSymbolIndex SymIndex = 0;
195753f127fSDimitry Andric        SymIndex < static_cast<COFFSymbolIndex>(Obj.getNumberOfSymbols());
196753f127fSDimitry Andric        SymIndex++) {
197753f127fSDimitry Andric     Expected<object::COFFSymbolRef> Sym = Obj.getSymbol(SymIndex);
198753f127fSDimitry Andric     if (!Sym)
199753f127fSDimitry Andric       return Sym.takeError();
200753f127fSDimitry Andric 
201753f127fSDimitry Andric     StringRef SymbolName;
202753f127fSDimitry Andric     if (Expected<StringRef> SymNameOrErr = Obj.getSymbolName(*Sym))
203753f127fSDimitry Andric       SymbolName = *SymNameOrErr;
204753f127fSDimitry Andric 
205753f127fSDimitry Andric     COFFSectionIndex SectionIndex = Sym->getSectionNumber();
206753f127fSDimitry Andric     const object::coff_section *Sec = nullptr;
207753f127fSDimitry Andric 
208753f127fSDimitry Andric     if (!COFF::isReservedSectionNumber(SectionIndex)) {
209753f127fSDimitry Andric       auto SecOrErr = Obj.getSection(SectionIndex);
210753f127fSDimitry Andric       if (!SecOrErr)
211753f127fSDimitry Andric         return make_error<JITLinkError>(
212753f127fSDimitry Andric             "Invalid COFF section number:" + formatv("{0:d}: ", SectionIndex) +
213753f127fSDimitry Andric             " (" + toString(SecOrErr.takeError()) + ")");
214753f127fSDimitry Andric       Sec = *SecOrErr;
215753f127fSDimitry Andric     }
216753f127fSDimitry Andric 
217753f127fSDimitry Andric     // Create jitlink symbol
218753f127fSDimitry Andric     jitlink::Symbol *GSym = nullptr;
219753f127fSDimitry Andric     if (Sym->isFileRecord())
220753f127fSDimitry Andric       LLVM_DEBUG({
221753f127fSDimitry Andric         dbgs() << "    " << SymIndex << ": Skipping FileRecord symbol \""
222753f127fSDimitry Andric                << SymbolName << "\" in "
223753f127fSDimitry Andric                << getCOFFSectionName(SectionIndex, Sec, *Sym)
224753f127fSDimitry Andric                << " (index: " << SectionIndex << ") \n";
225753f127fSDimitry Andric       });
226753f127fSDimitry Andric     else if (Sym->isUndefined()) {
227753f127fSDimitry Andric       LLVM_DEBUG({
228753f127fSDimitry Andric         dbgs() << "    " << SymIndex
229753f127fSDimitry Andric                << ": Creating external graph symbol for COFF symbol \""
230753f127fSDimitry Andric                << SymbolName << "\" in "
231753f127fSDimitry Andric                << getCOFFSectionName(SectionIndex, Sec, *Sym)
232753f127fSDimitry Andric                << " (index: " << SectionIndex << ") \n";
233753f127fSDimitry Andric       });
234*972a253aSDimitry Andric       if (!ExternalSymbols.count(SymbolName))
235*972a253aSDimitry Andric         ExternalSymbols[SymbolName] =
236753f127fSDimitry Andric             &G->addExternalSymbol(SymbolName, Sym->getValue(), Linkage::Strong);
237*972a253aSDimitry Andric       GSym = ExternalSymbols[SymbolName];
238753f127fSDimitry Andric     } else if (Sym->isWeakExternal()) {
239*972a253aSDimitry Andric       auto *WeakExternal = Sym->getAux<object::coff_aux_weak_external>();
240*972a253aSDimitry Andric       COFFSymbolIndex TagIndex = WeakExternal->TagIndex;
241*972a253aSDimitry Andric       uint32_t Characteristics = WeakExternal->Characteristics;
242*972a253aSDimitry Andric       WeakExternalRequests.push_back(
243*972a253aSDimitry Andric           {SymIndex, TagIndex, Characteristics, SymbolName});
244753f127fSDimitry Andric     } else {
245753f127fSDimitry Andric       Expected<jitlink::Symbol *> NewGSym =
246753f127fSDimitry Andric           createDefinedSymbol(SymIndex, SymbolName, *Sym, Sec);
247753f127fSDimitry Andric       if (!NewGSym)
248753f127fSDimitry Andric         return NewGSym.takeError();
249753f127fSDimitry Andric       GSym = *NewGSym;
250753f127fSDimitry Andric       if (GSym) {
251753f127fSDimitry Andric         LLVM_DEBUG({
252753f127fSDimitry Andric           dbgs() << "    " << SymIndex
253753f127fSDimitry Andric                  << ": Creating defined graph symbol for COFF symbol \""
254753f127fSDimitry Andric                  << SymbolName << "\" in "
255753f127fSDimitry Andric                  << getCOFFSectionName(SectionIndex, Sec, *Sym)
256753f127fSDimitry Andric                  << " (index: " << SectionIndex << ") \n";
257753f127fSDimitry Andric           dbgs() << "      " << *GSym << "\n";
258753f127fSDimitry Andric         });
259753f127fSDimitry Andric       }
260753f127fSDimitry Andric     }
261753f127fSDimitry Andric 
262753f127fSDimitry Andric     // Register the symbol
263753f127fSDimitry Andric     if (GSym)
264753f127fSDimitry Andric       setGraphSymbol(SectionIndex, SymIndex, *GSym);
265753f127fSDimitry Andric     SymIndex += Sym->getNumberOfAuxSymbols();
266753f127fSDimitry Andric   }
267753f127fSDimitry Andric 
268753f127fSDimitry Andric   if (auto Err = flushWeakAliasRequests())
269753f127fSDimitry Andric     return Err;
270753f127fSDimitry Andric 
271753f127fSDimitry Andric   if (auto Err = calculateImplicitSizeOfSymbols())
272753f127fSDimitry Andric     return Err;
273753f127fSDimitry Andric 
274753f127fSDimitry Andric   return Error::success();
275753f127fSDimitry Andric }
276753f127fSDimitry Andric 
277753f127fSDimitry Andric Error COFFLinkGraphBuilder::flushWeakAliasRequests() {
278753f127fSDimitry Andric   // Export the weak external symbols and alias it
279*972a253aSDimitry Andric   for (auto &WeakExternal : WeakExternalRequests) {
280*972a253aSDimitry Andric     if (auto *Target = getGraphSymbol(WeakExternal.Target)) {
281753f127fSDimitry Andric       Expected<object::COFFSymbolRef> AliasSymbol =
282*972a253aSDimitry Andric           Obj.getSymbol(WeakExternal.Alias);
283753f127fSDimitry Andric       if (!AliasSymbol)
284753f127fSDimitry Andric         return AliasSymbol.takeError();
285753f127fSDimitry Andric 
286*972a253aSDimitry Andric       // FIXME: IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY and
287*972a253aSDimitry Andric       // IMAGE_WEAK_EXTERN_SEARCH_LIBRARY are handled in the same way.
288*972a253aSDimitry Andric       Scope S =
289*972a253aSDimitry Andric           WeakExternal.Characteristics == COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS
290*972a253aSDimitry Andric               ? Scope::Default
291*972a253aSDimitry Andric               : Scope::Local;
292*972a253aSDimitry Andric 
293753f127fSDimitry Andric       // FIXME: Support this when there's a way to handle this.
294753f127fSDimitry Andric       if (!Target->isDefined())
295753f127fSDimitry Andric         return make_error<JITLinkError>("Weak external symbol with external "
296753f127fSDimitry Andric                                         "symbol as alternative not supported.");
297753f127fSDimitry Andric 
298753f127fSDimitry Andric       jitlink::Symbol *NewSymbol = &G->addDefinedSymbol(
299*972a253aSDimitry Andric           Target->getBlock(), Target->getOffset(), WeakExternal.SymbolName,
300*972a253aSDimitry Andric           Target->getSize(), Linkage::Weak, S, Target->isCallable(), false);
301*972a253aSDimitry Andric       setGraphSymbol(AliasSymbol->getSectionNumber(), WeakExternal.Alias,
302753f127fSDimitry Andric                      *NewSymbol);
303753f127fSDimitry Andric       LLVM_DEBUG({
304*972a253aSDimitry Andric         dbgs() << "    " << WeakExternal.Alias
305753f127fSDimitry Andric                << ": Creating weak external symbol for COFF symbol \""
306*972a253aSDimitry Andric                << WeakExternal.SymbolName << "\" in section "
307753f127fSDimitry Andric                << AliasSymbol->getSectionNumber() << "\n";
308753f127fSDimitry Andric         dbgs() << "      " << *NewSymbol << "\n";
309753f127fSDimitry Andric       });
310753f127fSDimitry Andric     } else
311753f127fSDimitry Andric       return make_error<JITLinkError>("Weak symbol alias requested but actual "
312753f127fSDimitry Andric                                       "symbol not found for symbol " +
313*972a253aSDimitry Andric                                       formatv("{0:d}", WeakExternal.Alias));
314753f127fSDimitry Andric   }
315753f127fSDimitry Andric   return Error::success();
316753f127fSDimitry Andric }
317753f127fSDimitry Andric 
318753f127fSDimitry Andric // In COFF, most of the defined symbols don't contain the size information.
319753f127fSDimitry Andric // Hence, we calculate the "implicit" size of symbol by taking the delta of
320753f127fSDimitry Andric // offsets of consecutive symbols within a block. We maintain a balanced tree
321753f127fSDimitry Andric // set of symbols sorted by offset per each block in order to achieve
322753f127fSDimitry Andric // logarithmic time complexity of sorted symbol insertion. Symbol is inserted to
323753f127fSDimitry Andric // the set once it's processed in graphifySymbols. In this function, we iterate
324753f127fSDimitry Andric // each collected symbol in sorted order and calculate the implicit size.
325753f127fSDimitry Andric Error COFFLinkGraphBuilder::calculateImplicitSizeOfSymbols() {
326753f127fSDimitry Andric   for (COFFSectionIndex SecIndex = 1;
327753f127fSDimitry Andric        SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections());
328753f127fSDimitry Andric        SecIndex++) {
329753f127fSDimitry Andric     auto &SymbolSet = SymbolSets[SecIndex];
330*972a253aSDimitry Andric     if (SymbolSet.empty())
331*972a253aSDimitry Andric       continue;
332753f127fSDimitry Andric     jitlink::Block *B = getGraphBlock(SecIndex);
333753f127fSDimitry Andric     orc::ExecutorAddrDiff LastOffset = B->getSize();
334753f127fSDimitry Andric     orc::ExecutorAddrDiff LastDifferentOffset = B->getSize();
335753f127fSDimitry Andric     orc::ExecutorAddrDiff LastSize = 0;
336753f127fSDimitry Andric     for (auto It = SymbolSet.rbegin(); It != SymbolSet.rend(); It++) {
337753f127fSDimitry Andric       orc::ExecutorAddrDiff Offset = It->first;
338753f127fSDimitry Andric       jitlink::Symbol *Symbol = It->second;
339753f127fSDimitry Andric       orc::ExecutorAddrDiff CandSize;
340753f127fSDimitry Andric       // Last offset can be same when aliasing happened
341753f127fSDimitry Andric       if (Symbol->getOffset() == LastOffset)
342753f127fSDimitry Andric         CandSize = LastSize;
343753f127fSDimitry Andric       else
344753f127fSDimitry Andric         CandSize = LastOffset - Offset;
345753f127fSDimitry Andric 
346753f127fSDimitry Andric       LLVM_DEBUG({
347753f127fSDimitry Andric         if (Offset + Symbol->getSize() > LastDifferentOffset)
348753f127fSDimitry Andric           dbgs() << "  Overlapping symbol range generated for the following "
349753f127fSDimitry Andric                     "symbol:"
350753f127fSDimitry Andric                  << "\n"
351753f127fSDimitry Andric                  << "    " << *Symbol << "\n";
352753f127fSDimitry Andric       });
353753f127fSDimitry Andric       (void)LastDifferentOffset;
354753f127fSDimitry Andric       if (LastOffset != Offset)
355753f127fSDimitry Andric         LastDifferentOffset = Offset;
356753f127fSDimitry Andric       LastSize = CandSize;
357753f127fSDimitry Andric       LastOffset = Offset;
358753f127fSDimitry Andric       if (Symbol->getSize()) {
359753f127fSDimitry Andric         // Non empty symbol can happen in COMDAT symbol.
360753f127fSDimitry Andric         // We don't consider the possibility of overlapping symbol range that
361753f127fSDimitry Andric         // could be introduced by disparity between inferred symbol size and
362753f127fSDimitry Andric         // defined symbol size because symbol size information is currently only
363753f127fSDimitry Andric         // used by jitlink-check where we have control to not make overlapping
364753f127fSDimitry Andric         // ranges.
365753f127fSDimitry Andric         continue;
366753f127fSDimitry Andric       }
367753f127fSDimitry Andric 
368753f127fSDimitry Andric       LLVM_DEBUG({
369753f127fSDimitry Andric         if (!CandSize)
370753f127fSDimitry Andric           dbgs() << "  Empty implicit symbol size generated for the following "
371753f127fSDimitry Andric                     "symbol:"
372753f127fSDimitry Andric                  << "\n"
373753f127fSDimitry Andric                  << "    " << *Symbol << "\n";
374753f127fSDimitry Andric       });
375753f127fSDimitry Andric 
376753f127fSDimitry Andric       Symbol->setSize(CandSize);
377753f127fSDimitry Andric     }
378753f127fSDimitry Andric   }
379753f127fSDimitry Andric   return Error::success();
380753f127fSDimitry Andric }
381753f127fSDimitry Andric 
382753f127fSDimitry Andric Expected<Symbol *> COFFLinkGraphBuilder::createDefinedSymbol(
383753f127fSDimitry Andric     COFFSymbolIndex SymIndex, StringRef SymbolName,
384753f127fSDimitry Andric     object::COFFSymbolRef Symbol, const object::coff_section *Section) {
385753f127fSDimitry Andric   if (Symbol.isCommon()) {
386753f127fSDimitry Andric     // FIXME: correct alignment
387753f127fSDimitry Andric     return &G->addCommonSymbol(SymbolName, Scope::Default, getCommonSection(),
388753f127fSDimitry Andric                                orc::ExecutorAddr(), Symbol.getValue(),
389753f127fSDimitry Andric                                Symbol.getValue(), false);
390753f127fSDimitry Andric   }
391753f127fSDimitry Andric   if (Symbol.isAbsolute())
392753f127fSDimitry Andric     return &G->addAbsoluteSymbol(SymbolName,
393753f127fSDimitry Andric                                  orc::ExecutorAddr(Symbol.getValue()), 0,
394753f127fSDimitry Andric                                  Linkage::Strong, Scope::Local, false);
395753f127fSDimitry Andric 
396753f127fSDimitry Andric   if (llvm::COFF::isReservedSectionNumber(Symbol.getSectionNumber()))
397753f127fSDimitry Andric     return make_error<JITLinkError>(
398753f127fSDimitry Andric         "Reserved section number used in regular symbol " +
399753f127fSDimitry Andric         formatv("{0:d}", SymIndex));
400753f127fSDimitry Andric 
401753f127fSDimitry Andric   Block *B = getGraphBlock(Symbol.getSectionNumber());
402*972a253aSDimitry Andric   if (!B) {
403*972a253aSDimitry Andric     LLVM_DEBUG({
404*972a253aSDimitry Andric       dbgs() << "    " << SymIndex
405*972a253aSDimitry Andric              << ": Skipping graph symbol since section was not created for "
406*972a253aSDimitry Andric                 "COFF symbol \""
407*972a253aSDimitry Andric              << SymbolName << "\" in section " << Symbol.getSectionNumber()
408*972a253aSDimitry Andric              << "\n";
409*972a253aSDimitry Andric     });
410*972a253aSDimitry Andric     return nullptr;
411*972a253aSDimitry Andric   }
412*972a253aSDimitry Andric 
413753f127fSDimitry Andric   if (Symbol.isExternal()) {
414753f127fSDimitry Andric     // This is not a comdat sequence, export the symbol as it is
415*972a253aSDimitry Andric     if (!isComdatSection(Section)) {
416*972a253aSDimitry Andric 
417753f127fSDimitry Andric       return &G->addDefinedSymbol(
418753f127fSDimitry Andric           *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Default,
419753f127fSDimitry Andric           Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
420*972a253aSDimitry Andric     } else {
421*972a253aSDimitry Andric       if (!PendingComdatExports[Symbol.getSectionNumber()])
422753f127fSDimitry Andric         return make_error<JITLinkError>("No pending COMDAT export for symbol " +
423753f127fSDimitry Andric                                         formatv("{0:d}", SymIndex));
424*972a253aSDimitry Andric 
425753f127fSDimitry Andric       return exportCOMDATSymbol(SymIndex, SymbolName, Symbol);
426753f127fSDimitry Andric     }
427753f127fSDimitry Andric   }
428753f127fSDimitry Andric 
429*972a253aSDimitry Andric   if (Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC ||
430*972a253aSDimitry Andric       Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_LABEL) {
431753f127fSDimitry Andric     const object::coff_aux_section_definition *Definition =
432753f127fSDimitry Andric         Symbol.getSectionDefinition();
433753f127fSDimitry Andric     if (!Definition || !isComdatSection(Section)) {
434753f127fSDimitry Andric       // Handle typical static symbol
435753f127fSDimitry Andric       return &G->addDefinedSymbol(
436753f127fSDimitry Andric           *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local,
437753f127fSDimitry Andric           Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
438753f127fSDimitry Andric     }
439753f127fSDimitry Andric     if (Definition->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
440*972a253aSDimitry Andric       auto Target = Definition->getNumber(Symbol.isBigObj());
441*972a253aSDimitry Andric       auto GSym = &G->addDefinedSymbol(
442753f127fSDimitry Andric           *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local,
443753f127fSDimitry Andric           Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
444*972a253aSDimitry Andric       getGraphBlock(Target)->addEdge(Edge::KeepAlive, 0, *GSym, 0);
445*972a253aSDimitry Andric       return GSym;
446753f127fSDimitry Andric     }
447*972a253aSDimitry Andric     if (PendingComdatExports[Symbol.getSectionNumber()])
448753f127fSDimitry Andric       return make_error<JITLinkError>(
449753f127fSDimitry Andric           "COMDAT export request already exists before symbol " +
450753f127fSDimitry Andric           formatv("{0:d}", SymIndex));
451753f127fSDimitry Andric     return createCOMDATExportRequest(SymIndex, Symbol, Definition);
452753f127fSDimitry Andric   }
453753f127fSDimitry Andric   return make_error<JITLinkError>("Unsupported storage class " +
454753f127fSDimitry Andric                                   formatv("{0:d}", Symbol.getStorageClass()) +
455753f127fSDimitry Andric                                   " in symbol " + formatv("{0:d}", SymIndex));
456753f127fSDimitry Andric }
457753f127fSDimitry Andric 
458753f127fSDimitry Andric // COMDAT handling:
459753f127fSDimitry Andric // When IMAGE_SCN_LNK_COMDAT flag is set in the flags of a section,
460753f127fSDimitry Andric // the section is called a COMDAT section. It contains two symbols
461753f127fSDimitry Andric // in a sequence that specifes the behavior. First symbol is the section
462753f127fSDimitry Andric // symbol which contains the size and name of the section. It also contains
463753f127fSDimitry Andric // selection type that specifies how duplicate of the symbol is handled.
464753f127fSDimitry Andric // Second symbol is COMDAT symbol which usually defines the external name and
465753f127fSDimitry Andric // data type.
466753f127fSDimitry Andric //
467753f127fSDimitry Andric // Since two symbols always come in a specific order, we initiate pending COMDAT
468753f127fSDimitry Andric // export request when we encounter the first symbol and actually exports it
469753f127fSDimitry Andric // when we process the second symbol.
470753f127fSDimitry Andric //
471753f127fSDimitry Andric // Process the first symbol of COMDAT sequence.
472753f127fSDimitry Andric Expected<Symbol *> COFFLinkGraphBuilder::createCOMDATExportRequest(
473753f127fSDimitry Andric     COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol,
474753f127fSDimitry Andric     const object::coff_aux_section_definition *Definition) {
475753f127fSDimitry Andric   Block *B = getGraphBlock(Symbol.getSectionNumber());
476753f127fSDimitry Andric   Linkage L = Linkage::Strong;
477753f127fSDimitry Andric   switch (Definition->Selection) {
478753f127fSDimitry Andric   case COFF::IMAGE_COMDAT_SELECT_NODUPLICATES: {
479753f127fSDimitry Andric     L = Linkage::Strong;
480753f127fSDimitry Andric     break;
481753f127fSDimitry Andric   }
482753f127fSDimitry Andric   case COFF::IMAGE_COMDAT_SELECT_ANY: {
483753f127fSDimitry Andric     L = Linkage::Weak;
484753f127fSDimitry Andric     break;
485753f127fSDimitry Andric   }
486753f127fSDimitry Andric   case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH:
487753f127fSDimitry Andric   case COFF::IMAGE_COMDAT_SELECT_SAME_SIZE: {
488753f127fSDimitry Andric     // FIXME: Implement size/content validation when LinkGraph is able to
489753f127fSDimitry Andric     // handle this.
490753f127fSDimitry Andric     L = Linkage::Weak;
491753f127fSDimitry Andric     break;
492753f127fSDimitry Andric   }
493753f127fSDimitry Andric   case COFF::IMAGE_COMDAT_SELECT_LARGEST: {
494*972a253aSDimitry Andric     // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST properly when LinkGraph is
495*972a253aSDimitry Andric     // able to handle this.
496*972a253aSDimitry Andric     LLVM_DEBUG({
497*972a253aSDimitry Andric       dbgs() << "    " << SymIndex
498*972a253aSDimitry Andric              << ": Partially supported IMAGE_COMDAT_SELECT_LARGEST was used"
499*972a253aSDimitry Andric                 " in section "
500*972a253aSDimitry Andric              << Symbol.getSectionNumber() << "\n";
501*972a253aSDimitry Andric     });
502*972a253aSDimitry Andric     L = Linkage::Weak;
503*972a253aSDimitry Andric     break;
504753f127fSDimitry Andric   }
505753f127fSDimitry Andric   case COFF::IMAGE_COMDAT_SELECT_NEWEST: {
506753f127fSDimitry Andric     // Even link.exe doesn't support this selection properly.
507753f127fSDimitry Andric     return make_error<JITLinkError>(
508753f127fSDimitry Andric         "IMAGE_COMDAT_SELECT_NEWEST is not supported.");
509753f127fSDimitry Andric   }
510753f127fSDimitry Andric   default: {
511753f127fSDimitry Andric     return make_error<JITLinkError>("Invalid comdat selection type: " +
512753f127fSDimitry Andric                                     formatv("{0:d}", Definition->Selection));
513753f127fSDimitry Andric   }
514753f127fSDimitry Andric   }
515*972a253aSDimitry Andric   PendingComdatExports[Symbol.getSectionNumber()] = {SymIndex, L};
516753f127fSDimitry Andric   return &G->addAnonymousSymbol(*B, Symbol.getValue(), Definition->Length,
517753f127fSDimitry Andric                                 false, false);
518753f127fSDimitry Andric }
519753f127fSDimitry Andric 
520753f127fSDimitry Andric // Process the second symbol of COMDAT sequence.
521753f127fSDimitry Andric Expected<Symbol *>
522753f127fSDimitry Andric COFFLinkGraphBuilder::exportCOMDATSymbol(COFFSymbolIndex SymIndex,
523753f127fSDimitry Andric                                          StringRef SymbolName,
524753f127fSDimitry Andric                                          object::COFFSymbolRef Symbol) {
525*972a253aSDimitry Andric   auto &PendingComdatExport = PendingComdatExports[Symbol.getSectionNumber()];
526753f127fSDimitry Andric   COFFSymbolIndex TargetIndex = PendingComdatExport->SymbolIndex;
527753f127fSDimitry Andric   Linkage L = PendingComdatExport->Linkage;
528753f127fSDimitry Andric   jitlink::Symbol *Target = getGraphSymbol(TargetIndex);
529753f127fSDimitry Andric   assert(Target && "COMDAT leaader is invalid.");
530753f127fSDimitry Andric   assert((llvm::count_if(G->defined_symbols(),
531753f127fSDimitry Andric                          [&](const jitlink::Symbol *Sym) {
532753f127fSDimitry Andric                            return Sym->getName() == SymbolName;
533753f127fSDimitry Andric                          }) == 0) &&
534753f127fSDimitry Andric          "Duplicate defined symbol");
535753f127fSDimitry Andric   Target->setName(SymbolName);
536753f127fSDimitry Andric   Target->setLinkage(L);
537753f127fSDimitry Andric   Target->setCallable(Symbol.getComplexType() ==
538753f127fSDimitry Andric                       COFF::IMAGE_SYM_DTYPE_FUNCTION);
539753f127fSDimitry Andric   Target->setScope(Scope::Default);
540753f127fSDimitry Andric   LLVM_DEBUG({
541753f127fSDimitry Andric     dbgs() << "    " << SymIndex
542753f127fSDimitry Andric            << ": Exporting COMDAT graph symbol for COFF symbol \"" << SymbolName
543753f127fSDimitry Andric            << "\" in section " << Symbol.getSectionNumber() << "\n";
544753f127fSDimitry Andric     dbgs() << "      " << *Target << "\n";
545753f127fSDimitry Andric   });
546753f127fSDimitry Andric   PendingComdatExport = None;
547753f127fSDimitry Andric   return Target;
548753f127fSDimitry Andric }
549753f127fSDimitry Andric 
550753f127fSDimitry Andric } // namespace jitlink
551753f127fSDimitry Andric } // namespace llvm
552