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 // 9*5f757f3fSDimitry Andric // Generic COFF LinkGraph building 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( 2706c3fb27SDimitry Andric const object::COFFObjectFile &Obj, Triple TT, SubtargetFeatures Features, 28753f127fSDimitry Andric LinkGraph::GetEdgeKindNameFunction GetEdgeKindName) 2906c3fb27SDimitry Andric : Obj(Obj), G(std::make_unique<LinkGraph>( 3006c3fb27SDimitry Andric Obj.getFileName().str(), createTripleWithCOFFFormat(TT), 3106c3fb27SDimitry Andric std::move(Features), getPointerSize(Obj), 3206c3fb27SDimitry 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 46*5f757f3fSDimitry Andric llvm::endianness 47753f127fSDimitry Andric COFFLinkGraphBuilder::getEndianness(const object::COFFObjectFile &Obj) { 48*5f757f3fSDimitry Andric return Obj.isLittleEndian() ? llvm::endianness::little 49*5f757f3fSDimitry Andric : llvm::endianness::big; 50753f127fSDimitry Andric } 51753f127fSDimitry Andric 52753f127fSDimitry Andric uint64_t COFFLinkGraphBuilder::getSectionSize(const object::COFFObjectFile &Obj, 53753f127fSDimitry Andric const object::coff_section *Sec) { 54753f127fSDimitry Andric // Consider the difference between executable form and object form. 55753f127fSDimitry Andric // More information is inside COFFObjectFile::getSectionSize 56753f127fSDimitry Andric if (Obj.getDOSHeader()) 57753f127fSDimitry Andric return std::min(Sec->VirtualSize, Sec->SizeOfRawData); 58753f127fSDimitry Andric return Sec->SizeOfRawData; 59753f127fSDimitry Andric } 60753f127fSDimitry Andric 61753f127fSDimitry Andric uint64_t 62753f127fSDimitry Andric COFFLinkGraphBuilder::getSectionAddress(const object::COFFObjectFile &Obj, 63753f127fSDimitry Andric const object::coff_section *Section) { 64753f127fSDimitry Andric return Section->VirtualAddress + Obj.getImageBase(); 65753f127fSDimitry Andric } 66753f127fSDimitry Andric 67753f127fSDimitry Andric bool COFFLinkGraphBuilder::isComdatSection( 68753f127fSDimitry Andric const object::coff_section *Section) { 69753f127fSDimitry Andric return Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT; 70753f127fSDimitry Andric } 71753f127fSDimitry Andric 72753f127fSDimitry Andric Section &COFFLinkGraphBuilder::getCommonSection() { 73753f127fSDimitry Andric if (!CommonSection) 74bdd1243dSDimitry Andric CommonSection = &G->createSection(CommonSectionName, 75bdd1243dSDimitry Andric orc::MemProt::Read | orc::MemProt::Write); 76753f127fSDimitry Andric return *CommonSection; 77753f127fSDimitry Andric } 78753f127fSDimitry Andric 79753f127fSDimitry Andric Expected<std::unique_ptr<LinkGraph>> COFFLinkGraphBuilder::buildGraph() { 80753f127fSDimitry Andric if (!Obj.isRelocatableObject()) 81753f127fSDimitry Andric return make_error<JITLinkError>("Object is not a relocatable COFF file"); 82753f127fSDimitry Andric 83753f127fSDimitry Andric if (auto Err = graphifySections()) 84753f127fSDimitry Andric return std::move(Err); 85753f127fSDimitry Andric 86753f127fSDimitry Andric if (auto Err = graphifySymbols()) 87753f127fSDimitry Andric return std::move(Err); 88753f127fSDimitry Andric 89753f127fSDimitry Andric if (auto Err = addRelocations()) 90753f127fSDimitry Andric return std::move(Err); 91753f127fSDimitry Andric 92753f127fSDimitry Andric return std::move(G); 93753f127fSDimitry Andric } 94753f127fSDimitry Andric 95753f127fSDimitry Andric StringRef 96753f127fSDimitry Andric COFFLinkGraphBuilder::getCOFFSectionName(COFFSectionIndex SectionIndex, 97753f127fSDimitry Andric const object::coff_section *Sec, 98753f127fSDimitry Andric object::COFFSymbolRef Sym) { 99753f127fSDimitry Andric switch (SectionIndex) { 100753f127fSDimitry Andric case COFF::IMAGE_SYM_UNDEFINED: { 101753f127fSDimitry Andric if (Sym.getValue()) 102753f127fSDimitry Andric return "(common)"; 103753f127fSDimitry Andric else 104753f127fSDimitry Andric return "(external)"; 105753f127fSDimitry Andric } 106753f127fSDimitry Andric case COFF::IMAGE_SYM_ABSOLUTE: 107753f127fSDimitry Andric return "(absolute)"; 108753f127fSDimitry Andric case COFF::IMAGE_SYM_DEBUG: { 109753f127fSDimitry Andric // Used with .file symbol 110753f127fSDimitry Andric return "(debug)"; 111753f127fSDimitry Andric } 112753f127fSDimitry Andric default: { 113753f127fSDimitry Andric // Non reserved regular section numbers 114753f127fSDimitry Andric if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(Sec)) 115753f127fSDimitry Andric return *SecNameOrErr; 116753f127fSDimitry Andric } 117753f127fSDimitry Andric } 118753f127fSDimitry Andric return ""; 119753f127fSDimitry Andric } 120753f127fSDimitry Andric 121753f127fSDimitry Andric Error COFFLinkGraphBuilder::graphifySections() { 122753f127fSDimitry Andric LLVM_DEBUG(dbgs() << " Creating graph sections...\n"); 123753f127fSDimitry Andric 124753f127fSDimitry Andric GraphBlocks.resize(Obj.getNumberOfSections() + 1); 125753f127fSDimitry Andric // For each section... 126753f127fSDimitry Andric for (COFFSectionIndex SecIndex = 1; 127753f127fSDimitry Andric SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections()); 128753f127fSDimitry Andric SecIndex++) { 129753f127fSDimitry Andric Expected<const object::coff_section *> Sec = Obj.getSection(SecIndex); 130753f127fSDimitry Andric if (!Sec) 131753f127fSDimitry Andric return Sec.takeError(); 132753f127fSDimitry Andric 133753f127fSDimitry Andric StringRef SectionName; 134753f127fSDimitry Andric if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(*Sec)) 135753f127fSDimitry Andric SectionName = *SecNameOrErr; 136753f127fSDimitry Andric 137753f127fSDimitry Andric // FIXME: Skip debug info sections 13806c3fb27SDimitry Andric if (SectionName == ".voltbl") { 13906c3fb27SDimitry Andric LLVM_DEBUG({ 14006c3fb27SDimitry Andric dbgs() << " " 14106c3fb27SDimitry Andric << "Skipping section \"" << SectionName << "\"\n"; 14206c3fb27SDimitry Andric }); 14306c3fb27SDimitry Andric continue; 14406c3fb27SDimitry Andric } 145753f127fSDimitry Andric 146753f127fSDimitry Andric LLVM_DEBUG({ 147753f127fSDimitry Andric dbgs() << " " 148753f127fSDimitry Andric << "Creating section for \"" << SectionName << "\"\n"; 149753f127fSDimitry Andric }); 150753f127fSDimitry Andric 151753f127fSDimitry Andric // Get the section's memory protection flags. 152bdd1243dSDimitry Andric orc::MemProt Prot = orc::MemProt::Read; 153753f127fSDimitry Andric if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE) 154bdd1243dSDimitry Andric Prot |= orc::MemProt::Exec; 155753f127fSDimitry Andric if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_READ) 156bdd1243dSDimitry Andric Prot |= orc::MemProt::Read; 157753f127fSDimitry Andric if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_WRITE) 158bdd1243dSDimitry Andric Prot |= orc::MemProt::Write; 159753f127fSDimitry Andric 160753f127fSDimitry Andric // Look for existing sections first. 161753f127fSDimitry Andric auto *GraphSec = G->findSectionByName(SectionName); 16206c3fb27SDimitry Andric if (!GraphSec) { 163753f127fSDimitry Andric GraphSec = &G->createSection(SectionName, Prot); 16406c3fb27SDimitry Andric if ((*Sec)->Characteristics & COFF::IMAGE_SCN_LNK_REMOVE) 165*5f757f3fSDimitry Andric GraphSec->setMemLifetime(orc::MemLifetime::NoAlloc); 16606c3fb27SDimitry Andric } 167753f127fSDimitry Andric if (GraphSec->getMemProt() != Prot) 168753f127fSDimitry Andric return make_error<JITLinkError>("MemProt should match"); 169753f127fSDimitry Andric 170753f127fSDimitry Andric Block *B = nullptr; 171753f127fSDimitry Andric if ((*Sec)->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) 172753f127fSDimitry Andric B = &G->createZeroFillBlock( 173753f127fSDimitry Andric *GraphSec, getSectionSize(Obj, *Sec), 174753f127fSDimitry Andric orc::ExecutorAddr(getSectionAddress(Obj, *Sec)), 175753f127fSDimitry Andric (*Sec)->getAlignment(), 0); 176753f127fSDimitry Andric else { 177753f127fSDimitry Andric ArrayRef<uint8_t> Data; 178753f127fSDimitry Andric if (auto Err = Obj.getSectionContents(*Sec, Data)) 179753f127fSDimitry Andric return Err; 180753f127fSDimitry Andric 181bdd1243dSDimitry Andric auto CharData = ArrayRef<char>( 182bdd1243dSDimitry Andric reinterpret_cast<const char *>(Data.data()), Data.size()); 183bdd1243dSDimitry Andric 184bdd1243dSDimitry Andric if (SectionName == getDirectiveSectionName()) 185bdd1243dSDimitry Andric if (auto Err = handleDirectiveSection( 186bdd1243dSDimitry Andric StringRef(CharData.data(), CharData.size()))) 187bdd1243dSDimitry Andric return Err; 188bdd1243dSDimitry Andric 189753f127fSDimitry Andric B = &G->createContentBlock( 190bdd1243dSDimitry Andric *GraphSec, CharData, orc::ExecutorAddr(getSectionAddress(Obj, *Sec)), 191753f127fSDimitry Andric (*Sec)->getAlignment(), 0); 192753f127fSDimitry Andric } 193753f127fSDimitry Andric 194753f127fSDimitry Andric setGraphBlock(SecIndex, B); 195753f127fSDimitry Andric } 196753f127fSDimitry Andric 197753f127fSDimitry Andric return Error::success(); 198753f127fSDimitry Andric } 199753f127fSDimitry Andric 200753f127fSDimitry Andric Error COFFLinkGraphBuilder::graphifySymbols() { 201753f127fSDimitry Andric LLVM_DEBUG(dbgs() << " Creating graph symbols...\n"); 202753f127fSDimitry Andric 203753f127fSDimitry Andric SymbolSets.resize(Obj.getNumberOfSections() + 1); 204972a253aSDimitry Andric PendingComdatExports.resize(Obj.getNumberOfSections() + 1); 205753f127fSDimitry Andric GraphSymbols.resize(Obj.getNumberOfSymbols()); 206753f127fSDimitry Andric 207753f127fSDimitry Andric for (COFFSymbolIndex SymIndex = 0; 208753f127fSDimitry Andric SymIndex < static_cast<COFFSymbolIndex>(Obj.getNumberOfSymbols()); 209753f127fSDimitry Andric SymIndex++) { 210753f127fSDimitry Andric Expected<object::COFFSymbolRef> Sym = Obj.getSymbol(SymIndex); 211753f127fSDimitry Andric if (!Sym) 212753f127fSDimitry Andric return Sym.takeError(); 213753f127fSDimitry Andric 214753f127fSDimitry Andric StringRef SymbolName; 215753f127fSDimitry Andric if (Expected<StringRef> SymNameOrErr = Obj.getSymbolName(*Sym)) 216753f127fSDimitry Andric SymbolName = *SymNameOrErr; 217753f127fSDimitry Andric 218753f127fSDimitry Andric COFFSectionIndex SectionIndex = Sym->getSectionNumber(); 219753f127fSDimitry Andric const object::coff_section *Sec = nullptr; 220753f127fSDimitry Andric 221753f127fSDimitry Andric if (!COFF::isReservedSectionNumber(SectionIndex)) { 222753f127fSDimitry Andric auto SecOrErr = Obj.getSection(SectionIndex); 223753f127fSDimitry Andric if (!SecOrErr) 224753f127fSDimitry Andric return make_error<JITLinkError>( 225753f127fSDimitry Andric "Invalid COFF section number:" + formatv("{0:d}: ", SectionIndex) + 226753f127fSDimitry Andric " (" + toString(SecOrErr.takeError()) + ")"); 227753f127fSDimitry Andric Sec = *SecOrErr; 228753f127fSDimitry Andric } 229753f127fSDimitry Andric 230753f127fSDimitry Andric // Create jitlink symbol 231753f127fSDimitry Andric jitlink::Symbol *GSym = nullptr; 232753f127fSDimitry Andric if (Sym->isFileRecord()) 233753f127fSDimitry Andric LLVM_DEBUG({ 234753f127fSDimitry Andric dbgs() << " " << SymIndex << ": Skipping FileRecord symbol \"" 235753f127fSDimitry Andric << SymbolName << "\" in " 236753f127fSDimitry Andric << getCOFFSectionName(SectionIndex, Sec, *Sym) 237753f127fSDimitry Andric << " (index: " << SectionIndex << ") \n"; 238753f127fSDimitry Andric }); 239753f127fSDimitry Andric else if (Sym->isUndefined()) { 240bdd1243dSDimitry Andric GSym = createExternalSymbol(SymIndex, SymbolName, *Sym, Sec); 241753f127fSDimitry Andric } else if (Sym->isWeakExternal()) { 242972a253aSDimitry Andric auto *WeakExternal = Sym->getAux<object::coff_aux_weak_external>(); 243972a253aSDimitry Andric COFFSymbolIndex TagIndex = WeakExternal->TagIndex; 244972a253aSDimitry Andric uint32_t Characteristics = WeakExternal->Characteristics; 245972a253aSDimitry Andric WeakExternalRequests.push_back( 246972a253aSDimitry Andric {SymIndex, TagIndex, Characteristics, SymbolName}); 247753f127fSDimitry Andric } else { 248753f127fSDimitry Andric Expected<jitlink::Symbol *> NewGSym = 249753f127fSDimitry Andric createDefinedSymbol(SymIndex, SymbolName, *Sym, Sec); 250753f127fSDimitry Andric if (!NewGSym) 251753f127fSDimitry Andric return NewGSym.takeError(); 252753f127fSDimitry Andric GSym = *NewGSym; 253753f127fSDimitry Andric if (GSym) { 254753f127fSDimitry Andric LLVM_DEBUG({ 255753f127fSDimitry Andric dbgs() << " " << SymIndex 256753f127fSDimitry Andric << ": Creating defined graph symbol for COFF symbol \"" 257753f127fSDimitry Andric << SymbolName << "\" in " 258753f127fSDimitry Andric << getCOFFSectionName(SectionIndex, Sec, *Sym) 259753f127fSDimitry Andric << " (index: " << SectionIndex << ") \n"; 260753f127fSDimitry Andric dbgs() << " " << *GSym << "\n"; 261753f127fSDimitry Andric }); 262753f127fSDimitry Andric } 263753f127fSDimitry Andric } 264753f127fSDimitry Andric 265753f127fSDimitry Andric // Register the symbol 266753f127fSDimitry Andric if (GSym) 267753f127fSDimitry Andric setGraphSymbol(SectionIndex, SymIndex, *GSym); 268753f127fSDimitry Andric SymIndex += Sym->getNumberOfAuxSymbols(); 269753f127fSDimitry Andric } 270753f127fSDimitry Andric 271753f127fSDimitry Andric if (auto Err = flushWeakAliasRequests()) 272753f127fSDimitry Andric return Err; 273753f127fSDimitry Andric 274bdd1243dSDimitry Andric if (auto Err = handleAlternateNames()) 275bdd1243dSDimitry Andric return Err; 276bdd1243dSDimitry Andric 277753f127fSDimitry Andric if (auto Err = calculateImplicitSizeOfSymbols()) 278753f127fSDimitry Andric return Err; 279753f127fSDimitry Andric 280753f127fSDimitry Andric return Error::success(); 281753f127fSDimitry Andric } 282753f127fSDimitry Andric 283bdd1243dSDimitry Andric Error COFFLinkGraphBuilder::handleDirectiveSection(StringRef Str) { 284bdd1243dSDimitry Andric auto Parsed = DirectiveParser.parse(Str); 285bdd1243dSDimitry Andric if (!Parsed) 286bdd1243dSDimitry Andric return Parsed.takeError(); 287bdd1243dSDimitry Andric for (auto *Arg : *Parsed) { 288bdd1243dSDimitry Andric StringRef S = Arg->getValue(); 289bdd1243dSDimitry Andric switch (Arg->getOption().getID()) { 290bdd1243dSDimitry Andric case COFF_OPT_alternatename: { 291bdd1243dSDimitry Andric StringRef From, To; 292bdd1243dSDimitry Andric std::tie(From, To) = S.split('='); 293bdd1243dSDimitry Andric if (From.empty() || To.empty()) 294bdd1243dSDimitry Andric return make_error<JITLinkError>( 295bdd1243dSDimitry Andric "Invalid COFF /alternatename directive"); 296bdd1243dSDimitry Andric AlternateNames[From] = To; 297bdd1243dSDimitry Andric break; 298bdd1243dSDimitry Andric } 299bdd1243dSDimitry Andric case COFF_OPT_incl: { 30006c3fb27SDimitry Andric auto DataCopy = G->allocateContent(S); 301bdd1243dSDimitry Andric StringRef StrCopy(DataCopy.data(), DataCopy.size()); 302bdd1243dSDimitry Andric ExternalSymbols[StrCopy] = &G->addExternalSymbol(StrCopy, 0, false); 303bdd1243dSDimitry Andric ExternalSymbols[StrCopy]->setLive(true); 304bdd1243dSDimitry Andric break; 305bdd1243dSDimitry Andric } 306bdd1243dSDimitry Andric case COFF_OPT_export: 307bdd1243dSDimitry Andric break; 308bdd1243dSDimitry Andric default: { 309bdd1243dSDimitry Andric LLVM_DEBUG({ 310bdd1243dSDimitry Andric dbgs() << "Unknown coff directive: " << Arg->getSpelling() << "\n"; 311bdd1243dSDimitry Andric }); 312bdd1243dSDimitry Andric break; 313bdd1243dSDimitry Andric } 314bdd1243dSDimitry Andric } 315bdd1243dSDimitry Andric } 316bdd1243dSDimitry Andric return Error::success(); 317bdd1243dSDimitry Andric } 318bdd1243dSDimitry Andric 319753f127fSDimitry Andric Error COFFLinkGraphBuilder::flushWeakAliasRequests() { 320753f127fSDimitry Andric // Export the weak external symbols and alias it 321972a253aSDimitry Andric for (auto &WeakExternal : WeakExternalRequests) { 322972a253aSDimitry Andric if (auto *Target = getGraphSymbol(WeakExternal.Target)) { 323753f127fSDimitry Andric Expected<object::COFFSymbolRef> AliasSymbol = 324972a253aSDimitry Andric Obj.getSymbol(WeakExternal.Alias); 325753f127fSDimitry Andric if (!AliasSymbol) 326753f127fSDimitry Andric return AliasSymbol.takeError(); 327753f127fSDimitry Andric 328972a253aSDimitry Andric // FIXME: IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY and 329972a253aSDimitry Andric // IMAGE_WEAK_EXTERN_SEARCH_LIBRARY are handled in the same way. 330972a253aSDimitry Andric Scope S = 331972a253aSDimitry Andric WeakExternal.Characteristics == COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS 332972a253aSDimitry Andric ? Scope::Default 333972a253aSDimitry Andric : Scope::Local; 334972a253aSDimitry Andric 335bdd1243dSDimitry Andric auto NewSymbol = 336bdd1243dSDimitry Andric createAliasSymbol(WeakExternal.SymbolName, Linkage::Weak, S, *Target); 337bdd1243dSDimitry Andric if (!NewSymbol) 338bdd1243dSDimitry Andric return NewSymbol.takeError(); 339972a253aSDimitry Andric setGraphSymbol(AliasSymbol->getSectionNumber(), WeakExternal.Alias, 340bdd1243dSDimitry Andric **NewSymbol); 341753f127fSDimitry Andric LLVM_DEBUG({ 342972a253aSDimitry Andric dbgs() << " " << WeakExternal.Alias 343753f127fSDimitry Andric << ": Creating weak external symbol for COFF symbol \"" 344972a253aSDimitry Andric << WeakExternal.SymbolName << "\" in section " 345753f127fSDimitry Andric << AliasSymbol->getSectionNumber() << "\n"; 346bdd1243dSDimitry Andric dbgs() << " " << **NewSymbol << "\n"; 347753f127fSDimitry Andric }); 348753f127fSDimitry Andric } else 349753f127fSDimitry Andric return make_error<JITLinkError>("Weak symbol alias requested but actual " 350753f127fSDimitry Andric "symbol not found for symbol " + 351972a253aSDimitry Andric formatv("{0:d}", WeakExternal.Alias)); 352753f127fSDimitry Andric } 353753f127fSDimitry Andric return Error::success(); 354753f127fSDimitry Andric } 355753f127fSDimitry Andric 356bdd1243dSDimitry Andric Error COFFLinkGraphBuilder::handleAlternateNames() { 357bdd1243dSDimitry Andric for (auto &KeyValue : AlternateNames) 358bdd1243dSDimitry Andric if (DefinedSymbols.count(KeyValue.second) && 359bdd1243dSDimitry Andric ExternalSymbols.count(KeyValue.first)) { 360bdd1243dSDimitry Andric auto *Target = DefinedSymbols[KeyValue.second]; 361bdd1243dSDimitry Andric auto *Alias = ExternalSymbols[KeyValue.first]; 362bdd1243dSDimitry Andric G->makeDefined(*Alias, Target->getBlock(), Target->getOffset(), 363bdd1243dSDimitry Andric Target->getSize(), Linkage::Weak, Scope::Local, false); 364bdd1243dSDimitry Andric } 365bdd1243dSDimitry Andric return Error::success(); 366bdd1243dSDimitry Andric } 367bdd1243dSDimitry Andric 368bdd1243dSDimitry Andric Symbol *COFFLinkGraphBuilder::createExternalSymbol( 369bdd1243dSDimitry Andric COFFSymbolIndex SymIndex, StringRef SymbolName, 370bdd1243dSDimitry Andric object::COFFSymbolRef Symbol, const object::coff_section *Section) { 371bdd1243dSDimitry Andric if (!ExternalSymbols.count(SymbolName)) 372bdd1243dSDimitry Andric ExternalSymbols[SymbolName] = 373bdd1243dSDimitry Andric &G->addExternalSymbol(SymbolName, Symbol.getValue(), false); 374bdd1243dSDimitry Andric 375bdd1243dSDimitry Andric LLVM_DEBUG({ 376bdd1243dSDimitry Andric dbgs() << " " << SymIndex 377bdd1243dSDimitry Andric << ": Creating external graph symbol for COFF symbol \"" 378bdd1243dSDimitry Andric << SymbolName << "\" in " 379bdd1243dSDimitry Andric << getCOFFSectionName(Symbol.getSectionNumber(), Section, Symbol) 380bdd1243dSDimitry Andric << " (index: " << Symbol.getSectionNumber() << ") \n"; 381bdd1243dSDimitry Andric }); 382bdd1243dSDimitry Andric return ExternalSymbols[SymbolName]; 383bdd1243dSDimitry Andric } 384bdd1243dSDimitry Andric 385bdd1243dSDimitry Andric Expected<Symbol *> COFFLinkGraphBuilder::createAliasSymbol(StringRef SymbolName, 386bdd1243dSDimitry Andric Linkage L, Scope S, 387bdd1243dSDimitry Andric Symbol &Target) { 388bdd1243dSDimitry Andric if (!Target.isDefined()) { 389bdd1243dSDimitry Andric // FIXME: Support this when there's a way to handle this. 390bdd1243dSDimitry Andric return make_error<JITLinkError>("Weak external symbol with external " 391bdd1243dSDimitry Andric "symbol as alternative not supported."); 392bdd1243dSDimitry Andric } 393bdd1243dSDimitry Andric return &G->addDefinedSymbol(Target.getBlock(), Target.getOffset(), SymbolName, 394bdd1243dSDimitry Andric Target.getSize(), L, S, Target.isCallable(), 395bdd1243dSDimitry Andric false); 396bdd1243dSDimitry Andric } 397bdd1243dSDimitry Andric 398753f127fSDimitry Andric // In COFF, most of the defined symbols don't contain the size information. 399753f127fSDimitry Andric // Hence, we calculate the "implicit" size of symbol by taking the delta of 400753f127fSDimitry Andric // offsets of consecutive symbols within a block. We maintain a balanced tree 401753f127fSDimitry Andric // set of symbols sorted by offset per each block in order to achieve 402753f127fSDimitry Andric // logarithmic time complexity of sorted symbol insertion. Symbol is inserted to 403753f127fSDimitry Andric // the set once it's processed in graphifySymbols. In this function, we iterate 404753f127fSDimitry Andric // each collected symbol in sorted order and calculate the implicit size. 405753f127fSDimitry Andric Error COFFLinkGraphBuilder::calculateImplicitSizeOfSymbols() { 406753f127fSDimitry Andric for (COFFSectionIndex SecIndex = 1; 407753f127fSDimitry Andric SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections()); 408753f127fSDimitry Andric SecIndex++) { 409753f127fSDimitry Andric auto &SymbolSet = SymbolSets[SecIndex]; 410972a253aSDimitry Andric if (SymbolSet.empty()) 411972a253aSDimitry Andric continue; 412753f127fSDimitry Andric jitlink::Block *B = getGraphBlock(SecIndex); 413753f127fSDimitry Andric orc::ExecutorAddrDiff LastOffset = B->getSize(); 414753f127fSDimitry Andric orc::ExecutorAddrDiff LastDifferentOffset = B->getSize(); 415753f127fSDimitry Andric orc::ExecutorAddrDiff LastSize = 0; 416753f127fSDimitry Andric for (auto It = SymbolSet.rbegin(); It != SymbolSet.rend(); It++) { 417753f127fSDimitry Andric orc::ExecutorAddrDiff Offset = It->first; 418753f127fSDimitry Andric jitlink::Symbol *Symbol = It->second; 419753f127fSDimitry Andric orc::ExecutorAddrDiff CandSize; 420753f127fSDimitry Andric // Last offset can be same when aliasing happened 421753f127fSDimitry Andric if (Symbol->getOffset() == LastOffset) 422753f127fSDimitry Andric CandSize = LastSize; 423753f127fSDimitry Andric else 424753f127fSDimitry Andric CandSize = LastOffset - Offset; 425753f127fSDimitry Andric 426753f127fSDimitry Andric LLVM_DEBUG({ 427753f127fSDimitry Andric if (Offset + Symbol->getSize() > LastDifferentOffset) 428753f127fSDimitry Andric dbgs() << " Overlapping symbol range generated for the following " 429753f127fSDimitry Andric "symbol:" 430753f127fSDimitry Andric << "\n" 431753f127fSDimitry Andric << " " << *Symbol << "\n"; 432753f127fSDimitry Andric }); 433753f127fSDimitry Andric (void)LastDifferentOffset; 434753f127fSDimitry Andric if (LastOffset != Offset) 435753f127fSDimitry Andric LastDifferentOffset = Offset; 436753f127fSDimitry Andric LastSize = CandSize; 437753f127fSDimitry Andric LastOffset = Offset; 438753f127fSDimitry Andric if (Symbol->getSize()) { 439753f127fSDimitry Andric // Non empty symbol can happen in COMDAT symbol. 440753f127fSDimitry Andric // We don't consider the possibility of overlapping symbol range that 441753f127fSDimitry Andric // could be introduced by disparity between inferred symbol size and 442753f127fSDimitry Andric // defined symbol size because symbol size information is currently only 443753f127fSDimitry Andric // used by jitlink-check where we have control to not make overlapping 444753f127fSDimitry Andric // ranges. 445753f127fSDimitry Andric continue; 446753f127fSDimitry Andric } 447753f127fSDimitry Andric 448753f127fSDimitry Andric LLVM_DEBUG({ 449753f127fSDimitry Andric if (!CandSize) 450753f127fSDimitry Andric dbgs() << " Empty implicit symbol size generated for the following " 451753f127fSDimitry Andric "symbol:" 452753f127fSDimitry Andric << "\n" 453753f127fSDimitry Andric << " " << *Symbol << "\n"; 454753f127fSDimitry Andric }); 455753f127fSDimitry Andric 456753f127fSDimitry Andric Symbol->setSize(CandSize); 457753f127fSDimitry Andric } 458753f127fSDimitry Andric } 459753f127fSDimitry Andric return Error::success(); 460753f127fSDimitry Andric } 461753f127fSDimitry Andric 462753f127fSDimitry Andric Expected<Symbol *> COFFLinkGraphBuilder::createDefinedSymbol( 463753f127fSDimitry Andric COFFSymbolIndex SymIndex, StringRef SymbolName, 464753f127fSDimitry Andric object::COFFSymbolRef Symbol, const object::coff_section *Section) { 465753f127fSDimitry Andric if (Symbol.isCommon()) { 466753f127fSDimitry Andric // FIXME: correct alignment 467bdd1243dSDimitry Andric return &G->addDefinedSymbol( 468bdd1243dSDimitry Andric G->createZeroFillBlock(getCommonSection(), Symbol.getValue(), 469bdd1243dSDimitry Andric orc::ExecutorAddr(), Symbol.getValue(), 0), 470bdd1243dSDimitry Andric 0, SymbolName, Symbol.getValue(), Linkage::Strong, Scope::Default, 471bdd1243dSDimitry Andric false, false); 472753f127fSDimitry Andric } 473753f127fSDimitry Andric if (Symbol.isAbsolute()) 474753f127fSDimitry Andric return &G->addAbsoluteSymbol(SymbolName, 475753f127fSDimitry Andric orc::ExecutorAddr(Symbol.getValue()), 0, 476753f127fSDimitry Andric Linkage::Strong, Scope::Local, false); 477753f127fSDimitry Andric 478753f127fSDimitry Andric if (llvm::COFF::isReservedSectionNumber(Symbol.getSectionNumber())) 479753f127fSDimitry Andric return make_error<JITLinkError>( 480753f127fSDimitry Andric "Reserved section number used in regular symbol " + 481753f127fSDimitry Andric formatv("{0:d}", SymIndex)); 482753f127fSDimitry Andric 483753f127fSDimitry Andric Block *B = getGraphBlock(Symbol.getSectionNumber()); 484972a253aSDimitry Andric if (!B) { 485972a253aSDimitry Andric LLVM_DEBUG({ 486972a253aSDimitry Andric dbgs() << " " << SymIndex 487972a253aSDimitry Andric << ": Skipping graph symbol since section was not created for " 488972a253aSDimitry Andric "COFF symbol \"" 489972a253aSDimitry Andric << SymbolName << "\" in section " << Symbol.getSectionNumber() 490972a253aSDimitry Andric << "\n"; 491972a253aSDimitry Andric }); 492972a253aSDimitry Andric return nullptr; 493972a253aSDimitry Andric } 494972a253aSDimitry Andric 495753f127fSDimitry Andric if (Symbol.isExternal()) { 496753f127fSDimitry Andric // This is not a comdat sequence, export the symbol as it is 497972a253aSDimitry Andric if (!isComdatSection(Section)) { 498bdd1243dSDimitry Andric auto GSym = &G->addDefinedSymbol( 499753f127fSDimitry Andric *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Default, 500753f127fSDimitry Andric Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); 501bdd1243dSDimitry Andric DefinedSymbols[SymbolName] = GSym; 502bdd1243dSDimitry Andric return GSym; 503972a253aSDimitry Andric } else { 504972a253aSDimitry Andric if (!PendingComdatExports[Symbol.getSectionNumber()]) 505753f127fSDimitry Andric return make_error<JITLinkError>("No pending COMDAT export for symbol " + 506753f127fSDimitry Andric formatv("{0:d}", SymIndex)); 507972a253aSDimitry Andric 508753f127fSDimitry Andric return exportCOMDATSymbol(SymIndex, SymbolName, Symbol); 509753f127fSDimitry Andric } 510753f127fSDimitry Andric } 511753f127fSDimitry Andric 512972a253aSDimitry Andric if (Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC || 513972a253aSDimitry Andric Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_LABEL) { 514753f127fSDimitry Andric const object::coff_aux_section_definition *Definition = 515753f127fSDimitry Andric Symbol.getSectionDefinition(); 516753f127fSDimitry Andric if (!Definition || !isComdatSection(Section)) { 517753f127fSDimitry Andric // Handle typical static symbol 518753f127fSDimitry Andric return &G->addDefinedSymbol( 519753f127fSDimitry Andric *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local, 520753f127fSDimitry Andric Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); 521753f127fSDimitry Andric } 522753f127fSDimitry Andric if (Definition->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { 523972a253aSDimitry Andric auto Target = Definition->getNumber(Symbol.isBigObj()); 524972a253aSDimitry Andric auto GSym = &G->addDefinedSymbol( 525753f127fSDimitry Andric *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local, 526753f127fSDimitry Andric Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); 527972a253aSDimitry Andric getGraphBlock(Target)->addEdge(Edge::KeepAlive, 0, *GSym, 0); 528972a253aSDimitry Andric return GSym; 529753f127fSDimitry Andric } 530972a253aSDimitry Andric if (PendingComdatExports[Symbol.getSectionNumber()]) 531753f127fSDimitry Andric return make_error<JITLinkError>( 532753f127fSDimitry Andric "COMDAT export request already exists before symbol " + 533753f127fSDimitry Andric formatv("{0:d}", SymIndex)); 534753f127fSDimitry Andric return createCOMDATExportRequest(SymIndex, Symbol, Definition); 535753f127fSDimitry Andric } 536753f127fSDimitry Andric return make_error<JITLinkError>("Unsupported storage class " + 537753f127fSDimitry Andric formatv("{0:d}", Symbol.getStorageClass()) + 538753f127fSDimitry Andric " in symbol " + formatv("{0:d}", SymIndex)); 539753f127fSDimitry Andric } 540753f127fSDimitry Andric 541753f127fSDimitry Andric // COMDAT handling: 542753f127fSDimitry Andric // When IMAGE_SCN_LNK_COMDAT flag is set in the flags of a section, 543753f127fSDimitry Andric // the section is called a COMDAT section. It contains two symbols 544753f127fSDimitry Andric // in a sequence that specifes the behavior. First symbol is the section 545753f127fSDimitry Andric // symbol which contains the size and name of the section. It also contains 546753f127fSDimitry Andric // selection type that specifies how duplicate of the symbol is handled. 547753f127fSDimitry Andric // Second symbol is COMDAT symbol which usually defines the external name and 548753f127fSDimitry Andric // data type. 549753f127fSDimitry Andric // 550753f127fSDimitry Andric // Since two symbols always come in a specific order, we initiate pending COMDAT 551753f127fSDimitry Andric // export request when we encounter the first symbol and actually exports it 552753f127fSDimitry Andric // when we process the second symbol. 553753f127fSDimitry Andric // 554753f127fSDimitry Andric // Process the first symbol of COMDAT sequence. 555753f127fSDimitry Andric Expected<Symbol *> COFFLinkGraphBuilder::createCOMDATExportRequest( 556753f127fSDimitry Andric COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol, 557753f127fSDimitry Andric const object::coff_aux_section_definition *Definition) { 558753f127fSDimitry Andric Linkage L = Linkage::Strong; 559753f127fSDimitry Andric switch (Definition->Selection) { 560753f127fSDimitry Andric case COFF::IMAGE_COMDAT_SELECT_NODUPLICATES: { 561753f127fSDimitry Andric L = Linkage::Strong; 562753f127fSDimitry Andric break; 563753f127fSDimitry Andric } 564753f127fSDimitry Andric case COFF::IMAGE_COMDAT_SELECT_ANY: { 565753f127fSDimitry Andric L = Linkage::Weak; 566753f127fSDimitry Andric break; 567753f127fSDimitry Andric } 568753f127fSDimitry Andric case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH: 569753f127fSDimitry Andric case COFF::IMAGE_COMDAT_SELECT_SAME_SIZE: { 570753f127fSDimitry Andric // FIXME: Implement size/content validation when LinkGraph is able to 571753f127fSDimitry Andric // handle this. 572753f127fSDimitry Andric L = Linkage::Weak; 573753f127fSDimitry Andric break; 574753f127fSDimitry Andric } 575753f127fSDimitry Andric case COFF::IMAGE_COMDAT_SELECT_LARGEST: { 576972a253aSDimitry Andric // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST properly when LinkGraph is 577972a253aSDimitry Andric // able to handle this. 578972a253aSDimitry Andric LLVM_DEBUG({ 579972a253aSDimitry Andric dbgs() << " " << SymIndex 580972a253aSDimitry Andric << ": Partially supported IMAGE_COMDAT_SELECT_LARGEST was used" 581972a253aSDimitry Andric " in section " 582bdd1243dSDimitry Andric << Symbol.getSectionNumber() << " (size: " << Definition->Length 583bdd1243dSDimitry Andric << ")\n"; 584972a253aSDimitry Andric }); 585972a253aSDimitry Andric L = Linkage::Weak; 586972a253aSDimitry Andric break; 587753f127fSDimitry Andric } 588753f127fSDimitry Andric case COFF::IMAGE_COMDAT_SELECT_NEWEST: { 589753f127fSDimitry Andric // Even link.exe doesn't support this selection properly. 590753f127fSDimitry Andric return make_error<JITLinkError>( 591753f127fSDimitry Andric "IMAGE_COMDAT_SELECT_NEWEST is not supported."); 592753f127fSDimitry Andric } 593753f127fSDimitry Andric default: { 594753f127fSDimitry Andric return make_error<JITLinkError>("Invalid comdat selection type: " + 595753f127fSDimitry Andric formatv("{0:d}", Definition->Selection)); 596753f127fSDimitry Andric } 597753f127fSDimitry Andric } 598bdd1243dSDimitry Andric PendingComdatExports[Symbol.getSectionNumber()] = {SymIndex, L, 599bdd1243dSDimitry Andric Definition->Length}; 600bdd1243dSDimitry Andric return nullptr; 601753f127fSDimitry Andric } 602753f127fSDimitry Andric 603753f127fSDimitry Andric // Process the second symbol of COMDAT sequence. 604753f127fSDimitry Andric Expected<Symbol *> 605753f127fSDimitry Andric COFFLinkGraphBuilder::exportCOMDATSymbol(COFFSymbolIndex SymIndex, 606753f127fSDimitry Andric StringRef SymbolName, 607753f127fSDimitry Andric object::COFFSymbolRef Symbol) { 608bdd1243dSDimitry Andric Block *B = getGraphBlock(Symbol.getSectionNumber()); 609972a253aSDimitry Andric auto &PendingComdatExport = PendingComdatExports[Symbol.getSectionNumber()]; 610*5f757f3fSDimitry Andric // NOTE: ComdatDef->Length is the size of "section" not size of symbol. 611bdd1243dSDimitry Andric // We use zero symbol size to not reach out of bound of block when symbol 612bdd1243dSDimitry Andric // offset is non-zero. 613bdd1243dSDimitry Andric auto GSym = &G->addDefinedSymbol( 614bdd1243dSDimitry Andric *B, Symbol.getValue(), SymbolName, 0, PendingComdatExport->Linkage, 615bdd1243dSDimitry Andric Scope::Default, Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, 616bdd1243dSDimitry Andric false); 617753f127fSDimitry Andric LLVM_DEBUG({ 618753f127fSDimitry Andric dbgs() << " " << SymIndex 619753f127fSDimitry Andric << ": Exporting COMDAT graph symbol for COFF symbol \"" << SymbolName 620753f127fSDimitry Andric << "\" in section " << Symbol.getSectionNumber() << "\n"; 621bdd1243dSDimitry Andric dbgs() << " " << *GSym << "\n"; 622753f127fSDimitry Andric }); 623bdd1243dSDimitry Andric setGraphSymbol(Symbol.getSectionNumber(), PendingComdatExport->SymbolIndex, 624bdd1243dSDimitry Andric *GSym); 625bdd1243dSDimitry Andric DefinedSymbols[SymbolName] = GSym; 626bdd1243dSDimitry Andric PendingComdatExport = std::nullopt; 627bdd1243dSDimitry Andric return GSym; 628753f127fSDimitry Andric } 629753f127fSDimitry Andric 630753f127fSDimitry Andric } // namespace jitlink 631753f127fSDimitry Andric } // namespace llvm 632