1 //=--------- COFFLinkGraphBuilder.cpp - COFF LinkGraph builder ----------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Generic COFF LinkGraph buliding code. 10 // 11 //===----------------------------------------------------------------------===// 12 #include "COFFLinkGraphBuilder.h" 13 14 #define DEBUG_TYPE "jitlink" 15 16 static const char *CommonSectionName = "__common"; 17 18 namespace llvm { 19 namespace jitlink { 20 21 static Triple createTripleWithCOFFFormat(Triple T) { 22 T.setObjectFormat(Triple::COFF); 23 return T; 24 } 25 26 COFFLinkGraphBuilder::COFFLinkGraphBuilder( 27 const object::COFFObjectFile &Obj, Triple TT, SubtargetFeatures Features, 28 LinkGraph::GetEdgeKindNameFunction GetEdgeKindName) 29 : Obj(Obj), G(std::make_unique<LinkGraph>( 30 Obj.getFileName().str(), createTripleWithCOFFFormat(TT), 31 std::move(Features), getPointerSize(Obj), 32 getEndianness(Obj), std::move(GetEdgeKindName))) { 33 LLVM_DEBUG({ 34 dbgs() << "Created COFFLinkGraphBuilder for \"" << Obj.getFileName() 35 << "\"\n"; 36 }); 37 } 38 39 COFFLinkGraphBuilder::~COFFLinkGraphBuilder() = default; 40 41 unsigned 42 COFFLinkGraphBuilder::getPointerSize(const object::COFFObjectFile &Obj) { 43 return Obj.getBytesInAddress(); 44 } 45 46 support::endianness 47 COFFLinkGraphBuilder::getEndianness(const object::COFFObjectFile &Obj) { 48 return Obj.isLittleEndian() ? support::little : support::big; 49 } 50 51 uint64_t COFFLinkGraphBuilder::getSectionSize(const object::COFFObjectFile &Obj, 52 const object::coff_section *Sec) { 53 // Consider the difference between executable form and object form. 54 // More information is inside COFFObjectFile::getSectionSize 55 if (Obj.getDOSHeader()) 56 return std::min(Sec->VirtualSize, Sec->SizeOfRawData); 57 return Sec->SizeOfRawData; 58 } 59 60 uint64_t 61 COFFLinkGraphBuilder::getSectionAddress(const object::COFFObjectFile &Obj, 62 const object::coff_section *Section) { 63 return Section->VirtualAddress + Obj.getImageBase(); 64 } 65 66 bool COFFLinkGraphBuilder::isComdatSection( 67 const object::coff_section *Section) { 68 return Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT; 69 } 70 71 Section &COFFLinkGraphBuilder::getCommonSection() { 72 if (!CommonSection) 73 CommonSection = &G->createSection(CommonSectionName, 74 orc::MemProt::Read | orc::MemProt::Write); 75 return *CommonSection; 76 } 77 78 Expected<std::unique_ptr<LinkGraph>> COFFLinkGraphBuilder::buildGraph() { 79 if (!Obj.isRelocatableObject()) 80 return make_error<JITLinkError>("Object is not a relocatable COFF file"); 81 82 if (auto Err = graphifySections()) 83 return std::move(Err); 84 85 if (auto Err = graphifySymbols()) 86 return std::move(Err); 87 88 if (auto Err = addRelocations()) 89 return std::move(Err); 90 91 return std::move(G); 92 } 93 94 StringRef 95 COFFLinkGraphBuilder::getCOFFSectionName(COFFSectionIndex SectionIndex, 96 const object::coff_section *Sec, 97 object::COFFSymbolRef Sym) { 98 switch (SectionIndex) { 99 case COFF::IMAGE_SYM_UNDEFINED: { 100 if (Sym.getValue()) 101 return "(common)"; 102 else 103 return "(external)"; 104 } 105 case COFF::IMAGE_SYM_ABSOLUTE: 106 return "(absolute)"; 107 case COFF::IMAGE_SYM_DEBUG: { 108 // Used with .file symbol 109 return "(debug)"; 110 } 111 default: { 112 // Non reserved regular section numbers 113 if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(Sec)) 114 return *SecNameOrErr; 115 } 116 } 117 return ""; 118 } 119 120 Error COFFLinkGraphBuilder::graphifySections() { 121 LLVM_DEBUG(dbgs() << " Creating graph sections...\n"); 122 123 GraphBlocks.resize(Obj.getNumberOfSections() + 1); 124 // For each section... 125 for (COFFSectionIndex SecIndex = 1; 126 SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections()); 127 SecIndex++) { 128 Expected<const object::coff_section *> Sec = Obj.getSection(SecIndex); 129 if (!Sec) 130 return Sec.takeError(); 131 132 StringRef SectionName; 133 if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(*Sec)) 134 SectionName = *SecNameOrErr; 135 136 // FIXME: Skip debug info sections 137 if (SectionName == ".voltbl") { 138 LLVM_DEBUG({ 139 dbgs() << " " 140 << "Skipping section \"" << SectionName << "\"\n"; 141 }); 142 continue; 143 } 144 145 LLVM_DEBUG({ 146 dbgs() << " " 147 << "Creating section for \"" << SectionName << "\"\n"; 148 }); 149 150 // Get the section's memory protection flags. 151 orc::MemProt Prot = orc::MemProt::Read; 152 if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE) 153 Prot |= orc::MemProt::Exec; 154 if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_READ) 155 Prot |= orc::MemProt::Read; 156 if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_WRITE) 157 Prot |= orc::MemProt::Write; 158 159 // Look for existing sections first. 160 auto *GraphSec = G->findSectionByName(SectionName); 161 if (!GraphSec) { 162 GraphSec = &G->createSection(SectionName, Prot); 163 if ((*Sec)->Characteristics & COFF::IMAGE_SCN_LNK_REMOVE) 164 GraphSec->setMemLifetimePolicy(orc::MemLifetimePolicy::NoAlloc); 165 } 166 if (GraphSec->getMemProt() != Prot) 167 return make_error<JITLinkError>("MemProt should match"); 168 169 Block *B = nullptr; 170 if ((*Sec)->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) 171 B = &G->createZeroFillBlock( 172 *GraphSec, getSectionSize(Obj, *Sec), 173 orc::ExecutorAddr(getSectionAddress(Obj, *Sec)), 174 (*Sec)->getAlignment(), 0); 175 else { 176 ArrayRef<uint8_t> Data; 177 if (auto Err = Obj.getSectionContents(*Sec, Data)) 178 return Err; 179 180 auto CharData = ArrayRef<char>( 181 reinterpret_cast<const char *>(Data.data()), Data.size()); 182 183 if (SectionName == getDirectiveSectionName()) 184 if (auto Err = handleDirectiveSection( 185 StringRef(CharData.data(), CharData.size()))) 186 return Err; 187 188 B = &G->createContentBlock( 189 *GraphSec, CharData, orc::ExecutorAddr(getSectionAddress(Obj, *Sec)), 190 (*Sec)->getAlignment(), 0); 191 } 192 193 setGraphBlock(SecIndex, B); 194 } 195 196 return Error::success(); 197 } 198 199 Error COFFLinkGraphBuilder::graphifySymbols() { 200 LLVM_DEBUG(dbgs() << " Creating graph symbols...\n"); 201 202 SymbolSets.resize(Obj.getNumberOfSections() + 1); 203 PendingComdatExports.resize(Obj.getNumberOfSections() + 1); 204 GraphSymbols.resize(Obj.getNumberOfSymbols()); 205 206 for (COFFSymbolIndex SymIndex = 0; 207 SymIndex < static_cast<COFFSymbolIndex>(Obj.getNumberOfSymbols()); 208 SymIndex++) { 209 Expected<object::COFFSymbolRef> Sym = Obj.getSymbol(SymIndex); 210 if (!Sym) 211 return Sym.takeError(); 212 213 StringRef SymbolName; 214 if (Expected<StringRef> SymNameOrErr = Obj.getSymbolName(*Sym)) 215 SymbolName = *SymNameOrErr; 216 217 COFFSectionIndex SectionIndex = Sym->getSectionNumber(); 218 const object::coff_section *Sec = nullptr; 219 220 if (!COFF::isReservedSectionNumber(SectionIndex)) { 221 auto SecOrErr = Obj.getSection(SectionIndex); 222 if (!SecOrErr) 223 return make_error<JITLinkError>( 224 "Invalid COFF section number:" + formatv("{0:d}: ", SectionIndex) + 225 " (" + toString(SecOrErr.takeError()) + ")"); 226 Sec = *SecOrErr; 227 } 228 229 // Create jitlink symbol 230 jitlink::Symbol *GSym = nullptr; 231 if (Sym->isFileRecord()) 232 LLVM_DEBUG({ 233 dbgs() << " " << SymIndex << ": Skipping FileRecord symbol \"" 234 << SymbolName << "\" in " 235 << getCOFFSectionName(SectionIndex, Sec, *Sym) 236 << " (index: " << SectionIndex << ") \n"; 237 }); 238 else if (Sym->isUndefined()) { 239 GSym = createExternalSymbol(SymIndex, SymbolName, *Sym, Sec); 240 } else if (Sym->isWeakExternal()) { 241 auto *WeakExternal = Sym->getAux<object::coff_aux_weak_external>(); 242 COFFSymbolIndex TagIndex = WeakExternal->TagIndex; 243 uint32_t Characteristics = WeakExternal->Characteristics; 244 WeakExternalRequests.push_back( 245 {SymIndex, TagIndex, Characteristics, SymbolName}); 246 } else { 247 Expected<jitlink::Symbol *> NewGSym = 248 createDefinedSymbol(SymIndex, SymbolName, *Sym, Sec); 249 if (!NewGSym) 250 return NewGSym.takeError(); 251 GSym = *NewGSym; 252 if (GSym) { 253 LLVM_DEBUG({ 254 dbgs() << " " << SymIndex 255 << ": Creating defined graph symbol for COFF symbol \"" 256 << SymbolName << "\" in " 257 << getCOFFSectionName(SectionIndex, Sec, *Sym) 258 << " (index: " << SectionIndex << ") \n"; 259 dbgs() << " " << *GSym << "\n"; 260 }); 261 } 262 } 263 264 // Register the symbol 265 if (GSym) 266 setGraphSymbol(SectionIndex, SymIndex, *GSym); 267 SymIndex += Sym->getNumberOfAuxSymbols(); 268 } 269 270 if (auto Err = flushWeakAliasRequests()) 271 return Err; 272 273 if (auto Err = handleAlternateNames()) 274 return Err; 275 276 if (auto Err = calculateImplicitSizeOfSymbols()) 277 return Err; 278 279 return Error::success(); 280 } 281 282 Error COFFLinkGraphBuilder::handleDirectiveSection(StringRef Str) { 283 auto Parsed = DirectiveParser.parse(Str); 284 if (!Parsed) 285 return Parsed.takeError(); 286 for (auto *Arg : *Parsed) { 287 StringRef S = Arg->getValue(); 288 switch (Arg->getOption().getID()) { 289 case COFF_OPT_alternatename: { 290 StringRef From, To; 291 std::tie(From, To) = S.split('='); 292 if (From.empty() || To.empty()) 293 return make_error<JITLinkError>( 294 "Invalid COFF /alternatename directive"); 295 AlternateNames[From] = To; 296 break; 297 } 298 case COFF_OPT_incl: { 299 auto DataCopy = G->allocateContent(S); 300 StringRef StrCopy(DataCopy.data(), DataCopy.size()); 301 ExternalSymbols[StrCopy] = &G->addExternalSymbol(StrCopy, 0, false); 302 ExternalSymbols[StrCopy]->setLive(true); 303 break; 304 } 305 case COFF_OPT_export: 306 break; 307 default: { 308 LLVM_DEBUG({ 309 dbgs() << "Unknown coff directive: " << Arg->getSpelling() << "\n"; 310 }); 311 break; 312 } 313 } 314 } 315 return Error::success(); 316 } 317 318 Error COFFLinkGraphBuilder::flushWeakAliasRequests() { 319 // Export the weak external symbols and alias it 320 for (auto &WeakExternal : WeakExternalRequests) { 321 if (auto *Target = getGraphSymbol(WeakExternal.Target)) { 322 Expected<object::COFFSymbolRef> AliasSymbol = 323 Obj.getSymbol(WeakExternal.Alias); 324 if (!AliasSymbol) 325 return AliasSymbol.takeError(); 326 327 // FIXME: IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY and 328 // IMAGE_WEAK_EXTERN_SEARCH_LIBRARY are handled in the same way. 329 Scope S = 330 WeakExternal.Characteristics == COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS 331 ? Scope::Default 332 : Scope::Local; 333 334 auto NewSymbol = 335 createAliasSymbol(WeakExternal.SymbolName, Linkage::Weak, S, *Target); 336 if (!NewSymbol) 337 return NewSymbol.takeError(); 338 setGraphSymbol(AliasSymbol->getSectionNumber(), WeakExternal.Alias, 339 **NewSymbol); 340 LLVM_DEBUG({ 341 dbgs() << " " << WeakExternal.Alias 342 << ": Creating weak external symbol for COFF symbol \"" 343 << WeakExternal.SymbolName << "\" in section " 344 << AliasSymbol->getSectionNumber() << "\n"; 345 dbgs() << " " << **NewSymbol << "\n"; 346 }); 347 } else 348 return make_error<JITLinkError>("Weak symbol alias requested but actual " 349 "symbol not found for symbol " + 350 formatv("{0:d}", WeakExternal.Alias)); 351 } 352 return Error::success(); 353 } 354 355 Error COFFLinkGraphBuilder::handleAlternateNames() { 356 for (auto &KeyValue : AlternateNames) 357 if (DefinedSymbols.count(KeyValue.second) && 358 ExternalSymbols.count(KeyValue.first)) { 359 auto *Target = DefinedSymbols[KeyValue.second]; 360 auto *Alias = ExternalSymbols[KeyValue.first]; 361 G->makeDefined(*Alias, Target->getBlock(), Target->getOffset(), 362 Target->getSize(), Linkage::Weak, Scope::Local, false); 363 } 364 return Error::success(); 365 } 366 367 Symbol *COFFLinkGraphBuilder::createExternalSymbol( 368 COFFSymbolIndex SymIndex, StringRef SymbolName, 369 object::COFFSymbolRef Symbol, const object::coff_section *Section) { 370 if (!ExternalSymbols.count(SymbolName)) 371 ExternalSymbols[SymbolName] = 372 &G->addExternalSymbol(SymbolName, Symbol.getValue(), false); 373 374 LLVM_DEBUG({ 375 dbgs() << " " << SymIndex 376 << ": Creating external graph symbol for COFF symbol \"" 377 << SymbolName << "\" in " 378 << getCOFFSectionName(Symbol.getSectionNumber(), Section, Symbol) 379 << " (index: " << Symbol.getSectionNumber() << ") \n"; 380 }); 381 return ExternalSymbols[SymbolName]; 382 } 383 384 Expected<Symbol *> COFFLinkGraphBuilder::createAliasSymbol(StringRef SymbolName, 385 Linkage L, Scope S, 386 Symbol &Target) { 387 if (!Target.isDefined()) { 388 // FIXME: Support this when there's a way to handle this. 389 return make_error<JITLinkError>("Weak external symbol with external " 390 "symbol as alternative not supported."); 391 } 392 return &G->addDefinedSymbol(Target.getBlock(), Target.getOffset(), SymbolName, 393 Target.getSize(), L, S, Target.isCallable(), 394 false); 395 } 396 397 // In COFF, most of the defined symbols don't contain the size information. 398 // Hence, we calculate the "implicit" size of symbol by taking the delta of 399 // offsets of consecutive symbols within a block. We maintain a balanced tree 400 // set of symbols sorted by offset per each block in order to achieve 401 // logarithmic time complexity of sorted symbol insertion. Symbol is inserted to 402 // the set once it's processed in graphifySymbols. In this function, we iterate 403 // each collected symbol in sorted order and calculate the implicit size. 404 Error COFFLinkGraphBuilder::calculateImplicitSizeOfSymbols() { 405 for (COFFSectionIndex SecIndex = 1; 406 SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections()); 407 SecIndex++) { 408 auto &SymbolSet = SymbolSets[SecIndex]; 409 if (SymbolSet.empty()) 410 continue; 411 jitlink::Block *B = getGraphBlock(SecIndex); 412 orc::ExecutorAddrDiff LastOffset = B->getSize(); 413 orc::ExecutorAddrDiff LastDifferentOffset = B->getSize(); 414 orc::ExecutorAddrDiff LastSize = 0; 415 for (auto It = SymbolSet.rbegin(); It != SymbolSet.rend(); It++) { 416 orc::ExecutorAddrDiff Offset = It->first; 417 jitlink::Symbol *Symbol = It->second; 418 orc::ExecutorAddrDiff CandSize; 419 // Last offset can be same when aliasing happened 420 if (Symbol->getOffset() == LastOffset) 421 CandSize = LastSize; 422 else 423 CandSize = LastOffset - Offset; 424 425 LLVM_DEBUG({ 426 if (Offset + Symbol->getSize() > LastDifferentOffset) 427 dbgs() << " Overlapping symbol range generated for the following " 428 "symbol:" 429 << "\n" 430 << " " << *Symbol << "\n"; 431 }); 432 (void)LastDifferentOffset; 433 if (LastOffset != Offset) 434 LastDifferentOffset = Offset; 435 LastSize = CandSize; 436 LastOffset = Offset; 437 if (Symbol->getSize()) { 438 // Non empty symbol can happen in COMDAT symbol. 439 // We don't consider the possibility of overlapping symbol range that 440 // could be introduced by disparity between inferred symbol size and 441 // defined symbol size because symbol size information is currently only 442 // used by jitlink-check where we have control to not make overlapping 443 // ranges. 444 continue; 445 } 446 447 LLVM_DEBUG({ 448 if (!CandSize) 449 dbgs() << " Empty implicit symbol size generated for the following " 450 "symbol:" 451 << "\n" 452 << " " << *Symbol << "\n"; 453 }); 454 455 Symbol->setSize(CandSize); 456 } 457 } 458 return Error::success(); 459 } 460 461 Expected<Symbol *> COFFLinkGraphBuilder::createDefinedSymbol( 462 COFFSymbolIndex SymIndex, StringRef SymbolName, 463 object::COFFSymbolRef Symbol, const object::coff_section *Section) { 464 if (Symbol.isCommon()) { 465 // FIXME: correct alignment 466 return &G->addDefinedSymbol( 467 G->createZeroFillBlock(getCommonSection(), Symbol.getValue(), 468 orc::ExecutorAddr(), Symbol.getValue(), 0), 469 0, SymbolName, Symbol.getValue(), Linkage::Strong, Scope::Default, 470 false, false); 471 } 472 if (Symbol.isAbsolute()) 473 return &G->addAbsoluteSymbol(SymbolName, 474 orc::ExecutorAddr(Symbol.getValue()), 0, 475 Linkage::Strong, Scope::Local, false); 476 477 if (llvm::COFF::isReservedSectionNumber(Symbol.getSectionNumber())) 478 return make_error<JITLinkError>( 479 "Reserved section number used in regular symbol " + 480 formatv("{0:d}", SymIndex)); 481 482 Block *B = getGraphBlock(Symbol.getSectionNumber()); 483 if (!B) { 484 LLVM_DEBUG({ 485 dbgs() << " " << SymIndex 486 << ": Skipping graph symbol since section was not created for " 487 "COFF symbol \"" 488 << SymbolName << "\" in section " << Symbol.getSectionNumber() 489 << "\n"; 490 }); 491 return nullptr; 492 } 493 494 if (Symbol.isExternal()) { 495 // This is not a comdat sequence, export the symbol as it is 496 if (!isComdatSection(Section)) { 497 auto GSym = &G->addDefinedSymbol( 498 *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Default, 499 Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); 500 DefinedSymbols[SymbolName] = GSym; 501 return GSym; 502 } else { 503 if (!PendingComdatExports[Symbol.getSectionNumber()]) 504 return make_error<JITLinkError>("No pending COMDAT export for symbol " + 505 formatv("{0:d}", SymIndex)); 506 507 return exportCOMDATSymbol(SymIndex, SymbolName, Symbol); 508 } 509 } 510 511 if (Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC || 512 Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_LABEL) { 513 const object::coff_aux_section_definition *Definition = 514 Symbol.getSectionDefinition(); 515 if (!Definition || !isComdatSection(Section)) { 516 // Handle typical static symbol 517 return &G->addDefinedSymbol( 518 *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local, 519 Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); 520 } 521 if (Definition->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { 522 auto Target = Definition->getNumber(Symbol.isBigObj()); 523 auto GSym = &G->addDefinedSymbol( 524 *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local, 525 Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); 526 getGraphBlock(Target)->addEdge(Edge::KeepAlive, 0, *GSym, 0); 527 return GSym; 528 } 529 if (PendingComdatExports[Symbol.getSectionNumber()]) 530 return make_error<JITLinkError>( 531 "COMDAT export request already exists before symbol " + 532 formatv("{0:d}", SymIndex)); 533 return createCOMDATExportRequest(SymIndex, Symbol, Definition); 534 } 535 return make_error<JITLinkError>("Unsupported storage class " + 536 formatv("{0:d}", Symbol.getStorageClass()) + 537 " in symbol " + formatv("{0:d}", SymIndex)); 538 } 539 540 // COMDAT handling: 541 // When IMAGE_SCN_LNK_COMDAT flag is set in the flags of a section, 542 // the section is called a COMDAT section. It contains two symbols 543 // in a sequence that specifes the behavior. First symbol is the section 544 // symbol which contains the size and name of the section. It also contains 545 // selection type that specifies how duplicate of the symbol is handled. 546 // Second symbol is COMDAT symbol which usually defines the external name and 547 // data type. 548 // 549 // Since two symbols always come in a specific order, we initiate pending COMDAT 550 // export request when we encounter the first symbol and actually exports it 551 // when we process the second symbol. 552 // 553 // Process the first symbol of COMDAT sequence. 554 Expected<Symbol *> COFFLinkGraphBuilder::createCOMDATExportRequest( 555 COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol, 556 const object::coff_aux_section_definition *Definition) { 557 Linkage L = Linkage::Strong; 558 switch (Definition->Selection) { 559 case COFF::IMAGE_COMDAT_SELECT_NODUPLICATES: { 560 L = Linkage::Strong; 561 break; 562 } 563 case COFF::IMAGE_COMDAT_SELECT_ANY: { 564 L = Linkage::Weak; 565 break; 566 } 567 case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH: 568 case COFF::IMAGE_COMDAT_SELECT_SAME_SIZE: { 569 // FIXME: Implement size/content validation when LinkGraph is able to 570 // handle this. 571 L = Linkage::Weak; 572 break; 573 } 574 case COFF::IMAGE_COMDAT_SELECT_LARGEST: { 575 // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST properly when LinkGraph is 576 // able to handle this. 577 LLVM_DEBUG({ 578 dbgs() << " " << SymIndex 579 << ": Partially supported IMAGE_COMDAT_SELECT_LARGEST was used" 580 " in section " 581 << Symbol.getSectionNumber() << " (size: " << Definition->Length 582 << ")\n"; 583 }); 584 L = Linkage::Weak; 585 break; 586 } 587 case COFF::IMAGE_COMDAT_SELECT_NEWEST: { 588 // Even link.exe doesn't support this selection properly. 589 return make_error<JITLinkError>( 590 "IMAGE_COMDAT_SELECT_NEWEST is not supported."); 591 } 592 default: { 593 return make_error<JITLinkError>("Invalid comdat selection type: " + 594 formatv("{0:d}", Definition->Selection)); 595 } 596 } 597 PendingComdatExports[Symbol.getSectionNumber()] = {SymIndex, L, 598 Definition->Length}; 599 return nullptr; 600 } 601 602 // Process the second symbol of COMDAT sequence. 603 Expected<Symbol *> 604 COFFLinkGraphBuilder::exportCOMDATSymbol(COFFSymbolIndex SymIndex, 605 StringRef SymbolName, 606 object::COFFSymbolRef Symbol) { 607 Block *B = getGraphBlock(Symbol.getSectionNumber()); 608 auto &PendingComdatExport = PendingComdatExports[Symbol.getSectionNumber()]; 609 // NOTE: ComdatDef->Legnth is the size of "section" not size of symbol. 610 // We use zero symbol size to not reach out of bound of block when symbol 611 // offset is non-zero. 612 auto GSym = &G->addDefinedSymbol( 613 *B, Symbol.getValue(), SymbolName, 0, PendingComdatExport->Linkage, 614 Scope::Default, Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, 615 false); 616 LLVM_DEBUG({ 617 dbgs() << " " << SymIndex 618 << ": Exporting COMDAT graph symbol for COFF symbol \"" << SymbolName 619 << "\" in section " << Symbol.getSectionNumber() << "\n"; 620 dbgs() << " " << *GSym << "\n"; 621 }); 622 setGraphSymbol(Symbol.getSectionNumber(), PendingComdatExport->SymbolIndex, 623 *GSym); 624 DefinedSymbols[SymbolName] = GSym; 625 PendingComdatExport = std::nullopt; 626 return GSym; 627 } 628 629 } // namespace jitlink 630 } // namespace llvm 631