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 21*972a253aSDimitry Andric static Triple createTripleWithCOFFFormat(Triple T) { 22*972a253aSDimitry Andric T.setObjectFormat(Triple::COFF); 23*972a253aSDimitry Andric return T; 24*972a253aSDimitry Andric } 25*972a253aSDimitry Andric 26753f127fSDimitry Andric COFFLinkGraphBuilder::COFFLinkGraphBuilder( 27753f127fSDimitry Andric const object::COFFObjectFile &Obj, Triple TT, 28753f127fSDimitry Andric LinkGraph::GetEdgeKindNameFunction GetEdgeKindName) 29753f127fSDimitry Andric : Obj(Obj), 30*972a253aSDimitry Andric G(std::make_unique<LinkGraph>(Obj.getFileName().str(), 31*972a253aSDimitry Andric createTripleWithCOFFFormat(TT), 32*972a253aSDimitry Andric getPointerSize(Obj), getEndianness(Obj), 33*972a253aSDimitry Andric std::move(GetEdgeKindName))) { 34753f127fSDimitry Andric LLVM_DEBUG({ 35753f127fSDimitry Andric dbgs() << "Created COFFLinkGraphBuilder for \"" << Obj.getFileName() 36753f127fSDimitry Andric << "\"\n"; 37753f127fSDimitry Andric }); 38753f127fSDimitry Andric } 39753f127fSDimitry Andric 40753f127fSDimitry Andric COFFLinkGraphBuilder::~COFFLinkGraphBuilder() = default; 41753f127fSDimitry Andric 42753f127fSDimitry Andric unsigned 43753f127fSDimitry Andric COFFLinkGraphBuilder::getPointerSize(const object::COFFObjectFile &Obj) { 44753f127fSDimitry Andric return Obj.getBytesInAddress(); 45753f127fSDimitry Andric } 46753f127fSDimitry Andric 47753f127fSDimitry Andric support::endianness 48753f127fSDimitry Andric COFFLinkGraphBuilder::getEndianness(const object::COFFObjectFile &Obj) { 49753f127fSDimitry Andric return Obj.isLittleEndian() ? support::little : support::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) 74753f127fSDimitry Andric CommonSection = 75753f127fSDimitry Andric &G->createSection(CommonSectionName, MemProt::Read | 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 138753f127fSDimitry Andric 139753f127fSDimitry Andric LLVM_DEBUG({ 140753f127fSDimitry Andric dbgs() << " " 141753f127fSDimitry Andric << "Creating section for \"" << SectionName << "\"\n"; 142753f127fSDimitry Andric }); 143753f127fSDimitry Andric 144*972a253aSDimitry Andric // FIXME: Revisit crash when dropping IMAGE_SCN_MEM_DISCARDABLE sections 145*972a253aSDimitry Andric 146753f127fSDimitry Andric // Get the section's memory protection flags. 147753f127fSDimitry Andric MemProt Prot = MemProt::None; 148753f127fSDimitry Andric if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE) 149753f127fSDimitry Andric Prot |= MemProt::Exec; 150753f127fSDimitry Andric if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_READ) 151753f127fSDimitry Andric Prot |= MemProt::Read; 152753f127fSDimitry Andric if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_WRITE) 153753f127fSDimitry Andric Prot |= MemProt::Write; 154753f127fSDimitry Andric 155753f127fSDimitry Andric // Look for existing sections first. 156753f127fSDimitry Andric auto *GraphSec = G->findSectionByName(SectionName); 157753f127fSDimitry Andric if (!GraphSec) 158753f127fSDimitry Andric GraphSec = &G->createSection(SectionName, Prot); 159753f127fSDimitry Andric if (GraphSec->getMemProt() != Prot) 160753f127fSDimitry Andric return make_error<JITLinkError>("MemProt should match"); 161753f127fSDimitry Andric 162753f127fSDimitry Andric Block *B = nullptr; 163753f127fSDimitry Andric if ((*Sec)->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) 164753f127fSDimitry Andric B = &G->createZeroFillBlock( 165753f127fSDimitry Andric *GraphSec, getSectionSize(Obj, *Sec), 166753f127fSDimitry Andric orc::ExecutorAddr(getSectionAddress(Obj, *Sec)), 167753f127fSDimitry Andric (*Sec)->getAlignment(), 0); 168753f127fSDimitry Andric else { 169753f127fSDimitry Andric ArrayRef<uint8_t> Data; 170753f127fSDimitry Andric if (auto Err = Obj.getSectionContents(*Sec, Data)) 171753f127fSDimitry Andric return Err; 172753f127fSDimitry Andric 173753f127fSDimitry Andric B = &G->createContentBlock( 174753f127fSDimitry Andric *GraphSec, 175753f127fSDimitry Andric ArrayRef<char>(reinterpret_cast<const char *>(Data.data()), 176753f127fSDimitry Andric Data.size()), 177753f127fSDimitry Andric orc::ExecutorAddr(getSectionAddress(Obj, *Sec)), 178753f127fSDimitry Andric (*Sec)->getAlignment(), 0); 179753f127fSDimitry Andric } 180753f127fSDimitry Andric 181753f127fSDimitry Andric setGraphBlock(SecIndex, B); 182753f127fSDimitry Andric } 183753f127fSDimitry Andric 184753f127fSDimitry Andric return Error::success(); 185753f127fSDimitry Andric } 186753f127fSDimitry Andric 187753f127fSDimitry Andric Error COFFLinkGraphBuilder::graphifySymbols() { 188753f127fSDimitry Andric LLVM_DEBUG(dbgs() << " Creating graph symbols...\n"); 189753f127fSDimitry Andric 190753f127fSDimitry Andric SymbolSets.resize(Obj.getNumberOfSections() + 1); 191*972a253aSDimitry Andric PendingComdatExports.resize(Obj.getNumberOfSections() + 1); 192753f127fSDimitry Andric GraphSymbols.resize(Obj.getNumberOfSymbols()); 193753f127fSDimitry Andric 194753f127fSDimitry Andric for (COFFSymbolIndex SymIndex = 0; 195753f127fSDimitry Andric SymIndex < static_cast<COFFSymbolIndex>(Obj.getNumberOfSymbols()); 196753f127fSDimitry Andric SymIndex++) { 197753f127fSDimitry Andric Expected<object::COFFSymbolRef> Sym = Obj.getSymbol(SymIndex); 198753f127fSDimitry Andric if (!Sym) 199753f127fSDimitry Andric return Sym.takeError(); 200753f127fSDimitry Andric 201753f127fSDimitry Andric StringRef SymbolName; 202753f127fSDimitry Andric if (Expected<StringRef> SymNameOrErr = Obj.getSymbolName(*Sym)) 203753f127fSDimitry Andric SymbolName = *SymNameOrErr; 204753f127fSDimitry Andric 205753f127fSDimitry Andric COFFSectionIndex SectionIndex = Sym->getSectionNumber(); 206753f127fSDimitry Andric const object::coff_section *Sec = nullptr; 207753f127fSDimitry Andric 208753f127fSDimitry Andric if (!COFF::isReservedSectionNumber(SectionIndex)) { 209753f127fSDimitry Andric auto SecOrErr = Obj.getSection(SectionIndex); 210753f127fSDimitry Andric if (!SecOrErr) 211753f127fSDimitry Andric return make_error<JITLinkError>( 212753f127fSDimitry Andric "Invalid COFF section number:" + formatv("{0:d}: ", SectionIndex) + 213753f127fSDimitry Andric " (" + toString(SecOrErr.takeError()) + ")"); 214753f127fSDimitry Andric Sec = *SecOrErr; 215753f127fSDimitry Andric } 216753f127fSDimitry Andric 217753f127fSDimitry Andric // Create jitlink symbol 218753f127fSDimitry Andric jitlink::Symbol *GSym = nullptr; 219753f127fSDimitry Andric if (Sym->isFileRecord()) 220753f127fSDimitry Andric LLVM_DEBUG({ 221753f127fSDimitry Andric dbgs() << " " << SymIndex << ": Skipping FileRecord symbol \"" 222753f127fSDimitry Andric << SymbolName << "\" in " 223753f127fSDimitry Andric << getCOFFSectionName(SectionIndex, Sec, *Sym) 224753f127fSDimitry Andric << " (index: " << SectionIndex << ") \n"; 225753f127fSDimitry Andric }); 226753f127fSDimitry Andric else if (Sym->isUndefined()) { 227753f127fSDimitry Andric LLVM_DEBUG({ 228753f127fSDimitry Andric dbgs() << " " << SymIndex 229753f127fSDimitry Andric << ": Creating external graph symbol for COFF symbol \"" 230753f127fSDimitry Andric << SymbolName << "\" in " 231753f127fSDimitry Andric << getCOFFSectionName(SectionIndex, Sec, *Sym) 232753f127fSDimitry Andric << " (index: " << SectionIndex << ") \n"; 233753f127fSDimitry Andric }); 234*972a253aSDimitry Andric if (!ExternalSymbols.count(SymbolName)) 235*972a253aSDimitry Andric ExternalSymbols[SymbolName] = 236753f127fSDimitry Andric &G->addExternalSymbol(SymbolName, Sym->getValue(), Linkage::Strong); 237*972a253aSDimitry Andric GSym = ExternalSymbols[SymbolName]; 238753f127fSDimitry Andric } else if (Sym->isWeakExternal()) { 239*972a253aSDimitry Andric auto *WeakExternal = Sym->getAux<object::coff_aux_weak_external>(); 240*972a253aSDimitry Andric COFFSymbolIndex TagIndex = WeakExternal->TagIndex; 241*972a253aSDimitry Andric uint32_t Characteristics = WeakExternal->Characteristics; 242*972a253aSDimitry Andric WeakExternalRequests.push_back( 243*972a253aSDimitry Andric {SymIndex, TagIndex, Characteristics, SymbolName}); 244753f127fSDimitry Andric } else { 245753f127fSDimitry Andric Expected<jitlink::Symbol *> NewGSym = 246753f127fSDimitry Andric createDefinedSymbol(SymIndex, SymbolName, *Sym, Sec); 247753f127fSDimitry Andric if (!NewGSym) 248753f127fSDimitry Andric return NewGSym.takeError(); 249753f127fSDimitry Andric GSym = *NewGSym; 250753f127fSDimitry Andric if (GSym) { 251753f127fSDimitry Andric LLVM_DEBUG({ 252753f127fSDimitry Andric dbgs() << " " << SymIndex 253753f127fSDimitry Andric << ": Creating defined graph symbol for COFF symbol \"" 254753f127fSDimitry Andric << SymbolName << "\" in " 255753f127fSDimitry Andric << getCOFFSectionName(SectionIndex, Sec, *Sym) 256753f127fSDimitry Andric << " (index: " << SectionIndex << ") \n"; 257753f127fSDimitry Andric dbgs() << " " << *GSym << "\n"; 258753f127fSDimitry Andric }); 259753f127fSDimitry Andric } 260753f127fSDimitry Andric } 261753f127fSDimitry Andric 262753f127fSDimitry Andric // Register the symbol 263753f127fSDimitry Andric if (GSym) 264753f127fSDimitry Andric setGraphSymbol(SectionIndex, SymIndex, *GSym); 265753f127fSDimitry Andric SymIndex += Sym->getNumberOfAuxSymbols(); 266753f127fSDimitry Andric } 267753f127fSDimitry Andric 268753f127fSDimitry Andric if (auto Err = flushWeakAliasRequests()) 269753f127fSDimitry Andric return Err; 270753f127fSDimitry Andric 271753f127fSDimitry Andric if (auto Err = calculateImplicitSizeOfSymbols()) 272753f127fSDimitry Andric return Err; 273753f127fSDimitry Andric 274753f127fSDimitry Andric return Error::success(); 275753f127fSDimitry Andric } 276753f127fSDimitry Andric 277753f127fSDimitry Andric Error COFFLinkGraphBuilder::flushWeakAliasRequests() { 278753f127fSDimitry Andric // Export the weak external symbols and alias it 279*972a253aSDimitry Andric for (auto &WeakExternal : WeakExternalRequests) { 280*972a253aSDimitry Andric if (auto *Target = getGraphSymbol(WeakExternal.Target)) { 281753f127fSDimitry Andric Expected<object::COFFSymbolRef> AliasSymbol = 282*972a253aSDimitry Andric Obj.getSymbol(WeakExternal.Alias); 283753f127fSDimitry Andric if (!AliasSymbol) 284753f127fSDimitry Andric return AliasSymbol.takeError(); 285753f127fSDimitry Andric 286*972a253aSDimitry Andric // FIXME: IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY and 287*972a253aSDimitry Andric // IMAGE_WEAK_EXTERN_SEARCH_LIBRARY are handled in the same way. 288*972a253aSDimitry Andric Scope S = 289*972a253aSDimitry Andric WeakExternal.Characteristics == COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS 290*972a253aSDimitry Andric ? Scope::Default 291*972a253aSDimitry Andric : Scope::Local; 292*972a253aSDimitry Andric 293753f127fSDimitry Andric // FIXME: Support this when there's a way to handle this. 294753f127fSDimitry Andric if (!Target->isDefined()) 295753f127fSDimitry Andric return make_error<JITLinkError>("Weak external symbol with external " 296753f127fSDimitry Andric "symbol as alternative not supported."); 297753f127fSDimitry Andric 298753f127fSDimitry Andric jitlink::Symbol *NewSymbol = &G->addDefinedSymbol( 299*972a253aSDimitry Andric Target->getBlock(), Target->getOffset(), WeakExternal.SymbolName, 300*972a253aSDimitry Andric Target->getSize(), Linkage::Weak, S, Target->isCallable(), false); 301*972a253aSDimitry Andric setGraphSymbol(AliasSymbol->getSectionNumber(), WeakExternal.Alias, 302753f127fSDimitry Andric *NewSymbol); 303753f127fSDimitry Andric LLVM_DEBUG({ 304*972a253aSDimitry Andric dbgs() << " " << WeakExternal.Alias 305753f127fSDimitry Andric << ": Creating weak external symbol for COFF symbol \"" 306*972a253aSDimitry Andric << WeakExternal.SymbolName << "\" in section " 307753f127fSDimitry Andric << AliasSymbol->getSectionNumber() << "\n"; 308753f127fSDimitry Andric dbgs() << " " << *NewSymbol << "\n"; 309753f127fSDimitry Andric }); 310753f127fSDimitry Andric } else 311753f127fSDimitry Andric return make_error<JITLinkError>("Weak symbol alias requested but actual " 312753f127fSDimitry Andric "symbol not found for symbol " + 313*972a253aSDimitry Andric formatv("{0:d}", WeakExternal.Alias)); 314753f127fSDimitry Andric } 315753f127fSDimitry Andric return Error::success(); 316753f127fSDimitry Andric } 317753f127fSDimitry Andric 318753f127fSDimitry Andric // In COFF, most of the defined symbols don't contain the size information. 319753f127fSDimitry Andric // Hence, we calculate the "implicit" size of symbol by taking the delta of 320753f127fSDimitry Andric // offsets of consecutive symbols within a block. We maintain a balanced tree 321753f127fSDimitry Andric // set of symbols sorted by offset per each block in order to achieve 322753f127fSDimitry Andric // logarithmic time complexity of sorted symbol insertion. Symbol is inserted to 323753f127fSDimitry Andric // the set once it's processed in graphifySymbols. In this function, we iterate 324753f127fSDimitry Andric // each collected symbol in sorted order and calculate the implicit size. 325753f127fSDimitry Andric Error COFFLinkGraphBuilder::calculateImplicitSizeOfSymbols() { 326753f127fSDimitry Andric for (COFFSectionIndex SecIndex = 1; 327753f127fSDimitry Andric SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections()); 328753f127fSDimitry Andric SecIndex++) { 329753f127fSDimitry Andric auto &SymbolSet = SymbolSets[SecIndex]; 330*972a253aSDimitry Andric if (SymbolSet.empty()) 331*972a253aSDimitry Andric continue; 332753f127fSDimitry Andric jitlink::Block *B = getGraphBlock(SecIndex); 333753f127fSDimitry Andric orc::ExecutorAddrDiff LastOffset = B->getSize(); 334753f127fSDimitry Andric orc::ExecutorAddrDiff LastDifferentOffset = B->getSize(); 335753f127fSDimitry Andric orc::ExecutorAddrDiff LastSize = 0; 336753f127fSDimitry Andric for (auto It = SymbolSet.rbegin(); It != SymbolSet.rend(); It++) { 337753f127fSDimitry Andric orc::ExecutorAddrDiff Offset = It->first; 338753f127fSDimitry Andric jitlink::Symbol *Symbol = It->second; 339753f127fSDimitry Andric orc::ExecutorAddrDiff CandSize; 340753f127fSDimitry Andric // Last offset can be same when aliasing happened 341753f127fSDimitry Andric if (Symbol->getOffset() == LastOffset) 342753f127fSDimitry Andric CandSize = LastSize; 343753f127fSDimitry Andric else 344753f127fSDimitry Andric CandSize = LastOffset - Offset; 345753f127fSDimitry Andric 346753f127fSDimitry Andric LLVM_DEBUG({ 347753f127fSDimitry Andric if (Offset + Symbol->getSize() > LastDifferentOffset) 348753f127fSDimitry Andric dbgs() << " Overlapping symbol range generated for the following " 349753f127fSDimitry Andric "symbol:" 350753f127fSDimitry Andric << "\n" 351753f127fSDimitry Andric << " " << *Symbol << "\n"; 352753f127fSDimitry Andric }); 353753f127fSDimitry Andric (void)LastDifferentOffset; 354753f127fSDimitry Andric if (LastOffset != Offset) 355753f127fSDimitry Andric LastDifferentOffset = Offset; 356753f127fSDimitry Andric LastSize = CandSize; 357753f127fSDimitry Andric LastOffset = Offset; 358753f127fSDimitry Andric if (Symbol->getSize()) { 359753f127fSDimitry Andric // Non empty symbol can happen in COMDAT symbol. 360753f127fSDimitry Andric // We don't consider the possibility of overlapping symbol range that 361753f127fSDimitry Andric // could be introduced by disparity between inferred symbol size and 362753f127fSDimitry Andric // defined symbol size because symbol size information is currently only 363753f127fSDimitry Andric // used by jitlink-check where we have control to not make overlapping 364753f127fSDimitry Andric // ranges. 365753f127fSDimitry Andric continue; 366753f127fSDimitry Andric } 367753f127fSDimitry Andric 368753f127fSDimitry Andric LLVM_DEBUG({ 369753f127fSDimitry Andric if (!CandSize) 370753f127fSDimitry Andric dbgs() << " Empty implicit symbol size generated for the following " 371753f127fSDimitry Andric "symbol:" 372753f127fSDimitry Andric << "\n" 373753f127fSDimitry Andric << " " << *Symbol << "\n"; 374753f127fSDimitry Andric }); 375753f127fSDimitry Andric 376753f127fSDimitry Andric Symbol->setSize(CandSize); 377753f127fSDimitry Andric } 378753f127fSDimitry Andric } 379753f127fSDimitry Andric return Error::success(); 380753f127fSDimitry Andric } 381753f127fSDimitry Andric 382753f127fSDimitry Andric Expected<Symbol *> COFFLinkGraphBuilder::createDefinedSymbol( 383753f127fSDimitry Andric COFFSymbolIndex SymIndex, StringRef SymbolName, 384753f127fSDimitry Andric object::COFFSymbolRef Symbol, const object::coff_section *Section) { 385753f127fSDimitry Andric if (Symbol.isCommon()) { 386753f127fSDimitry Andric // FIXME: correct alignment 387753f127fSDimitry Andric return &G->addCommonSymbol(SymbolName, Scope::Default, getCommonSection(), 388753f127fSDimitry Andric orc::ExecutorAddr(), Symbol.getValue(), 389753f127fSDimitry Andric Symbol.getValue(), false); 390753f127fSDimitry Andric } 391753f127fSDimitry Andric if (Symbol.isAbsolute()) 392753f127fSDimitry Andric return &G->addAbsoluteSymbol(SymbolName, 393753f127fSDimitry Andric orc::ExecutorAddr(Symbol.getValue()), 0, 394753f127fSDimitry Andric Linkage::Strong, Scope::Local, false); 395753f127fSDimitry Andric 396753f127fSDimitry Andric if (llvm::COFF::isReservedSectionNumber(Symbol.getSectionNumber())) 397753f127fSDimitry Andric return make_error<JITLinkError>( 398753f127fSDimitry Andric "Reserved section number used in regular symbol " + 399753f127fSDimitry Andric formatv("{0:d}", SymIndex)); 400753f127fSDimitry Andric 401753f127fSDimitry Andric Block *B = getGraphBlock(Symbol.getSectionNumber()); 402*972a253aSDimitry Andric if (!B) { 403*972a253aSDimitry Andric LLVM_DEBUG({ 404*972a253aSDimitry Andric dbgs() << " " << SymIndex 405*972a253aSDimitry Andric << ": Skipping graph symbol since section was not created for " 406*972a253aSDimitry Andric "COFF symbol \"" 407*972a253aSDimitry Andric << SymbolName << "\" in section " << Symbol.getSectionNumber() 408*972a253aSDimitry Andric << "\n"; 409*972a253aSDimitry Andric }); 410*972a253aSDimitry Andric return nullptr; 411*972a253aSDimitry Andric } 412*972a253aSDimitry Andric 413753f127fSDimitry Andric if (Symbol.isExternal()) { 414753f127fSDimitry Andric // This is not a comdat sequence, export the symbol as it is 415*972a253aSDimitry Andric if (!isComdatSection(Section)) { 416*972a253aSDimitry Andric 417753f127fSDimitry Andric return &G->addDefinedSymbol( 418753f127fSDimitry Andric *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Default, 419753f127fSDimitry Andric Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); 420*972a253aSDimitry Andric } else { 421*972a253aSDimitry Andric if (!PendingComdatExports[Symbol.getSectionNumber()]) 422753f127fSDimitry Andric return make_error<JITLinkError>("No pending COMDAT export for symbol " + 423753f127fSDimitry Andric formatv("{0:d}", SymIndex)); 424*972a253aSDimitry Andric 425753f127fSDimitry Andric return exportCOMDATSymbol(SymIndex, SymbolName, Symbol); 426753f127fSDimitry Andric } 427753f127fSDimitry Andric } 428753f127fSDimitry Andric 429*972a253aSDimitry Andric if (Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC || 430*972a253aSDimitry Andric Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_LABEL) { 431753f127fSDimitry Andric const object::coff_aux_section_definition *Definition = 432753f127fSDimitry Andric Symbol.getSectionDefinition(); 433753f127fSDimitry Andric if (!Definition || !isComdatSection(Section)) { 434753f127fSDimitry Andric // Handle typical static symbol 435753f127fSDimitry Andric return &G->addDefinedSymbol( 436753f127fSDimitry Andric *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local, 437753f127fSDimitry Andric Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); 438753f127fSDimitry Andric } 439753f127fSDimitry Andric if (Definition->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { 440*972a253aSDimitry Andric auto Target = Definition->getNumber(Symbol.isBigObj()); 441*972a253aSDimitry Andric auto GSym = &G->addDefinedSymbol( 442753f127fSDimitry Andric *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local, 443753f127fSDimitry Andric Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); 444*972a253aSDimitry Andric getGraphBlock(Target)->addEdge(Edge::KeepAlive, 0, *GSym, 0); 445*972a253aSDimitry Andric return GSym; 446753f127fSDimitry Andric } 447*972a253aSDimitry Andric if (PendingComdatExports[Symbol.getSectionNumber()]) 448753f127fSDimitry Andric return make_error<JITLinkError>( 449753f127fSDimitry Andric "COMDAT export request already exists before symbol " + 450753f127fSDimitry Andric formatv("{0:d}", SymIndex)); 451753f127fSDimitry Andric return createCOMDATExportRequest(SymIndex, Symbol, Definition); 452753f127fSDimitry Andric } 453753f127fSDimitry Andric return make_error<JITLinkError>("Unsupported storage class " + 454753f127fSDimitry Andric formatv("{0:d}", Symbol.getStorageClass()) + 455753f127fSDimitry Andric " in symbol " + formatv("{0:d}", SymIndex)); 456753f127fSDimitry Andric } 457753f127fSDimitry Andric 458753f127fSDimitry Andric // COMDAT handling: 459753f127fSDimitry Andric // When IMAGE_SCN_LNK_COMDAT flag is set in the flags of a section, 460753f127fSDimitry Andric // the section is called a COMDAT section. It contains two symbols 461753f127fSDimitry Andric // in a sequence that specifes the behavior. First symbol is the section 462753f127fSDimitry Andric // symbol which contains the size and name of the section. It also contains 463753f127fSDimitry Andric // selection type that specifies how duplicate of the symbol is handled. 464753f127fSDimitry Andric // Second symbol is COMDAT symbol which usually defines the external name and 465753f127fSDimitry Andric // data type. 466753f127fSDimitry Andric // 467753f127fSDimitry Andric // Since two symbols always come in a specific order, we initiate pending COMDAT 468753f127fSDimitry Andric // export request when we encounter the first symbol and actually exports it 469753f127fSDimitry Andric // when we process the second symbol. 470753f127fSDimitry Andric // 471753f127fSDimitry Andric // Process the first symbol of COMDAT sequence. 472753f127fSDimitry Andric Expected<Symbol *> COFFLinkGraphBuilder::createCOMDATExportRequest( 473753f127fSDimitry Andric COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol, 474753f127fSDimitry Andric const object::coff_aux_section_definition *Definition) { 475753f127fSDimitry Andric Block *B = getGraphBlock(Symbol.getSectionNumber()); 476753f127fSDimitry Andric Linkage L = Linkage::Strong; 477753f127fSDimitry Andric switch (Definition->Selection) { 478753f127fSDimitry Andric case COFF::IMAGE_COMDAT_SELECT_NODUPLICATES: { 479753f127fSDimitry Andric L = Linkage::Strong; 480753f127fSDimitry Andric break; 481753f127fSDimitry Andric } 482753f127fSDimitry Andric case COFF::IMAGE_COMDAT_SELECT_ANY: { 483753f127fSDimitry Andric L = Linkage::Weak; 484753f127fSDimitry Andric break; 485753f127fSDimitry Andric } 486753f127fSDimitry Andric case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH: 487753f127fSDimitry Andric case COFF::IMAGE_COMDAT_SELECT_SAME_SIZE: { 488753f127fSDimitry Andric // FIXME: Implement size/content validation when LinkGraph is able to 489753f127fSDimitry Andric // handle this. 490753f127fSDimitry Andric L = Linkage::Weak; 491753f127fSDimitry Andric break; 492753f127fSDimitry Andric } 493753f127fSDimitry Andric case COFF::IMAGE_COMDAT_SELECT_LARGEST: { 494*972a253aSDimitry Andric // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST properly when LinkGraph is 495*972a253aSDimitry Andric // able to handle this. 496*972a253aSDimitry Andric LLVM_DEBUG({ 497*972a253aSDimitry Andric dbgs() << " " << SymIndex 498*972a253aSDimitry Andric << ": Partially supported IMAGE_COMDAT_SELECT_LARGEST was used" 499*972a253aSDimitry Andric " in section " 500*972a253aSDimitry Andric << Symbol.getSectionNumber() << "\n"; 501*972a253aSDimitry Andric }); 502*972a253aSDimitry Andric L = Linkage::Weak; 503*972a253aSDimitry Andric break; 504753f127fSDimitry Andric } 505753f127fSDimitry Andric case COFF::IMAGE_COMDAT_SELECT_NEWEST: { 506753f127fSDimitry Andric // Even link.exe doesn't support this selection properly. 507753f127fSDimitry Andric return make_error<JITLinkError>( 508753f127fSDimitry Andric "IMAGE_COMDAT_SELECT_NEWEST is not supported."); 509753f127fSDimitry Andric } 510753f127fSDimitry Andric default: { 511753f127fSDimitry Andric return make_error<JITLinkError>("Invalid comdat selection type: " + 512753f127fSDimitry Andric formatv("{0:d}", Definition->Selection)); 513753f127fSDimitry Andric } 514753f127fSDimitry Andric } 515*972a253aSDimitry Andric PendingComdatExports[Symbol.getSectionNumber()] = {SymIndex, L}; 516753f127fSDimitry Andric return &G->addAnonymousSymbol(*B, Symbol.getValue(), Definition->Length, 517753f127fSDimitry Andric false, false); 518753f127fSDimitry Andric } 519753f127fSDimitry Andric 520753f127fSDimitry Andric // Process the second symbol of COMDAT sequence. 521753f127fSDimitry Andric Expected<Symbol *> 522753f127fSDimitry Andric COFFLinkGraphBuilder::exportCOMDATSymbol(COFFSymbolIndex SymIndex, 523753f127fSDimitry Andric StringRef SymbolName, 524753f127fSDimitry Andric object::COFFSymbolRef Symbol) { 525*972a253aSDimitry Andric auto &PendingComdatExport = PendingComdatExports[Symbol.getSectionNumber()]; 526753f127fSDimitry Andric COFFSymbolIndex TargetIndex = PendingComdatExport->SymbolIndex; 527753f127fSDimitry Andric Linkage L = PendingComdatExport->Linkage; 528753f127fSDimitry Andric jitlink::Symbol *Target = getGraphSymbol(TargetIndex); 529753f127fSDimitry Andric assert(Target && "COMDAT leaader is invalid."); 530753f127fSDimitry Andric assert((llvm::count_if(G->defined_symbols(), 531753f127fSDimitry Andric [&](const jitlink::Symbol *Sym) { 532753f127fSDimitry Andric return Sym->getName() == SymbolName; 533753f127fSDimitry Andric }) == 0) && 534753f127fSDimitry Andric "Duplicate defined symbol"); 535753f127fSDimitry Andric Target->setName(SymbolName); 536753f127fSDimitry Andric Target->setLinkage(L); 537753f127fSDimitry Andric Target->setCallable(Symbol.getComplexType() == 538753f127fSDimitry Andric COFF::IMAGE_SYM_DTYPE_FUNCTION); 539753f127fSDimitry Andric Target->setScope(Scope::Default); 540753f127fSDimitry Andric LLVM_DEBUG({ 541753f127fSDimitry Andric dbgs() << " " << SymIndex 542753f127fSDimitry Andric << ": Exporting COMDAT graph symbol for COFF symbol \"" << SymbolName 543753f127fSDimitry Andric << "\" in section " << Symbol.getSectionNumber() << "\n"; 544753f127fSDimitry Andric dbgs() << " " << *Target << "\n"; 545753f127fSDimitry Andric }); 546753f127fSDimitry Andric PendingComdatExport = None; 547753f127fSDimitry Andric return Target; 548753f127fSDimitry Andric } 549753f127fSDimitry Andric 550753f127fSDimitry Andric } // namespace jitlink 551753f127fSDimitry Andric } // namespace llvm 552