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