xref: /llvm-project/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp (revision 9c5001e45491ae8b1b2967d2fa48f445799c88ae)
1db995d72SSunho Kim //=--------- COFFLinkGraphBuilder.cpp - COFF LinkGraph builder ----------===//
2db995d72SSunho Kim //
3db995d72SSunho Kim // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4db995d72SSunho Kim // See https://llvm.org/LICENSE.txt for license information.
5db995d72SSunho Kim // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6db995d72SSunho Kim //
7db995d72SSunho Kim //===----------------------------------------------------------------------===//
8db995d72SSunho Kim //
994239712SEymen Ünay // Generic COFF LinkGraph building code.
10db995d72SSunho Kim //
11db995d72SSunho Kim //===----------------------------------------------------------------------===//
12db995d72SSunho Kim #include "COFFLinkGraphBuilder.h"
13db995d72SSunho Kim 
142ccf7ed2SJared Wyles #include <memory>
152ccf7ed2SJared Wyles 
16db995d72SSunho Kim #define DEBUG_TYPE "jitlink"
17db995d72SSunho Kim 
18db995d72SSunho Kim static const char *CommonSectionName = "__common";
19db995d72SSunho Kim 
20db995d72SSunho Kim namespace llvm {
21db995d72SSunho Kim namespace jitlink {
22db995d72SSunho Kim 
230f00e588SSunho Kim static Triple createTripleWithCOFFFormat(Triple T) {
240f00e588SSunho Kim   T.setObjectFormat(Triple::COFF);
250f00e588SSunho Kim   return T;
260f00e588SSunho Kim }
270f00e588SSunho Kim 
28db995d72SSunho Kim COFFLinkGraphBuilder::COFFLinkGraphBuilder(
292ccf7ed2SJared Wyles     const object::COFFObjectFile &Obj,
302ccf7ed2SJared Wyles     std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
312ccf7ed2SJared Wyles     SubtargetFeatures Features,
32db995d72SSunho Kim     LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
332ccf7ed2SJared Wyles     : Obj(Obj),
342ccf7ed2SJared Wyles       G(std::make_unique<LinkGraph>(Obj.getFileName().str(), std::move(SSP),
354eaff6c5SLang Hames                                     createTripleWithCOFFFormat(std::move(TT)),
364eaff6c5SLang Hames                                     std::move(Features),
372ccf7ed2SJared Wyles                                     std::move(GetEdgeKindName))) {
38db995d72SSunho Kim   LLVM_DEBUG({
39db995d72SSunho Kim     dbgs() << "Created COFFLinkGraphBuilder for \"" << Obj.getFileName()
40db995d72SSunho Kim            << "\"\n";
41db995d72SSunho Kim   });
42db995d72SSunho Kim }
43db995d72SSunho Kim 
44db995d72SSunho Kim COFFLinkGraphBuilder::~COFFLinkGraphBuilder() = default;
45db995d72SSunho Kim 
46db995d72SSunho Kim uint64_t COFFLinkGraphBuilder::getSectionSize(const object::COFFObjectFile &Obj,
47db995d72SSunho Kim                                               const object::coff_section *Sec) {
48db995d72SSunho Kim   // Consider the difference between executable form and object form.
49db995d72SSunho Kim   // More information is inside COFFObjectFile::getSectionSize
50db995d72SSunho Kim   if (Obj.getDOSHeader())
51db995d72SSunho Kim     return std::min(Sec->VirtualSize, Sec->SizeOfRawData);
52db995d72SSunho Kim   return Sec->SizeOfRawData;
53db995d72SSunho Kim }
54db995d72SSunho Kim 
55db995d72SSunho Kim uint64_t
56db995d72SSunho Kim COFFLinkGraphBuilder::getSectionAddress(const object::COFFObjectFile &Obj,
57db995d72SSunho Kim                                         const object::coff_section *Section) {
58db995d72SSunho Kim   return Section->VirtualAddress + Obj.getImageBase();
59db995d72SSunho Kim }
60db995d72SSunho Kim 
61db995d72SSunho Kim bool COFFLinkGraphBuilder::isComdatSection(
62db995d72SSunho Kim     const object::coff_section *Section) {
63db995d72SSunho Kim   return Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT;
64db995d72SSunho Kim }
65db995d72SSunho Kim 
66db995d72SSunho Kim Section &COFFLinkGraphBuilder::getCommonSection() {
67db995d72SSunho Kim   if (!CommonSection)
68d3d9f7caSLang Hames     CommonSection = &G->createSection(CommonSectionName,
69d3d9f7caSLang Hames                                       orc::MemProt::Read | orc::MemProt::Write);
70db995d72SSunho Kim   return *CommonSection;
71db995d72SSunho Kim }
72db995d72SSunho Kim 
73db995d72SSunho Kim Expected<std::unique_ptr<LinkGraph>> COFFLinkGraphBuilder::buildGraph() {
74db995d72SSunho Kim   if (!Obj.isRelocatableObject())
75db995d72SSunho Kim     return make_error<JITLinkError>("Object is not a relocatable COFF file");
76db995d72SSunho Kim 
77db995d72SSunho Kim   if (auto Err = graphifySections())
78db995d72SSunho Kim     return std::move(Err);
79db995d72SSunho Kim 
80db995d72SSunho Kim   if (auto Err = graphifySymbols())
81db995d72SSunho Kim     return std::move(Err);
82db995d72SSunho Kim 
83db995d72SSunho Kim   if (auto Err = addRelocations())
84db995d72SSunho Kim     return std::move(Err);
85db995d72SSunho Kim 
86db995d72SSunho Kim   return std::move(G);
87db995d72SSunho Kim }
88db995d72SSunho Kim 
89db995d72SSunho Kim StringRef
90db995d72SSunho Kim COFFLinkGraphBuilder::getCOFFSectionName(COFFSectionIndex SectionIndex,
91db995d72SSunho Kim                                          const object::coff_section *Sec,
92db995d72SSunho Kim                                          object::COFFSymbolRef Sym) {
93db995d72SSunho Kim   switch (SectionIndex) {
94db995d72SSunho Kim   case COFF::IMAGE_SYM_UNDEFINED: {
95db995d72SSunho Kim     if (Sym.getValue())
96db995d72SSunho Kim       return "(common)";
97db995d72SSunho Kim     else
98db995d72SSunho Kim       return "(external)";
99db995d72SSunho Kim   }
100db995d72SSunho Kim   case COFF::IMAGE_SYM_ABSOLUTE:
101db995d72SSunho Kim     return "(absolute)";
102db995d72SSunho Kim   case COFF::IMAGE_SYM_DEBUG: {
103db995d72SSunho Kim     // Used with .file symbol
104db995d72SSunho Kim     return "(debug)";
105db995d72SSunho Kim   }
106db995d72SSunho Kim   default: {
107db995d72SSunho Kim     // Non reserved regular section numbers
108db995d72SSunho Kim     if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(Sec))
109db995d72SSunho Kim       return *SecNameOrErr;
110db995d72SSunho Kim   }
111db995d72SSunho Kim   }
112db995d72SSunho Kim   return "";
113db995d72SSunho Kim }
114db995d72SSunho Kim 
115db995d72SSunho Kim Error COFFLinkGraphBuilder::graphifySections() {
116db995d72SSunho Kim   LLVM_DEBUG(dbgs() << "  Creating graph sections...\n");
117db995d72SSunho Kim 
118db995d72SSunho Kim   GraphBlocks.resize(Obj.getNumberOfSections() + 1);
119db995d72SSunho Kim   // For each section...
120e5ff1a7fSsunho   for (COFFSectionIndex SecIndex = 1;
121e5ff1a7fSsunho        SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections());
122db995d72SSunho Kim        SecIndex++) {
123db995d72SSunho Kim     Expected<const object::coff_section *> Sec = Obj.getSection(SecIndex);
124db995d72SSunho Kim     if (!Sec)
125db995d72SSunho Kim       return Sec.takeError();
126db995d72SSunho Kim 
127db995d72SSunho Kim     StringRef SectionName;
128db995d72SSunho Kim     if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(*Sec))
129db995d72SSunho Kim       SectionName = *SecNameOrErr;
130db995d72SSunho Kim 
131db995d72SSunho Kim     // FIXME: Skip debug info sections
132639e411cSRiver Riddle     if (SectionName == ".voltbl") {
133639e411cSRiver Riddle       LLVM_DEBUG({
134639e411cSRiver Riddle         dbgs() << "    "
135639e411cSRiver Riddle                << "Skipping section \"" << SectionName << "\"\n";
136639e411cSRiver Riddle       });
137639e411cSRiver Riddle       continue;
138639e411cSRiver Riddle     }
139db995d72SSunho Kim 
140db995d72SSunho Kim     LLVM_DEBUG({
141db995d72SSunho Kim       dbgs() << "    "
142db995d72SSunho Kim              << "Creating section for \"" << SectionName << "\"\n";
143db995d72SSunho Kim     });
144db995d72SSunho Kim 
145db995d72SSunho Kim     // Get the section's memory protection flags.
146d3d9f7caSLang Hames     orc::MemProt Prot = orc::MemProt::Read;
147db995d72SSunho Kim     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE)
148d3d9f7caSLang Hames       Prot |= orc::MemProt::Exec;
149db995d72SSunho Kim     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_READ)
150d3d9f7caSLang Hames       Prot |= orc::MemProt::Read;
151db995d72SSunho Kim     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_WRITE)
152d3d9f7caSLang Hames       Prot |= orc::MemProt::Write;
153db995d72SSunho Kim 
154db995d72SSunho Kim     // Look for existing sections first.
155db995d72SSunho Kim     auto *GraphSec = G->findSectionByName(SectionName);
1560b7e16afSLang Hames     if (!GraphSec) {
157db995d72SSunho Kim       GraphSec = &G->createSection(SectionName, Prot);
1580b7e16afSLang Hames       if ((*Sec)->Characteristics & COFF::IMAGE_SCN_LNK_REMOVE)
159e994f84cSLang Hames         GraphSec->setMemLifetime(orc::MemLifetime::NoAlloc);
1600b7e16afSLang Hames     }
161db995d72SSunho Kim     if (GraphSec->getMemProt() != Prot)
162db995d72SSunho Kim       return make_error<JITLinkError>("MemProt should match");
163db995d72SSunho Kim 
164db995d72SSunho Kim     Block *B = nullptr;
165db995d72SSunho Kim     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
166db995d72SSunho Kim       B = &G->createZeroFillBlock(
167db995d72SSunho Kim           *GraphSec, getSectionSize(Obj, *Sec),
168db995d72SSunho Kim           orc::ExecutorAddr(getSectionAddress(Obj, *Sec)),
1693e5f54d6SGuillaume Chatelet           (*Sec)->getAlignment(), 0);
170db995d72SSunho Kim     else {
171db995d72SSunho Kim       ArrayRef<uint8_t> Data;
172db995d72SSunho Kim       if (auto Err = Obj.getSectionContents(*Sec, Data))
173db995d72SSunho Kim         return Err;
174db995d72SSunho Kim 
17588181375SSunho Kim       auto CharData = ArrayRef<char>(
17688181375SSunho Kim           reinterpret_cast<const char *>(Data.data()), Data.size());
17788181375SSunho Kim 
17888181375SSunho Kim       if (SectionName == getDirectiveSectionName())
17988181375SSunho Kim         if (auto Err = handleDirectiveSection(
18088181375SSunho Kim                 StringRef(CharData.data(), CharData.size())))
18188181375SSunho Kim           return Err;
18288181375SSunho Kim 
183db995d72SSunho Kim       B = &G->createContentBlock(
18488181375SSunho Kim           *GraphSec, CharData, orc::ExecutorAddr(getSectionAddress(Obj, *Sec)),
1853e5f54d6SGuillaume Chatelet           (*Sec)->getAlignment(), 0);
186db995d72SSunho Kim     }
187db995d72SSunho Kim 
188db995d72SSunho Kim     setGraphBlock(SecIndex, B);
189db995d72SSunho Kim   }
190db995d72SSunho Kim 
191db995d72SSunho Kim   return Error::success();
192db995d72SSunho Kim }
193db995d72SSunho Kim 
194db995d72SSunho Kim Error COFFLinkGraphBuilder::graphifySymbols() {
195db995d72SSunho Kim   LLVM_DEBUG(dbgs() << "  Creating graph symbols...\n");
196db995d72SSunho Kim 
197db995d72SSunho Kim   SymbolSets.resize(Obj.getNumberOfSections() + 1);
19807aa8fc8SSunho Kim   PendingComdatExports.resize(Obj.getNumberOfSections() + 1);
199db995d72SSunho Kim   GraphSymbols.resize(Obj.getNumberOfSymbols());
200db995d72SSunho Kim 
201e5ff1a7fSsunho   for (COFFSymbolIndex SymIndex = 0;
202e5ff1a7fSsunho        SymIndex < static_cast<COFFSymbolIndex>(Obj.getNumberOfSymbols());
203db995d72SSunho Kim        SymIndex++) {
204db995d72SSunho Kim     Expected<object::COFFSymbolRef> Sym = Obj.getSymbol(SymIndex);
205db995d72SSunho Kim     if (!Sym)
206db995d72SSunho Kim       return Sym.takeError();
207db995d72SSunho Kim 
208db995d72SSunho Kim     StringRef SymbolName;
209db995d72SSunho Kim     if (Expected<StringRef> SymNameOrErr = Obj.getSymbolName(*Sym))
210db995d72SSunho Kim       SymbolName = *SymNameOrErr;
211db995d72SSunho Kim 
212db995d72SSunho Kim     COFFSectionIndex SectionIndex = Sym->getSectionNumber();
213db995d72SSunho Kim     const object::coff_section *Sec = nullptr;
214db995d72SSunho Kim 
215db995d72SSunho Kim     if (!COFF::isReservedSectionNumber(SectionIndex)) {
216db995d72SSunho Kim       auto SecOrErr = Obj.getSection(SectionIndex);
217db995d72SSunho Kim       if (!SecOrErr)
218db995d72SSunho Kim         return make_error<JITLinkError>(
219db995d72SSunho Kim             "Invalid COFF section number:" + formatv("{0:d}: ", SectionIndex) +
220db995d72SSunho Kim             " (" + toString(SecOrErr.takeError()) + ")");
221db995d72SSunho Kim       Sec = *SecOrErr;
222db995d72SSunho Kim     }
2232ccf7ed2SJared Wyles     auto InternedSymbolName = G->intern(std::move(SymbolName));
224db995d72SSunho Kim 
225db995d72SSunho Kim     // Create jitlink symbol
226db995d72SSunho Kim     jitlink::Symbol *GSym = nullptr;
227db995d72SSunho Kim     if (Sym->isFileRecord())
228db995d72SSunho Kim       LLVM_DEBUG({
229db995d72SSunho Kim         dbgs() << "    " << SymIndex << ": Skipping FileRecord symbol \""
2302ccf7ed2SJared Wyles                << InternedSymbolName << "\" in "
231db995d72SSunho Kim                << getCOFFSectionName(SectionIndex, Sec, *Sym)
232db995d72SSunho Kim                << " (index: " << SectionIndex << ") \n";
233db995d72SSunho Kim       });
234db995d72SSunho Kim     else if (Sym->isUndefined()) {
2352ccf7ed2SJared Wyles       GSym = createExternalSymbol(SymIndex, InternedSymbolName, *Sym, Sec);
236db995d72SSunho Kim     } else if (Sym->isWeakExternal()) {
237736b6311SSunho Kim       auto *WeakExternal = Sym->getAux<object::coff_aux_weak_external>();
238736b6311SSunho Kim       COFFSymbolIndex TagIndex = WeakExternal->TagIndex;
239736b6311SSunho Kim       uint32_t Characteristics = WeakExternal->Characteristics;
240736b6311SSunho Kim       WeakExternalRequests.push_back(
241736b6311SSunho Kim           {SymIndex, TagIndex, Characteristics, SymbolName});
242db995d72SSunho Kim     } else {
243db995d72SSunho Kim       Expected<jitlink::Symbol *> NewGSym =
2442ccf7ed2SJared Wyles           createDefinedSymbol(SymIndex, InternedSymbolName, *Sym, Sec);
245db995d72SSunho Kim       if (!NewGSym)
246db995d72SSunho Kim         return NewGSym.takeError();
247db995d72SSunho Kim       GSym = *NewGSym;
248db995d72SSunho Kim       if (GSym) {
249db995d72SSunho Kim         LLVM_DEBUG({
250db995d72SSunho Kim           dbgs() << "    " << SymIndex
251db995d72SSunho Kim                  << ": Creating defined graph symbol for COFF symbol \""
2522ccf7ed2SJared Wyles                  << InternedSymbolName << "\" in "
253db995d72SSunho Kim                  << getCOFFSectionName(SectionIndex, Sec, *Sym)
254db995d72SSunho Kim                  << " (index: " << SectionIndex << ") \n";
255db995d72SSunho Kim           dbgs() << "      " << *GSym << "\n";
256db995d72SSunho Kim         });
257db995d72SSunho Kim       }
258db995d72SSunho Kim     }
259db995d72SSunho Kim 
260db995d72SSunho Kim     // Register the symbol
261db995d72SSunho Kim     if (GSym)
262db995d72SSunho Kim       setGraphSymbol(SectionIndex, SymIndex, *GSym);
263db995d72SSunho Kim     SymIndex += Sym->getNumberOfAuxSymbols();
264db995d72SSunho Kim   }
265db995d72SSunho Kim 
266db995d72SSunho Kim   if (auto Err = flushWeakAliasRequests())
267db995d72SSunho Kim     return Err;
268db995d72SSunho Kim 
26988181375SSunho Kim   if (auto Err = handleAlternateNames())
27088181375SSunho Kim     return Err;
27188181375SSunho Kim 
272db995d72SSunho Kim   if (auto Err = calculateImplicitSizeOfSymbols())
273db995d72SSunho Kim     return Err;
274db995d72SSunho Kim 
275db995d72SSunho Kim   return Error::success();
276db995d72SSunho Kim }
277db995d72SSunho Kim 
27888181375SSunho Kim Error COFFLinkGraphBuilder::handleDirectiveSection(StringRef Str) {
27988181375SSunho Kim   auto Parsed = DirectiveParser.parse(Str);
28088181375SSunho Kim   if (!Parsed)
28188181375SSunho Kim     return Parsed.takeError();
282ea75c258SSunho Kim   for (auto *Arg : *Parsed) {
28388181375SSunho Kim     StringRef S = Arg->getValue();
28488181375SSunho Kim     switch (Arg->getOption().getID()) {
28588181375SSunho Kim     case COFF_OPT_alternatename: {
28688181375SSunho Kim       StringRef From, To;
28788181375SSunho Kim       std::tie(From, To) = S.split('=');
28888181375SSunho Kim       if (From.empty() || To.empty())
28988181375SSunho Kim         return make_error<JITLinkError>(
29088181375SSunho Kim             "Invalid COFF /alternatename directive");
2912ccf7ed2SJared Wyles       AlternateNames[G->intern(From)] = G->intern(To);
29288181375SSunho Kim       break;
29388181375SSunho Kim     }
29488181375SSunho Kim     case COFF_OPT_incl: {
2952ccf7ed2SJared Wyles       auto Symbol = &G->addExternalSymbol(S, 0, false);
2962ccf7ed2SJared Wyles       Symbol->setLive(true);
2972ccf7ed2SJared Wyles       ExternalSymbols[Symbol->getName()] = Symbol;
29888181375SSunho Kim       break;
29988181375SSunho Kim     }
30088181375SSunho Kim     case COFF_OPT_export:
30188181375SSunho Kim       break;
30288181375SSunho Kim     default: {
30388181375SSunho Kim       LLVM_DEBUG({
30488181375SSunho Kim         dbgs() << "Unknown coff directive: " << Arg->getSpelling() << "\n";
30588181375SSunho Kim       });
30688181375SSunho Kim       break;
30788181375SSunho Kim     }
30888181375SSunho Kim     }
30988181375SSunho Kim   }
31088181375SSunho Kim   return Error::success();
31188181375SSunho Kim }
31288181375SSunho Kim 
313db995d72SSunho Kim Error COFFLinkGraphBuilder::flushWeakAliasRequests() {
314db995d72SSunho Kim   // Export the weak external symbols and alias it
315736b6311SSunho Kim   for (auto &WeakExternal : WeakExternalRequests) {
316736b6311SSunho Kim     if (auto *Target = getGraphSymbol(WeakExternal.Target)) {
317db995d72SSunho Kim       Expected<object::COFFSymbolRef> AliasSymbol =
318736b6311SSunho Kim           Obj.getSymbol(WeakExternal.Alias);
319db995d72SSunho Kim       if (!AliasSymbol)
320db995d72SSunho Kim         return AliasSymbol.takeError();
321db995d72SSunho Kim 
322736b6311SSunho Kim       // FIXME: IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY and
323736b6311SSunho Kim       // IMAGE_WEAK_EXTERN_SEARCH_LIBRARY are handled in the same way.
324736b6311SSunho Kim       Scope S =
325736b6311SSunho Kim           WeakExternal.Characteristics == COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS
326736b6311SSunho Kim               ? Scope::Default
327736b6311SSunho Kim               : Scope::Local;
328736b6311SSunho Kim 
3292ccf7ed2SJared Wyles       auto NewSymbol = createAliasSymbol(G->intern(WeakExternal.SymbolName),
3302ccf7ed2SJared Wyles                                          Linkage::Weak, S, *Target);
33188181375SSunho Kim       if (!NewSymbol)
33288181375SSunho Kim         return NewSymbol.takeError();
333736b6311SSunho Kim       setGraphSymbol(AliasSymbol->getSectionNumber(), WeakExternal.Alias,
33488181375SSunho Kim                      **NewSymbol);
335db995d72SSunho Kim       LLVM_DEBUG({
336736b6311SSunho Kim         dbgs() << "    " << WeakExternal.Alias
337db995d72SSunho Kim                << ": Creating weak external symbol for COFF symbol \""
338736b6311SSunho Kim                << WeakExternal.SymbolName << "\" in section "
339db995d72SSunho Kim                << AliasSymbol->getSectionNumber() << "\n";
34088181375SSunho Kim         dbgs() << "      " << **NewSymbol << "\n";
341db995d72SSunho Kim       });
342db995d72SSunho Kim     } else
343db995d72SSunho Kim       return make_error<JITLinkError>("Weak symbol alias requested but actual "
344db995d72SSunho Kim                                       "symbol not found for symbol " +
345736b6311SSunho Kim                                       formatv("{0:d}", WeakExternal.Alias));
346db995d72SSunho Kim   }
347db995d72SSunho Kim   return Error::success();
348db995d72SSunho Kim }
349db995d72SSunho Kim 
35088181375SSunho Kim Error COFFLinkGraphBuilder::handleAlternateNames() {
3512ccf7ed2SJared Wyles   for (auto &KeyValue : AlternateNames) {
3522ccf7ed2SJared Wyles     auto DefinedSymbolName = KeyValue.second;
3532ccf7ed2SJared Wyles     auto ExternalSymbolsName = KeyValue.first;
3542ccf7ed2SJared Wyles     if (DefinedSymbols.count(DefinedSymbolName) &&
3552ccf7ed2SJared Wyles         ExternalSymbols.count(ExternalSymbolsName)) {
3562ccf7ed2SJared Wyles       auto *Target = DefinedSymbols[DefinedSymbolName];
3572ccf7ed2SJared Wyles       auto *Alias = ExternalSymbols[ExternalSymbolsName];
35888181375SSunho Kim       G->makeDefined(*Alias, Target->getBlock(), Target->getOffset(),
35988181375SSunho Kim                      Target->getSize(), Linkage::Weak, Scope::Local, false);
36088181375SSunho Kim     }
3612ccf7ed2SJared Wyles   }
36288181375SSunho Kim   return Error::success();
36388181375SSunho Kim }
36488181375SSunho Kim 
36588181375SSunho Kim Symbol *COFFLinkGraphBuilder::createExternalSymbol(
3662ccf7ed2SJared Wyles     COFFSymbolIndex SymIndex, orc::SymbolStringPtr SymbolName,
36788181375SSunho Kim     object::COFFSymbolRef Symbol, const object::coff_section *Section) {
3682ccf7ed2SJared Wyles   llvm::jitlink::Symbol *Sym = nullptr;
3692ccf7ed2SJared Wyles   if (!ExternalSymbols.count(SymbolName)) {
3702ccf7ed2SJared Wyles     Sym = &G->addExternalSymbol(*SymbolName, Symbol.getValue(), false);
3712ccf7ed2SJared Wyles     ExternalSymbols[Sym->getName()] = Sym;
3722ccf7ed2SJared Wyles   } else {
3732ccf7ed2SJared Wyles     Sym = ExternalSymbols[SymbolName];
3742ccf7ed2SJared Wyles   }
37588181375SSunho Kim 
37688181375SSunho Kim   LLVM_DEBUG({
37788181375SSunho Kim     dbgs() << "    " << SymIndex
37888181375SSunho Kim            << ": Creating external graph symbol for COFF symbol \""
3792ccf7ed2SJared Wyles            << Sym->getName() << "\" in "
38088181375SSunho Kim            << getCOFFSectionName(Symbol.getSectionNumber(), Section, Symbol)
38188181375SSunho Kim            << " (index: " << Symbol.getSectionNumber() << ") \n";
38288181375SSunho Kim   });
3832ccf7ed2SJared Wyles   return Sym;
38488181375SSunho Kim }
38588181375SSunho Kim 
3862ccf7ed2SJared Wyles Expected<Symbol *>
3872ccf7ed2SJared Wyles COFFLinkGraphBuilder::createAliasSymbol(orc::SymbolStringPtr SymbolName,
3882ccf7ed2SJared Wyles                                         Linkage L, Scope S, Symbol &Target) {
38988181375SSunho Kim   if (!Target.isDefined()) {
39088181375SSunho Kim     // FIXME: Support this when there's a way to handle this.
39188181375SSunho Kim     return make_error<JITLinkError>("Weak external symbol with external "
39288181375SSunho Kim                                     "symbol as alternative not supported.");
39388181375SSunho Kim   }
39488181375SSunho Kim   return &G->addDefinedSymbol(Target.getBlock(), Target.getOffset(), SymbolName,
39588181375SSunho Kim                               Target.getSize(), L, S, Target.isCallable(),
39688181375SSunho Kim                               false);
39788181375SSunho Kim }
39888181375SSunho Kim 
399db995d72SSunho Kim // In COFF, most of the defined symbols don't contain the size information.
400db995d72SSunho Kim // Hence, we calculate the "implicit" size of symbol by taking the delta of
401db995d72SSunho Kim // offsets of consecutive symbols within a block. We maintain a balanced tree
402db995d72SSunho Kim // set of symbols sorted by offset per each block in order to achieve
403db995d72SSunho Kim // logarithmic time complexity of sorted symbol insertion. Symbol is inserted to
404db995d72SSunho Kim // the set once it's processed in graphifySymbols. In this function, we iterate
405db995d72SSunho Kim // each collected symbol in sorted order and calculate the implicit size.
406db995d72SSunho Kim Error COFFLinkGraphBuilder::calculateImplicitSizeOfSymbols() {
407e5ff1a7fSsunho   for (COFFSectionIndex SecIndex = 1;
408e5ff1a7fSsunho        SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections());
409db995d72SSunho Kim        SecIndex++) {
410db995d72SSunho Kim     auto &SymbolSet = SymbolSets[SecIndex];
4110f00e588SSunho Kim     if (SymbolSet.empty())
4120f00e588SSunho Kim       continue;
413db995d72SSunho Kim     jitlink::Block *B = getGraphBlock(SecIndex);
414db995d72SSunho Kim     orc::ExecutorAddrDiff LastOffset = B->getSize();
415db995d72SSunho Kim     orc::ExecutorAddrDiff LastDifferentOffset = B->getSize();
416db995d72SSunho Kim     orc::ExecutorAddrDiff LastSize = 0;
417db995d72SSunho Kim     for (auto It = SymbolSet.rbegin(); It != SymbolSet.rend(); It++) {
418db995d72SSunho Kim       orc::ExecutorAddrDiff Offset = It->first;
419db995d72SSunho Kim       jitlink::Symbol *Symbol = It->second;
420db995d72SSunho Kim       orc::ExecutorAddrDiff CandSize;
421db995d72SSunho Kim       // Last offset can be same when aliasing happened
422db995d72SSunho Kim       if (Symbol->getOffset() == LastOffset)
423db995d72SSunho Kim         CandSize = LastSize;
424db995d72SSunho Kim       else
425db995d72SSunho Kim         CandSize = LastOffset - Offset;
426db995d72SSunho Kim 
427db995d72SSunho Kim       LLVM_DEBUG({
428db995d72SSunho Kim         if (Offset + Symbol->getSize() > LastDifferentOffset)
429db995d72SSunho Kim           dbgs() << "  Overlapping symbol range generated for the following "
430db995d72SSunho Kim                     "symbol:"
431db995d72SSunho Kim                  << "\n"
432db995d72SSunho Kim                  << "    " << *Symbol << "\n";
433db995d72SSunho Kim       });
43418a6ab5bSSunho Kim       (void)LastDifferentOffset;
435db995d72SSunho Kim       if (LastOffset != Offset)
436db995d72SSunho Kim         LastDifferentOffset = Offset;
437db995d72SSunho Kim       LastSize = CandSize;
438db995d72SSunho Kim       LastOffset = Offset;
439db995d72SSunho Kim       if (Symbol->getSize()) {
440db995d72SSunho Kim         // Non empty symbol can happen in COMDAT symbol.
441db995d72SSunho Kim         // We don't consider the possibility of overlapping symbol range that
442db995d72SSunho Kim         // could be introduced by disparity between inferred symbol size and
443db995d72SSunho Kim         // defined symbol size because symbol size information is currently only
444db995d72SSunho Kim         // used by jitlink-check where we have control to not make overlapping
445db995d72SSunho Kim         // ranges.
446db995d72SSunho Kim         continue;
447db995d72SSunho Kim       }
448db995d72SSunho Kim 
449db995d72SSunho Kim       LLVM_DEBUG({
450db995d72SSunho Kim         if (!CandSize)
451db995d72SSunho Kim           dbgs() << "  Empty implicit symbol size generated for the following "
452db995d72SSunho Kim                     "symbol:"
453db995d72SSunho Kim                  << "\n"
454db995d72SSunho Kim                  << "    " << *Symbol << "\n";
455db995d72SSunho Kim       });
456db995d72SSunho Kim 
457db995d72SSunho Kim       Symbol->setSize(CandSize);
458db995d72SSunho Kim     }
459db995d72SSunho Kim   }
460db995d72SSunho Kim   return Error::success();
461db995d72SSunho Kim }
462db995d72SSunho Kim 
463db995d72SSunho Kim Expected<Symbol *> COFFLinkGraphBuilder::createDefinedSymbol(
4642ccf7ed2SJared Wyles     COFFSymbolIndex SymIndex, orc::SymbolStringPtr SymbolName,
465db995d72SSunho Kim     object::COFFSymbolRef Symbol, const object::coff_section *Section) {
4662ccf7ed2SJared Wyles 
467db995d72SSunho Kim   if (Symbol.isCommon()) {
468db995d72SSunho Kim     // FIXME: correct alignment
469ffe2dda2SLang Hames     return &G->addDefinedSymbol(
470ffe2dda2SLang Hames         G->createZeroFillBlock(getCommonSection(), Symbol.getValue(),
471ffe2dda2SLang Hames                                orc::ExecutorAddr(), Symbol.getValue(), 0),
472e7698a13SLang Hames         0, SymbolName, Symbol.getValue(), Linkage::Weak, Scope::Default,
473ffe2dda2SLang Hames         false, false);
474db995d72SSunho Kim   }
4752ccf7ed2SJared Wyles 
476db995d72SSunho Kim   if (Symbol.isAbsolute())
477db995d72SSunho Kim     return &G->addAbsoluteSymbol(SymbolName,
478db995d72SSunho Kim                                  orc::ExecutorAddr(Symbol.getValue()), 0,
479db995d72SSunho Kim                                  Linkage::Strong, Scope::Local, false);
480db995d72SSunho Kim 
481db995d72SSunho Kim   if (llvm::COFF::isReservedSectionNumber(Symbol.getSectionNumber()))
482db995d72SSunho Kim     return make_error<JITLinkError>(
483db995d72SSunho Kim         "Reserved section number used in regular symbol " +
484db995d72SSunho Kim         formatv("{0:d}", SymIndex));
485db995d72SSunho Kim 
486db995d72SSunho Kim   Block *B = getGraphBlock(Symbol.getSectionNumber());
4870f00e588SSunho Kim   if (!B) {
4880f00e588SSunho Kim     LLVM_DEBUG({
4890f00e588SSunho Kim       dbgs() << "    " << SymIndex
4900f00e588SSunho Kim              << ": Skipping graph symbol since section was not created for "
4910f00e588SSunho Kim                 "COFF symbol \""
4920f00e588SSunho Kim              << SymbolName << "\" in section " << Symbol.getSectionNumber()
4930f00e588SSunho Kim              << "\n";
4940f00e588SSunho Kim     });
4950f00e588SSunho Kim     return nullptr;
4960f00e588SSunho Kim   }
4970f00e588SSunho Kim 
498db995d72SSunho Kim   if (Symbol.isExternal()) {
499db995d72SSunho Kim     // This is not a comdat sequence, export the symbol as it is
50007aa8fc8SSunho Kim     if (!isComdatSection(Section)) {
50188181375SSunho Kim       auto GSym = &G->addDefinedSymbol(
502db995d72SSunho Kim           *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Default,
503db995d72SSunho Kim           Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
50488181375SSunho Kim       DefinedSymbols[SymbolName] = GSym;
50588181375SSunho Kim       return GSym;
50607aa8fc8SSunho Kim     } else {
50707aa8fc8SSunho Kim       if (!PendingComdatExports[Symbol.getSectionNumber()])
508db995d72SSunho Kim         return make_error<JITLinkError>("No pending COMDAT export for symbol " +
509db995d72SSunho Kim                                         formatv("{0:d}", SymIndex));
51007aa8fc8SSunho Kim 
511db995d72SSunho Kim       return exportCOMDATSymbol(SymIndex, SymbolName, Symbol);
512db995d72SSunho Kim     }
513db995d72SSunho Kim   }
514db995d72SSunho Kim 
515aef75aecSSunho Kim   if (Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC ||
516aef75aecSSunho Kim       Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_LABEL) {
517db995d72SSunho Kim     const object::coff_aux_section_definition *Definition =
518db995d72SSunho Kim         Symbol.getSectionDefinition();
519db995d72SSunho Kim     if (!Definition || !isComdatSection(Section)) {
520db995d72SSunho Kim       // Handle typical static symbol
521db995d72SSunho Kim       return &G->addDefinedSymbol(
522db995d72SSunho Kim           *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local,
523db995d72SSunho Kim           Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
524db995d72SSunho Kim     }
525db995d72SSunho Kim     if (Definition->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
526b4878493SSunho Kim       auto Target = Definition->getNumber(Symbol.isBigObj());
527b4878493SSunho Kim       auto GSym = &G->addDefinedSymbol(
528db995d72SSunho Kim           *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local,
529db995d72SSunho Kim           Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
530b4878493SSunho Kim       getGraphBlock(Target)->addEdge(Edge::KeepAlive, 0, *GSym, 0);
531b4878493SSunho Kim       return GSym;
532db995d72SSunho Kim     }
53307aa8fc8SSunho Kim     if (PendingComdatExports[Symbol.getSectionNumber()])
534db995d72SSunho Kim       return make_error<JITLinkError>(
535db995d72SSunho Kim           "COMDAT export request already exists before symbol " +
536db995d72SSunho Kim           formatv("{0:d}", SymIndex));
537db995d72SSunho Kim     return createCOMDATExportRequest(SymIndex, Symbol, Definition);
538db995d72SSunho Kim   }
539db995d72SSunho Kim   return make_error<JITLinkError>("Unsupported storage class " +
540db995d72SSunho Kim                                   formatv("{0:d}", Symbol.getStorageClass()) +
541db995d72SSunho Kim                                   " in symbol " + formatv("{0:d}", SymIndex));
542db995d72SSunho Kim }
543db995d72SSunho Kim 
544db995d72SSunho Kim // COMDAT handling:
545db995d72SSunho Kim // When IMAGE_SCN_LNK_COMDAT flag is set in the flags of a section,
546db995d72SSunho Kim // the section is called a COMDAT section. It contains two symbols
547db995d72SSunho Kim // in a sequence that specifes the behavior. First symbol is the section
548db995d72SSunho Kim // symbol which contains the size and name of the section. It also contains
549db995d72SSunho Kim // selection type that specifies how duplicate of the symbol is handled.
550db995d72SSunho Kim // Second symbol is COMDAT symbol which usually defines the external name and
551db995d72SSunho Kim // data type.
552db995d72SSunho Kim //
553db995d72SSunho Kim // Since two symbols always come in a specific order, we initiate pending COMDAT
554db995d72SSunho Kim // export request when we encounter the first symbol and actually exports it
555db995d72SSunho Kim // when we process the second symbol.
556db995d72SSunho Kim //
557db995d72SSunho Kim // Process the first symbol of COMDAT sequence.
558db995d72SSunho Kim Expected<Symbol *> COFFLinkGraphBuilder::createCOMDATExportRequest(
559db995d72SSunho Kim     COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol,
560db995d72SSunho Kim     const object::coff_aux_section_definition *Definition) {
561db995d72SSunho Kim   Linkage L = Linkage::Strong;
562db995d72SSunho Kim   switch (Definition->Selection) {
563db995d72SSunho Kim   case COFF::IMAGE_COMDAT_SELECT_NODUPLICATES: {
564db995d72SSunho Kim     L = Linkage::Strong;
565db995d72SSunho Kim     break;
566db995d72SSunho Kim   }
567db995d72SSunho Kim   case COFF::IMAGE_COMDAT_SELECT_ANY: {
568db995d72SSunho Kim     L = Linkage::Weak;
569db995d72SSunho Kim     break;
570db995d72SSunho Kim   }
571db995d72SSunho Kim   case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH:
572db995d72SSunho Kim   case COFF::IMAGE_COMDAT_SELECT_SAME_SIZE: {
573db995d72SSunho Kim     // FIXME: Implement size/content validation when LinkGraph is able to
574db995d72SSunho Kim     // handle this.
575db995d72SSunho Kim     L = Linkage::Weak;
576db995d72SSunho Kim     break;
577db995d72SSunho Kim   }
578db995d72SSunho Kim   case COFF::IMAGE_COMDAT_SELECT_LARGEST: {
579df344e1fSSunho Kim     // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST properly when LinkGraph is
580df344e1fSSunho Kim     // able to handle this.
581df344e1fSSunho Kim     LLVM_DEBUG({
582df344e1fSSunho Kim       dbgs() << "    " << SymIndex
583df344e1fSSunho Kim              << ": Partially supported IMAGE_COMDAT_SELECT_LARGEST was used"
584df344e1fSSunho Kim                 " in section "
585b501770aSSunho Kim              << Symbol.getSectionNumber() << " (size: " << Definition->Length
586b501770aSSunho Kim              << ")\n";
587df344e1fSSunho Kim     });
588df344e1fSSunho Kim     L = Linkage::Weak;
589df344e1fSSunho Kim     break;
590db995d72SSunho Kim   }
591db995d72SSunho Kim   case COFF::IMAGE_COMDAT_SELECT_NEWEST: {
592db995d72SSunho Kim     // Even link.exe doesn't support this selection properly.
593db995d72SSunho Kim     return make_error<JITLinkError>(
594db995d72SSunho Kim         "IMAGE_COMDAT_SELECT_NEWEST is not supported.");
595db995d72SSunho Kim   }
596db995d72SSunho Kim   default: {
597db995d72SSunho Kim     return make_error<JITLinkError>("Invalid comdat selection type: " +
598db995d72SSunho Kim                                     formatv("{0:d}", Definition->Selection));
599db995d72SSunho Kim   }
600db995d72SSunho Kim   }
601b501770aSSunho Kim   PendingComdatExports[Symbol.getSectionNumber()] = {SymIndex, L,
602b501770aSSunho Kim                                                      Definition->Length};
603b501770aSSunho Kim   return nullptr;
604db995d72SSunho Kim }
605db995d72SSunho Kim 
606db995d72SSunho Kim // Process the second symbol of COMDAT sequence.
607db995d72SSunho Kim Expected<Symbol *>
608db995d72SSunho Kim COFFLinkGraphBuilder::exportCOMDATSymbol(COFFSymbolIndex SymIndex,
6092ccf7ed2SJared Wyles                                          orc::SymbolStringPtr SymbolName,
610db995d72SSunho Kim                                          object::COFFSymbolRef Symbol) {
611b501770aSSunho Kim   Block *B = getGraphBlock(Symbol.getSectionNumber());
61207aa8fc8SSunho Kim   auto &PendingComdatExport = PendingComdatExports[Symbol.getSectionNumber()];
61394239712SEymen Ünay   // NOTE: ComdatDef->Length is the size of "section" not size of symbol.
614b501770aSSunho Kim   // We use zero symbol size to not reach out of bound of block when symbol
615b501770aSSunho Kim   // offset is non-zero.
616b501770aSSunho Kim   auto GSym = &G->addDefinedSymbol(
617b501770aSSunho Kim       *B, Symbol.getValue(), SymbolName, 0, PendingComdatExport->Linkage,
618b501770aSSunho Kim       Scope::Default, Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION,
619b501770aSSunho Kim       false);
620db995d72SSunho Kim   LLVM_DEBUG({
621db995d72SSunho Kim     dbgs() << "    " << SymIndex
622db995d72SSunho Kim            << ": Exporting COMDAT graph symbol for COFF symbol \"" << SymbolName
623db995d72SSunho Kim            << "\" in section " << Symbol.getSectionNumber() << "\n";
624b501770aSSunho Kim     dbgs() << "      " << *GSym << "\n";
625db995d72SSunho Kim   });
626b501770aSSunho Kim   setGraphSymbol(Symbol.getSectionNumber(), PendingComdatExport->SymbolIndex,
627b501770aSSunho Kim                  *GSym);
628b501770aSSunho Kim   DefinedSymbols[SymbolName] = GSym;
629aadaafacSKazu Hirata   PendingComdatExport = std::nullopt;
630b501770aSSunho Kim   return GSym;
631db995d72SSunho Kim }
632db995d72SSunho Kim 
63398be16f2SLang Hames Symbol *GetImageBaseSymbol::operator()(LinkGraph &G) {
63498be16f2SLang Hames   if (ImageBase)
63598be16f2SLang Hames     return *ImageBase;
63698be16f2SLang Hames 
63798be16f2SLang Hames   auto IBN = G.intern(ImageBaseName);
638*9c5001e4SLang Hames   ImageBase = G.findExternalSymbolByName(IBN);
639*9c5001e4SLang Hames   if (*ImageBase)
640*9c5001e4SLang Hames     return *ImageBase;
641*9c5001e4SLang Hames   ImageBase = G.findAbsoluteSymbolByName(IBN);
642*9c5001e4SLang Hames   if (*ImageBase)
643*9c5001e4SLang Hames     return *ImageBase;
644*9c5001e4SLang Hames   ImageBase = G.findDefinedSymbolByName(IBN);
645*9c5001e4SLang Hames   if (*ImageBase)
646*9c5001e4SLang Hames     return *ImageBase;
64798be16f2SLang Hames 
64898be16f2SLang Hames   return nullptr;
64998be16f2SLang Hames }
65098be16f2SLang Hames 
651db995d72SSunho Kim } // namespace jitlink
652db995d72SSunho Kim } // namespace llvm
653