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