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