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