xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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 
21972a253aSDimitry Andric static Triple createTripleWithCOFFFormat(Triple T) {
22972a253aSDimitry Andric   T.setObjectFormat(Triple::COFF);
23972a253aSDimitry Andric   return T;
24972a253aSDimitry Andric }
25972a253aSDimitry Andric 
26753f127fSDimitry Andric COFFLinkGraphBuilder::COFFLinkGraphBuilder(
27*06c3fb27SDimitry Andric     const object::COFFObjectFile &Obj, Triple TT, SubtargetFeatures Features,
28753f127fSDimitry Andric     LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
29*06c3fb27SDimitry Andric     : Obj(Obj), G(std::make_unique<LinkGraph>(
30*06c3fb27SDimitry Andric                     Obj.getFileName().str(), createTripleWithCOFFFormat(TT),
31*06c3fb27SDimitry Andric                     std::move(Features), getPointerSize(Obj),
32*06c3fb27SDimitry Andric                     getEndianness(Obj), std::move(GetEdgeKindName))) {
33753f127fSDimitry Andric   LLVM_DEBUG({
34753f127fSDimitry Andric     dbgs() << "Created COFFLinkGraphBuilder for \"" << Obj.getFileName()
35753f127fSDimitry Andric            << "\"\n";
36753f127fSDimitry Andric   });
37753f127fSDimitry Andric }
38753f127fSDimitry Andric 
39753f127fSDimitry Andric COFFLinkGraphBuilder::~COFFLinkGraphBuilder() = default;
40753f127fSDimitry Andric 
41753f127fSDimitry Andric unsigned
42753f127fSDimitry Andric COFFLinkGraphBuilder::getPointerSize(const object::COFFObjectFile &Obj) {
43753f127fSDimitry Andric   return Obj.getBytesInAddress();
44753f127fSDimitry Andric }
45753f127fSDimitry Andric 
46753f127fSDimitry Andric support::endianness
47753f127fSDimitry Andric COFFLinkGraphBuilder::getEndianness(const object::COFFObjectFile &Obj) {
48753f127fSDimitry Andric   return Obj.isLittleEndian() ? support::little : support::big;
49753f127fSDimitry Andric }
50753f127fSDimitry Andric 
51753f127fSDimitry Andric uint64_t COFFLinkGraphBuilder::getSectionSize(const object::COFFObjectFile &Obj,
52753f127fSDimitry Andric                                               const object::coff_section *Sec) {
53753f127fSDimitry Andric   // Consider the difference between executable form and object form.
54753f127fSDimitry Andric   // More information is inside COFFObjectFile::getSectionSize
55753f127fSDimitry Andric   if (Obj.getDOSHeader())
56753f127fSDimitry Andric     return std::min(Sec->VirtualSize, Sec->SizeOfRawData);
57753f127fSDimitry Andric   return Sec->SizeOfRawData;
58753f127fSDimitry Andric }
59753f127fSDimitry Andric 
60753f127fSDimitry Andric uint64_t
61753f127fSDimitry Andric COFFLinkGraphBuilder::getSectionAddress(const object::COFFObjectFile &Obj,
62753f127fSDimitry Andric                                         const object::coff_section *Section) {
63753f127fSDimitry Andric   return Section->VirtualAddress + Obj.getImageBase();
64753f127fSDimitry Andric }
65753f127fSDimitry Andric 
66753f127fSDimitry Andric bool COFFLinkGraphBuilder::isComdatSection(
67753f127fSDimitry Andric     const object::coff_section *Section) {
68753f127fSDimitry Andric   return Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT;
69753f127fSDimitry Andric }
70753f127fSDimitry Andric 
71753f127fSDimitry Andric Section &COFFLinkGraphBuilder::getCommonSection() {
72753f127fSDimitry Andric   if (!CommonSection)
73bdd1243dSDimitry Andric     CommonSection = &G->createSection(CommonSectionName,
74bdd1243dSDimitry Andric                                       orc::MemProt::Read | orc::MemProt::Write);
75753f127fSDimitry Andric   return *CommonSection;
76753f127fSDimitry Andric }
77753f127fSDimitry Andric 
78753f127fSDimitry Andric Expected<std::unique_ptr<LinkGraph>> COFFLinkGraphBuilder::buildGraph() {
79753f127fSDimitry Andric   if (!Obj.isRelocatableObject())
80753f127fSDimitry Andric     return make_error<JITLinkError>("Object is not a relocatable COFF file");
81753f127fSDimitry Andric 
82753f127fSDimitry Andric   if (auto Err = graphifySections())
83753f127fSDimitry Andric     return std::move(Err);
84753f127fSDimitry Andric 
85753f127fSDimitry Andric   if (auto Err = graphifySymbols())
86753f127fSDimitry Andric     return std::move(Err);
87753f127fSDimitry Andric 
88753f127fSDimitry Andric   if (auto Err = addRelocations())
89753f127fSDimitry Andric     return std::move(Err);
90753f127fSDimitry Andric 
91753f127fSDimitry Andric   return std::move(G);
92753f127fSDimitry Andric }
93753f127fSDimitry Andric 
94753f127fSDimitry Andric StringRef
95753f127fSDimitry Andric COFFLinkGraphBuilder::getCOFFSectionName(COFFSectionIndex SectionIndex,
96753f127fSDimitry Andric                                          const object::coff_section *Sec,
97753f127fSDimitry Andric                                          object::COFFSymbolRef Sym) {
98753f127fSDimitry Andric   switch (SectionIndex) {
99753f127fSDimitry Andric   case COFF::IMAGE_SYM_UNDEFINED: {
100753f127fSDimitry Andric     if (Sym.getValue())
101753f127fSDimitry Andric       return "(common)";
102753f127fSDimitry Andric     else
103753f127fSDimitry Andric       return "(external)";
104753f127fSDimitry Andric   }
105753f127fSDimitry Andric   case COFF::IMAGE_SYM_ABSOLUTE:
106753f127fSDimitry Andric     return "(absolute)";
107753f127fSDimitry Andric   case COFF::IMAGE_SYM_DEBUG: {
108753f127fSDimitry Andric     // Used with .file symbol
109753f127fSDimitry Andric     return "(debug)";
110753f127fSDimitry Andric   }
111753f127fSDimitry Andric   default: {
112753f127fSDimitry Andric     // Non reserved regular section numbers
113753f127fSDimitry Andric     if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(Sec))
114753f127fSDimitry Andric       return *SecNameOrErr;
115753f127fSDimitry Andric   }
116753f127fSDimitry Andric   }
117753f127fSDimitry Andric   return "";
118753f127fSDimitry Andric }
119753f127fSDimitry Andric 
120753f127fSDimitry Andric Error COFFLinkGraphBuilder::graphifySections() {
121753f127fSDimitry Andric   LLVM_DEBUG(dbgs() << "  Creating graph sections...\n");
122753f127fSDimitry Andric 
123753f127fSDimitry Andric   GraphBlocks.resize(Obj.getNumberOfSections() + 1);
124753f127fSDimitry Andric   // For each section...
125753f127fSDimitry Andric   for (COFFSectionIndex SecIndex = 1;
126753f127fSDimitry Andric        SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections());
127753f127fSDimitry Andric        SecIndex++) {
128753f127fSDimitry Andric     Expected<const object::coff_section *> Sec = Obj.getSection(SecIndex);
129753f127fSDimitry Andric     if (!Sec)
130753f127fSDimitry Andric       return Sec.takeError();
131753f127fSDimitry Andric 
132753f127fSDimitry Andric     StringRef SectionName;
133753f127fSDimitry Andric     if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(*Sec))
134753f127fSDimitry Andric       SectionName = *SecNameOrErr;
135753f127fSDimitry Andric 
136753f127fSDimitry Andric     // FIXME: Skip debug info sections
137*06c3fb27SDimitry Andric     if (SectionName == ".voltbl") {
138*06c3fb27SDimitry Andric       LLVM_DEBUG({
139*06c3fb27SDimitry Andric         dbgs() << "    "
140*06c3fb27SDimitry Andric                << "Skipping section \"" << SectionName << "\"\n";
141*06c3fb27SDimitry Andric       });
142*06c3fb27SDimitry Andric       continue;
143*06c3fb27SDimitry Andric     }
144753f127fSDimitry Andric 
145753f127fSDimitry Andric     LLVM_DEBUG({
146753f127fSDimitry Andric       dbgs() << "    "
147753f127fSDimitry Andric              << "Creating section for \"" << SectionName << "\"\n";
148753f127fSDimitry Andric     });
149753f127fSDimitry Andric 
150753f127fSDimitry Andric     // Get the section's memory protection flags.
151bdd1243dSDimitry Andric     orc::MemProt Prot = orc::MemProt::Read;
152753f127fSDimitry Andric     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE)
153bdd1243dSDimitry Andric       Prot |= orc::MemProt::Exec;
154753f127fSDimitry Andric     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_READ)
155bdd1243dSDimitry Andric       Prot |= orc::MemProt::Read;
156753f127fSDimitry Andric     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_WRITE)
157bdd1243dSDimitry Andric       Prot |= orc::MemProt::Write;
158753f127fSDimitry Andric 
159753f127fSDimitry Andric     // Look for existing sections first.
160753f127fSDimitry Andric     auto *GraphSec = G->findSectionByName(SectionName);
161*06c3fb27SDimitry Andric     if (!GraphSec) {
162753f127fSDimitry Andric       GraphSec = &G->createSection(SectionName, Prot);
163*06c3fb27SDimitry Andric       if ((*Sec)->Characteristics & COFF::IMAGE_SCN_LNK_REMOVE)
164*06c3fb27SDimitry Andric         GraphSec->setMemLifetimePolicy(orc::MemLifetimePolicy::NoAlloc);
165*06c3fb27SDimitry Andric     }
166753f127fSDimitry Andric     if (GraphSec->getMemProt() != Prot)
167753f127fSDimitry Andric       return make_error<JITLinkError>("MemProt should match");
168753f127fSDimitry Andric 
169753f127fSDimitry Andric     Block *B = nullptr;
170753f127fSDimitry Andric     if ((*Sec)->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
171753f127fSDimitry Andric       B = &G->createZeroFillBlock(
172753f127fSDimitry Andric           *GraphSec, getSectionSize(Obj, *Sec),
173753f127fSDimitry Andric           orc::ExecutorAddr(getSectionAddress(Obj, *Sec)),
174753f127fSDimitry Andric           (*Sec)->getAlignment(), 0);
175753f127fSDimitry Andric     else {
176753f127fSDimitry Andric       ArrayRef<uint8_t> Data;
177753f127fSDimitry Andric       if (auto Err = Obj.getSectionContents(*Sec, Data))
178753f127fSDimitry Andric         return Err;
179753f127fSDimitry Andric 
180bdd1243dSDimitry Andric       auto CharData = ArrayRef<char>(
181bdd1243dSDimitry Andric           reinterpret_cast<const char *>(Data.data()), Data.size());
182bdd1243dSDimitry Andric 
183bdd1243dSDimitry Andric       if (SectionName == getDirectiveSectionName())
184bdd1243dSDimitry Andric         if (auto Err = handleDirectiveSection(
185bdd1243dSDimitry Andric                 StringRef(CharData.data(), CharData.size())))
186bdd1243dSDimitry Andric           return Err;
187bdd1243dSDimitry Andric 
188753f127fSDimitry Andric       B = &G->createContentBlock(
189bdd1243dSDimitry Andric           *GraphSec, CharData, orc::ExecutorAddr(getSectionAddress(Obj, *Sec)),
190753f127fSDimitry Andric           (*Sec)->getAlignment(), 0);
191753f127fSDimitry Andric     }
192753f127fSDimitry Andric 
193753f127fSDimitry Andric     setGraphBlock(SecIndex, B);
194753f127fSDimitry Andric   }
195753f127fSDimitry Andric 
196753f127fSDimitry Andric   return Error::success();
197753f127fSDimitry Andric }
198753f127fSDimitry Andric 
199753f127fSDimitry Andric Error COFFLinkGraphBuilder::graphifySymbols() {
200753f127fSDimitry Andric   LLVM_DEBUG(dbgs() << "  Creating graph symbols...\n");
201753f127fSDimitry Andric 
202753f127fSDimitry Andric   SymbolSets.resize(Obj.getNumberOfSections() + 1);
203972a253aSDimitry Andric   PendingComdatExports.resize(Obj.getNumberOfSections() + 1);
204753f127fSDimitry Andric   GraphSymbols.resize(Obj.getNumberOfSymbols());
205753f127fSDimitry Andric 
206753f127fSDimitry Andric   for (COFFSymbolIndex SymIndex = 0;
207753f127fSDimitry Andric        SymIndex < static_cast<COFFSymbolIndex>(Obj.getNumberOfSymbols());
208753f127fSDimitry Andric        SymIndex++) {
209753f127fSDimitry Andric     Expected<object::COFFSymbolRef> Sym = Obj.getSymbol(SymIndex);
210753f127fSDimitry Andric     if (!Sym)
211753f127fSDimitry Andric       return Sym.takeError();
212753f127fSDimitry Andric 
213753f127fSDimitry Andric     StringRef SymbolName;
214753f127fSDimitry Andric     if (Expected<StringRef> SymNameOrErr = Obj.getSymbolName(*Sym))
215753f127fSDimitry Andric       SymbolName = *SymNameOrErr;
216753f127fSDimitry Andric 
217753f127fSDimitry Andric     COFFSectionIndex SectionIndex = Sym->getSectionNumber();
218753f127fSDimitry Andric     const object::coff_section *Sec = nullptr;
219753f127fSDimitry Andric 
220753f127fSDimitry Andric     if (!COFF::isReservedSectionNumber(SectionIndex)) {
221753f127fSDimitry Andric       auto SecOrErr = Obj.getSection(SectionIndex);
222753f127fSDimitry Andric       if (!SecOrErr)
223753f127fSDimitry Andric         return make_error<JITLinkError>(
224753f127fSDimitry Andric             "Invalid COFF section number:" + formatv("{0:d}: ", SectionIndex) +
225753f127fSDimitry Andric             " (" + toString(SecOrErr.takeError()) + ")");
226753f127fSDimitry Andric       Sec = *SecOrErr;
227753f127fSDimitry Andric     }
228753f127fSDimitry Andric 
229753f127fSDimitry Andric     // Create jitlink symbol
230753f127fSDimitry Andric     jitlink::Symbol *GSym = nullptr;
231753f127fSDimitry Andric     if (Sym->isFileRecord())
232753f127fSDimitry Andric       LLVM_DEBUG({
233753f127fSDimitry Andric         dbgs() << "    " << SymIndex << ": Skipping FileRecord symbol \""
234753f127fSDimitry Andric                << SymbolName << "\" in "
235753f127fSDimitry Andric                << getCOFFSectionName(SectionIndex, Sec, *Sym)
236753f127fSDimitry Andric                << " (index: " << SectionIndex << ") \n";
237753f127fSDimitry Andric       });
238753f127fSDimitry Andric     else if (Sym->isUndefined()) {
239bdd1243dSDimitry Andric       GSym = createExternalSymbol(SymIndex, SymbolName, *Sym, Sec);
240753f127fSDimitry Andric     } else if (Sym->isWeakExternal()) {
241972a253aSDimitry Andric       auto *WeakExternal = Sym->getAux<object::coff_aux_weak_external>();
242972a253aSDimitry Andric       COFFSymbolIndex TagIndex = WeakExternal->TagIndex;
243972a253aSDimitry Andric       uint32_t Characteristics = WeakExternal->Characteristics;
244972a253aSDimitry Andric       WeakExternalRequests.push_back(
245972a253aSDimitry Andric           {SymIndex, TagIndex, Characteristics, SymbolName});
246753f127fSDimitry Andric     } else {
247753f127fSDimitry Andric       Expected<jitlink::Symbol *> NewGSym =
248753f127fSDimitry Andric           createDefinedSymbol(SymIndex, SymbolName, *Sym, Sec);
249753f127fSDimitry Andric       if (!NewGSym)
250753f127fSDimitry Andric         return NewGSym.takeError();
251753f127fSDimitry Andric       GSym = *NewGSym;
252753f127fSDimitry Andric       if (GSym) {
253753f127fSDimitry Andric         LLVM_DEBUG({
254753f127fSDimitry Andric           dbgs() << "    " << SymIndex
255753f127fSDimitry Andric                  << ": Creating defined graph symbol for COFF symbol \""
256753f127fSDimitry Andric                  << SymbolName << "\" in "
257753f127fSDimitry Andric                  << getCOFFSectionName(SectionIndex, Sec, *Sym)
258753f127fSDimitry Andric                  << " (index: " << SectionIndex << ") \n";
259753f127fSDimitry Andric           dbgs() << "      " << *GSym << "\n";
260753f127fSDimitry Andric         });
261753f127fSDimitry Andric       }
262753f127fSDimitry Andric     }
263753f127fSDimitry Andric 
264753f127fSDimitry Andric     // Register the symbol
265753f127fSDimitry Andric     if (GSym)
266753f127fSDimitry Andric       setGraphSymbol(SectionIndex, SymIndex, *GSym);
267753f127fSDimitry Andric     SymIndex += Sym->getNumberOfAuxSymbols();
268753f127fSDimitry Andric   }
269753f127fSDimitry Andric 
270753f127fSDimitry Andric   if (auto Err = flushWeakAliasRequests())
271753f127fSDimitry Andric     return Err;
272753f127fSDimitry Andric 
273bdd1243dSDimitry Andric   if (auto Err = handleAlternateNames())
274bdd1243dSDimitry Andric     return Err;
275bdd1243dSDimitry Andric 
276753f127fSDimitry Andric   if (auto Err = calculateImplicitSizeOfSymbols())
277753f127fSDimitry Andric     return Err;
278753f127fSDimitry Andric 
279753f127fSDimitry Andric   return Error::success();
280753f127fSDimitry Andric }
281753f127fSDimitry Andric 
282bdd1243dSDimitry Andric Error COFFLinkGraphBuilder::handleDirectiveSection(StringRef Str) {
283bdd1243dSDimitry Andric   auto Parsed = DirectiveParser.parse(Str);
284bdd1243dSDimitry Andric   if (!Parsed)
285bdd1243dSDimitry Andric     return Parsed.takeError();
286bdd1243dSDimitry Andric   for (auto *Arg : *Parsed) {
287bdd1243dSDimitry Andric     StringRef S = Arg->getValue();
288bdd1243dSDimitry Andric     switch (Arg->getOption().getID()) {
289bdd1243dSDimitry Andric     case COFF_OPT_alternatename: {
290bdd1243dSDimitry Andric       StringRef From, To;
291bdd1243dSDimitry Andric       std::tie(From, To) = S.split('=');
292bdd1243dSDimitry Andric       if (From.empty() || To.empty())
293bdd1243dSDimitry Andric         return make_error<JITLinkError>(
294bdd1243dSDimitry Andric             "Invalid COFF /alternatename directive");
295bdd1243dSDimitry Andric       AlternateNames[From] = To;
296bdd1243dSDimitry Andric       break;
297bdd1243dSDimitry Andric     }
298bdd1243dSDimitry Andric     case COFF_OPT_incl: {
299*06c3fb27SDimitry Andric       auto DataCopy = G->allocateContent(S);
300bdd1243dSDimitry Andric       StringRef StrCopy(DataCopy.data(), DataCopy.size());
301bdd1243dSDimitry Andric       ExternalSymbols[StrCopy] = &G->addExternalSymbol(StrCopy, 0, false);
302bdd1243dSDimitry Andric       ExternalSymbols[StrCopy]->setLive(true);
303bdd1243dSDimitry Andric       break;
304bdd1243dSDimitry Andric     }
305bdd1243dSDimitry Andric     case COFF_OPT_export:
306bdd1243dSDimitry Andric       break;
307bdd1243dSDimitry Andric     default: {
308bdd1243dSDimitry Andric       LLVM_DEBUG({
309bdd1243dSDimitry Andric         dbgs() << "Unknown coff directive: " << Arg->getSpelling() << "\n";
310bdd1243dSDimitry Andric       });
311bdd1243dSDimitry Andric       break;
312bdd1243dSDimitry Andric     }
313bdd1243dSDimitry Andric     }
314bdd1243dSDimitry Andric   }
315bdd1243dSDimitry Andric   return Error::success();
316bdd1243dSDimitry Andric }
317bdd1243dSDimitry Andric 
318753f127fSDimitry Andric Error COFFLinkGraphBuilder::flushWeakAliasRequests() {
319753f127fSDimitry Andric   // Export the weak external symbols and alias it
320972a253aSDimitry Andric   for (auto &WeakExternal : WeakExternalRequests) {
321972a253aSDimitry Andric     if (auto *Target = getGraphSymbol(WeakExternal.Target)) {
322753f127fSDimitry Andric       Expected<object::COFFSymbolRef> AliasSymbol =
323972a253aSDimitry Andric           Obj.getSymbol(WeakExternal.Alias);
324753f127fSDimitry Andric       if (!AliasSymbol)
325753f127fSDimitry Andric         return AliasSymbol.takeError();
326753f127fSDimitry Andric 
327972a253aSDimitry Andric       // FIXME: IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY and
328972a253aSDimitry Andric       // IMAGE_WEAK_EXTERN_SEARCH_LIBRARY are handled in the same way.
329972a253aSDimitry Andric       Scope S =
330972a253aSDimitry Andric           WeakExternal.Characteristics == COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS
331972a253aSDimitry Andric               ? Scope::Default
332972a253aSDimitry Andric               : Scope::Local;
333972a253aSDimitry Andric 
334bdd1243dSDimitry Andric       auto NewSymbol =
335bdd1243dSDimitry Andric           createAliasSymbol(WeakExternal.SymbolName, Linkage::Weak, S, *Target);
336bdd1243dSDimitry Andric       if (!NewSymbol)
337bdd1243dSDimitry Andric         return NewSymbol.takeError();
338972a253aSDimitry Andric       setGraphSymbol(AliasSymbol->getSectionNumber(), WeakExternal.Alias,
339bdd1243dSDimitry Andric                      **NewSymbol);
340753f127fSDimitry Andric       LLVM_DEBUG({
341972a253aSDimitry Andric         dbgs() << "    " << WeakExternal.Alias
342753f127fSDimitry Andric                << ": Creating weak external symbol for COFF symbol \""
343972a253aSDimitry Andric                << WeakExternal.SymbolName << "\" in section "
344753f127fSDimitry Andric                << AliasSymbol->getSectionNumber() << "\n";
345bdd1243dSDimitry Andric         dbgs() << "      " << **NewSymbol << "\n";
346753f127fSDimitry Andric       });
347753f127fSDimitry Andric     } else
348753f127fSDimitry Andric       return make_error<JITLinkError>("Weak symbol alias requested but actual "
349753f127fSDimitry Andric                                       "symbol not found for symbol " +
350972a253aSDimitry Andric                                       formatv("{0:d}", WeakExternal.Alias));
351753f127fSDimitry Andric   }
352753f127fSDimitry Andric   return Error::success();
353753f127fSDimitry Andric }
354753f127fSDimitry Andric 
355bdd1243dSDimitry Andric Error COFFLinkGraphBuilder::handleAlternateNames() {
356bdd1243dSDimitry Andric   for (auto &KeyValue : AlternateNames)
357bdd1243dSDimitry Andric     if (DefinedSymbols.count(KeyValue.second) &&
358bdd1243dSDimitry Andric         ExternalSymbols.count(KeyValue.first)) {
359bdd1243dSDimitry Andric       auto *Target = DefinedSymbols[KeyValue.second];
360bdd1243dSDimitry Andric       auto *Alias = ExternalSymbols[KeyValue.first];
361bdd1243dSDimitry Andric       G->makeDefined(*Alias, Target->getBlock(), Target->getOffset(),
362bdd1243dSDimitry Andric                      Target->getSize(), Linkage::Weak, Scope::Local, false);
363bdd1243dSDimitry Andric     }
364bdd1243dSDimitry Andric   return Error::success();
365bdd1243dSDimitry Andric }
366bdd1243dSDimitry Andric 
367bdd1243dSDimitry Andric Symbol *COFFLinkGraphBuilder::createExternalSymbol(
368bdd1243dSDimitry Andric     COFFSymbolIndex SymIndex, StringRef SymbolName,
369bdd1243dSDimitry Andric     object::COFFSymbolRef Symbol, const object::coff_section *Section) {
370bdd1243dSDimitry Andric   if (!ExternalSymbols.count(SymbolName))
371bdd1243dSDimitry Andric     ExternalSymbols[SymbolName] =
372bdd1243dSDimitry Andric         &G->addExternalSymbol(SymbolName, Symbol.getValue(), false);
373bdd1243dSDimitry Andric 
374bdd1243dSDimitry Andric   LLVM_DEBUG({
375bdd1243dSDimitry Andric     dbgs() << "    " << SymIndex
376bdd1243dSDimitry Andric            << ": Creating external graph symbol for COFF symbol \""
377bdd1243dSDimitry Andric            << SymbolName << "\" in "
378bdd1243dSDimitry Andric            << getCOFFSectionName(Symbol.getSectionNumber(), Section, Symbol)
379bdd1243dSDimitry Andric            << " (index: " << Symbol.getSectionNumber() << ") \n";
380bdd1243dSDimitry Andric   });
381bdd1243dSDimitry Andric   return ExternalSymbols[SymbolName];
382bdd1243dSDimitry Andric }
383bdd1243dSDimitry Andric 
384bdd1243dSDimitry Andric Expected<Symbol *> COFFLinkGraphBuilder::createAliasSymbol(StringRef SymbolName,
385bdd1243dSDimitry Andric                                                            Linkage L, Scope S,
386bdd1243dSDimitry Andric                                                            Symbol &Target) {
387bdd1243dSDimitry Andric   if (!Target.isDefined()) {
388bdd1243dSDimitry Andric     // FIXME: Support this when there's a way to handle this.
389bdd1243dSDimitry Andric     return make_error<JITLinkError>("Weak external symbol with external "
390bdd1243dSDimitry Andric                                     "symbol as alternative not supported.");
391bdd1243dSDimitry Andric   }
392bdd1243dSDimitry Andric   return &G->addDefinedSymbol(Target.getBlock(), Target.getOffset(), SymbolName,
393bdd1243dSDimitry Andric                               Target.getSize(), L, S, Target.isCallable(),
394bdd1243dSDimitry Andric                               false);
395bdd1243dSDimitry Andric }
396bdd1243dSDimitry Andric 
397753f127fSDimitry Andric // In COFF, most of the defined symbols don't contain the size information.
398753f127fSDimitry Andric // Hence, we calculate the "implicit" size of symbol by taking the delta of
399753f127fSDimitry Andric // offsets of consecutive symbols within a block. We maintain a balanced tree
400753f127fSDimitry Andric // set of symbols sorted by offset per each block in order to achieve
401753f127fSDimitry Andric // logarithmic time complexity of sorted symbol insertion. Symbol is inserted to
402753f127fSDimitry Andric // the set once it's processed in graphifySymbols. In this function, we iterate
403753f127fSDimitry Andric // each collected symbol in sorted order and calculate the implicit size.
404753f127fSDimitry Andric Error COFFLinkGraphBuilder::calculateImplicitSizeOfSymbols() {
405753f127fSDimitry Andric   for (COFFSectionIndex SecIndex = 1;
406753f127fSDimitry Andric        SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections());
407753f127fSDimitry Andric        SecIndex++) {
408753f127fSDimitry Andric     auto &SymbolSet = SymbolSets[SecIndex];
409972a253aSDimitry Andric     if (SymbolSet.empty())
410972a253aSDimitry Andric       continue;
411753f127fSDimitry Andric     jitlink::Block *B = getGraphBlock(SecIndex);
412753f127fSDimitry Andric     orc::ExecutorAddrDiff LastOffset = B->getSize();
413753f127fSDimitry Andric     orc::ExecutorAddrDiff LastDifferentOffset = B->getSize();
414753f127fSDimitry Andric     orc::ExecutorAddrDiff LastSize = 0;
415753f127fSDimitry Andric     for (auto It = SymbolSet.rbegin(); It != SymbolSet.rend(); It++) {
416753f127fSDimitry Andric       orc::ExecutorAddrDiff Offset = It->first;
417753f127fSDimitry Andric       jitlink::Symbol *Symbol = It->second;
418753f127fSDimitry Andric       orc::ExecutorAddrDiff CandSize;
419753f127fSDimitry Andric       // Last offset can be same when aliasing happened
420753f127fSDimitry Andric       if (Symbol->getOffset() == LastOffset)
421753f127fSDimitry Andric         CandSize = LastSize;
422753f127fSDimitry Andric       else
423753f127fSDimitry Andric         CandSize = LastOffset - Offset;
424753f127fSDimitry Andric 
425753f127fSDimitry Andric       LLVM_DEBUG({
426753f127fSDimitry Andric         if (Offset + Symbol->getSize() > LastDifferentOffset)
427753f127fSDimitry Andric           dbgs() << "  Overlapping symbol range generated for the following "
428753f127fSDimitry Andric                     "symbol:"
429753f127fSDimitry Andric                  << "\n"
430753f127fSDimitry Andric                  << "    " << *Symbol << "\n";
431753f127fSDimitry Andric       });
432753f127fSDimitry Andric       (void)LastDifferentOffset;
433753f127fSDimitry Andric       if (LastOffset != Offset)
434753f127fSDimitry Andric         LastDifferentOffset = Offset;
435753f127fSDimitry Andric       LastSize = CandSize;
436753f127fSDimitry Andric       LastOffset = Offset;
437753f127fSDimitry Andric       if (Symbol->getSize()) {
438753f127fSDimitry Andric         // Non empty symbol can happen in COMDAT symbol.
439753f127fSDimitry Andric         // We don't consider the possibility of overlapping symbol range that
440753f127fSDimitry Andric         // could be introduced by disparity between inferred symbol size and
441753f127fSDimitry Andric         // defined symbol size because symbol size information is currently only
442753f127fSDimitry Andric         // used by jitlink-check where we have control to not make overlapping
443753f127fSDimitry Andric         // ranges.
444753f127fSDimitry Andric         continue;
445753f127fSDimitry Andric       }
446753f127fSDimitry Andric 
447753f127fSDimitry Andric       LLVM_DEBUG({
448753f127fSDimitry Andric         if (!CandSize)
449753f127fSDimitry Andric           dbgs() << "  Empty implicit symbol size generated for the following "
450753f127fSDimitry Andric                     "symbol:"
451753f127fSDimitry Andric                  << "\n"
452753f127fSDimitry Andric                  << "    " << *Symbol << "\n";
453753f127fSDimitry Andric       });
454753f127fSDimitry Andric 
455753f127fSDimitry Andric       Symbol->setSize(CandSize);
456753f127fSDimitry Andric     }
457753f127fSDimitry Andric   }
458753f127fSDimitry Andric   return Error::success();
459753f127fSDimitry Andric }
460753f127fSDimitry Andric 
461753f127fSDimitry Andric Expected<Symbol *> COFFLinkGraphBuilder::createDefinedSymbol(
462753f127fSDimitry Andric     COFFSymbolIndex SymIndex, StringRef SymbolName,
463753f127fSDimitry Andric     object::COFFSymbolRef Symbol, const object::coff_section *Section) {
464753f127fSDimitry Andric   if (Symbol.isCommon()) {
465753f127fSDimitry Andric     // FIXME: correct alignment
466bdd1243dSDimitry Andric     return &G->addDefinedSymbol(
467bdd1243dSDimitry Andric         G->createZeroFillBlock(getCommonSection(), Symbol.getValue(),
468bdd1243dSDimitry Andric                                orc::ExecutorAddr(), Symbol.getValue(), 0),
469bdd1243dSDimitry Andric         0, SymbolName, Symbol.getValue(), Linkage::Strong, Scope::Default,
470bdd1243dSDimitry Andric         false, false);
471753f127fSDimitry Andric   }
472753f127fSDimitry Andric   if (Symbol.isAbsolute())
473753f127fSDimitry Andric     return &G->addAbsoluteSymbol(SymbolName,
474753f127fSDimitry Andric                                  orc::ExecutorAddr(Symbol.getValue()), 0,
475753f127fSDimitry Andric                                  Linkage::Strong, Scope::Local, false);
476753f127fSDimitry Andric 
477753f127fSDimitry Andric   if (llvm::COFF::isReservedSectionNumber(Symbol.getSectionNumber()))
478753f127fSDimitry Andric     return make_error<JITLinkError>(
479753f127fSDimitry Andric         "Reserved section number used in regular symbol " +
480753f127fSDimitry Andric         formatv("{0:d}", SymIndex));
481753f127fSDimitry Andric 
482753f127fSDimitry Andric   Block *B = getGraphBlock(Symbol.getSectionNumber());
483972a253aSDimitry Andric   if (!B) {
484972a253aSDimitry Andric     LLVM_DEBUG({
485972a253aSDimitry Andric       dbgs() << "    " << SymIndex
486972a253aSDimitry Andric              << ": Skipping graph symbol since section was not created for "
487972a253aSDimitry Andric                 "COFF symbol \""
488972a253aSDimitry Andric              << SymbolName << "\" in section " << Symbol.getSectionNumber()
489972a253aSDimitry Andric              << "\n";
490972a253aSDimitry Andric     });
491972a253aSDimitry Andric     return nullptr;
492972a253aSDimitry Andric   }
493972a253aSDimitry Andric 
494753f127fSDimitry Andric   if (Symbol.isExternal()) {
495753f127fSDimitry Andric     // This is not a comdat sequence, export the symbol as it is
496972a253aSDimitry Andric     if (!isComdatSection(Section)) {
497bdd1243dSDimitry Andric       auto GSym = &G->addDefinedSymbol(
498753f127fSDimitry Andric           *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Default,
499753f127fSDimitry Andric           Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
500bdd1243dSDimitry Andric       DefinedSymbols[SymbolName] = GSym;
501bdd1243dSDimitry Andric       return GSym;
502972a253aSDimitry Andric     } else {
503972a253aSDimitry Andric       if (!PendingComdatExports[Symbol.getSectionNumber()])
504753f127fSDimitry Andric         return make_error<JITLinkError>("No pending COMDAT export for symbol " +
505753f127fSDimitry Andric                                         formatv("{0:d}", SymIndex));
506972a253aSDimitry Andric 
507753f127fSDimitry Andric       return exportCOMDATSymbol(SymIndex, SymbolName, Symbol);
508753f127fSDimitry Andric     }
509753f127fSDimitry Andric   }
510753f127fSDimitry Andric 
511972a253aSDimitry Andric   if (Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC ||
512972a253aSDimitry Andric       Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_LABEL) {
513753f127fSDimitry Andric     const object::coff_aux_section_definition *Definition =
514753f127fSDimitry Andric         Symbol.getSectionDefinition();
515753f127fSDimitry Andric     if (!Definition || !isComdatSection(Section)) {
516753f127fSDimitry Andric       // Handle typical static symbol
517753f127fSDimitry Andric       return &G->addDefinedSymbol(
518753f127fSDimitry Andric           *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local,
519753f127fSDimitry Andric           Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
520753f127fSDimitry Andric     }
521753f127fSDimitry Andric     if (Definition->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
522972a253aSDimitry Andric       auto Target = Definition->getNumber(Symbol.isBigObj());
523972a253aSDimitry Andric       auto GSym = &G->addDefinedSymbol(
524753f127fSDimitry Andric           *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local,
525753f127fSDimitry Andric           Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
526972a253aSDimitry Andric       getGraphBlock(Target)->addEdge(Edge::KeepAlive, 0, *GSym, 0);
527972a253aSDimitry Andric       return GSym;
528753f127fSDimitry Andric     }
529972a253aSDimitry Andric     if (PendingComdatExports[Symbol.getSectionNumber()])
530753f127fSDimitry Andric       return make_error<JITLinkError>(
531753f127fSDimitry Andric           "COMDAT export request already exists before symbol " +
532753f127fSDimitry Andric           formatv("{0:d}", SymIndex));
533753f127fSDimitry Andric     return createCOMDATExportRequest(SymIndex, Symbol, Definition);
534753f127fSDimitry Andric   }
535753f127fSDimitry Andric   return make_error<JITLinkError>("Unsupported storage class " +
536753f127fSDimitry Andric                                   formatv("{0:d}", Symbol.getStorageClass()) +
537753f127fSDimitry Andric                                   " in symbol " + formatv("{0:d}", SymIndex));
538753f127fSDimitry Andric }
539753f127fSDimitry Andric 
540753f127fSDimitry Andric // COMDAT handling:
541753f127fSDimitry Andric // When IMAGE_SCN_LNK_COMDAT flag is set in the flags of a section,
542753f127fSDimitry Andric // the section is called a COMDAT section. It contains two symbols
543753f127fSDimitry Andric // in a sequence that specifes the behavior. First symbol is the section
544753f127fSDimitry Andric // symbol which contains the size and name of the section. It also contains
545753f127fSDimitry Andric // selection type that specifies how duplicate of the symbol is handled.
546753f127fSDimitry Andric // Second symbol is COMDAT symbol which usually defines the external name and
547753f127fSDimitry Andric // data type.
548753f127fSDimitry Andric //
549753f127fSDimitry Andric // Since two symbols always come in a specific order, we initiate pending COMDAT
550753f127fSDimitry Andric // export request when we encounter the first symbol and actually exports it
551753f127fSDimitry Andric // when we process the second symbol.
552753f127fSDimitry Andric //
553753f127fSDimitry Andric // Process the first symbol of COMDAT sequence.
554753f127fSDimitry Andric Expected<Symbol *> COFFLinkGraphBuilder::createCOMDATExportRequest(
555753f127fSDimitry Andric     COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol,
556753f127fSDimitry Andric     const object::coff_aux_section_definition *Definition) {
557753f127fSDimitry Andric   Linkage L = Linkage::Strong;
558753f127fSDimitry Andric   switch (Definition->Selection) {
559753f127fSDimitry Andric   case COFF::IMAGE_COMDAT_SELECT_NODUPLICATES: {
560753f127fSDimitry Andric     L = Linkage::Strong;
561753f127fSDimitry Andric     break;
562753f127fSDimitry Andric   }
563753f127fSDimitry Andric   case COFF::IMAGE_COMDAT_SELECT_ANY: {
564753f127fSDimitry Andric     L = Linkage::Weak;
565753f127fSDimitry Andric     break;
566753f127fSDimitry Andric   }
567753f127fSDimitry Andric   case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH:
568753f127fSDimitry Andric   case COFF::IMAGE_COMDAT_SELECT_SAME_SIZE: {
569753f127fSDimitry Andric     // FIXME: Implement size/content validation when LinkGraph is able to
570753f127fSDimitry Andric     // handle this.
571753f127fSDimitry Andric     L = Linkage::Weak;
572753f127fSDimitry Andric     break;
573753f127fSDimitry Andric   }
574753f127fSDimitry Andric   case COFF::IMAGE_COMDAT_SELECT_LARGEST: {
575972a253aSDimitry Andric     // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST properly when LinkGraph is
576972a253aSDimitry Andric     // able to handle this.
577972a253aSDimitry Andric     LLVM_DEBUG({
578972a253aSDimitry Andric       dbgs() << "    " << SymIndex
579972a253aSDimitry Andric              << ": Partially supported IMAGE_COMDAT_SELECT_LARGEST was used"
580972a253aSDimitry Andric                 " in section "
581bdd1243dSDimitry Andric              << Symbol.getSectionNumber() << " (size: " << Definition->Length
582bdd1243dSDimitry Andric              << ")\n";
583972a253aSDimitry Andric     });
584972a253aSDimitry Andric     L = Linkage::Weak;
585972a253aSDimitry Andric     break;
586753f127fSDimitry Andric   }
587753f127fSDimitry Andric   case COFF::IMAGE_COMDAT_SELECT_NEWEST: {
588753f127fSDimitry Andric     // Even link.exe doesn't support this selection properly.
589753f127fSDimitry Andric     return make_error<JITLinkError>(
590753f127fSDimitry Andric         "IMAGE_COMDAT_SELECT_NEWEST is not supported.");
591753f127fSDimitry Andric   }
592753f127fSDimitry Andric   default: {
593753f127fSDimitry Andric     return make_error<JITLinkError>("Invalid comdat selection type: " +
594753f127fSDimitry Andric                                     formatv("{0:d}", Definition->Selection));
595753f127fSDimitry Andric   }
596753f127fSDimitry Andric   }
597bdd1243dSDimitry Andric   PendingComdatExports[Symbol.getSectionNumber()] = {SymIndex, L,
598bdd1243dSDimitry Andric                                                      Definition->Length};
599bdd1243dSDimitry Andric   return nullptr;
600753f127fSDimitry Andric }
601753f127fSDimitry Andric 
602753f127fSDimitry Andric // Process the second symbol of COMDAT sequence.
603753f127fSDimitry Andric Expected<Symbol *>
604753f127fSDimitry Andric COFFLinkGraphBuilder::exportCOMDATSymbol(COFFSymbolIndex SymIndex,
605753f127fSDimitry Andric                                          StringRef SymbolName,
606753f127fSDimitry Andric                                          object::COFFSymbolRef Symbol) {
607bdd1243dSDimitry Andric   Block *B = getGraphBlock(Symbol.getSectionNumber());
608972a253aSDimitry Andric   auto &PendingComdatExport = PendingComdatExports[Symbol.getSectionNumber()];
609bdd1243dSDimitry Andric   // NOTE: ComdatDef->Legnth is the size of "section" not size of symbol.
610bdd1243dSDimitry Andric   // We use zero symbol size to not reach out of bound of block when symbol
611bdd1243dSDimitry Andric   // offset is non-zero.
612bdd1243dSDimitry Andric   auto GSym = &G->addDefinedSymbol(
613bdd1243dSDimitry Andric       *B, Symbol.getValue(), SymbolName, 0, PendingComdatExport->Linkage,
614bdd1243dSDimitry Andric       Scope::Default, Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION,
615bdd1243dSDimitry Andric       false);
616753f127fSDimitry Andric   LLVM_DEBUG({
617753f127fSDimitry Andric     dbgs() << "    " << SymIndex
618753f127fSDimitry Andric            << ": Exporting COMDAT graph symbol for COFF symbol \"" << SymbolName
619753f127fSDimitry Andric            << "\" in section " << Symbol.getSectionNumber() << "\n";
620bdd1243dSDimitry Andric     dbgs() << "      " << *GSym << "\n";
621753f127fSDimitry Andric   });
622bdd1243dSDimitry Andric   setGraphSymbol(Symbol.getSectionNumber(), PendingComdatExport->SymbolIndex,
623bdd1243dSDimitry Andric                  *GSym);
624bdd1243dSDimitry Andric   DefinedSymbols[SymbolName] = GSym;
625bdd1243dSDimitry Andric   PendingComdatExport = std::nullopt;
626bdd1243dSDimitry Andric   return GSym;
627753f127fSDimitry Andric }
628753f127fSDimitry Andric 
629753f127fSDimitry Andric } // namespace jitlink
630753f127fSDimitry Andric } // namespace llvm
631