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