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 COFFLinkGraphBuilder::COFFLinkGraphBuilder( 22 const object::COFFObjectFile &Obj, Triple TT, 23 LinkGraph::GetEdgeKindNameFunction GetEdgeKindName) 24 : G(std::make_unique<LinkGraph>( 25 Obj.getFileName().str(), Triple(std::move(TT)), getPointerSize(Obj), 26 getEndianness(Obj), std::move(GetEdgeKindName))), 27 Obj(Obj) { 28 LLVM_DEBUG({ 29 dbgs() << "Created COFFLinkGraphBuilder for \"" << Obj.getFileName() 30 << "\"\n"; 31 }); 32 } 33 34 COFFLinkGraphBuilder::~COFFLinkGraphBuilder() = default; 35 36 unsigned 37 COFFLinkGraphBuilder::getPointerSize(const object::COFFObjectFile &Obj) { 38 return Obj.getBytesInAddress(); 39 } 40 41 support::endianness 42 COFFLinkGraphBuilder::getEndianness(const object::COFFObjectFile &Obj) { 43 return Obj.isLittleEndian() ? support::little : support::big; 44 } 45 46 uint64_t COFFLinkGraphBuilder::getSectionSize(const object::COFFObjectFile &Obj, 47 const object::coff_section *Sec) { 48 // Consider the difference between executable form and object form. 49 // More information is inside COFFObjectFile::getSectionSize 50 if (Obj.getDOSHeader()) 51 return std::min(Sec->VirtualSize, Sec->SizeOfRawData); 52 return Sec->SizeOfRawData; 53 } 54 55 uint64_t 56 COFFLinkGraphBuilder::getSectionAddress(const object::COFFObjectFile &Obj, 57 const object::coff_section *Section) { 58 return Section->VirtualAddress + Obj.getImageBase(); 59 } 60 61 bool COFFLinkGraphBuilder::isComdatSection( 62 const object::coff_section *Section) { 63 return Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT; 64 } 65 66 Section &COFFLinkGraphBuilder::getCommonSection() { 67 if (!CommonSection) 68 CommonSection = 69 &G->createSection(CommonSectionName, MemProt::Read | MemProt::Write); 70 return *CommonSection; 71 } 72 73 Expected<std::unique_ptr<LinkGraph>> COFFLinkGraphBuilder::buildGraph() { 74 if (!Obj.isRelocatableObject()) 75 return make_error<JITLinkError>("Object is not a relocatable COFF file"); 76 77 if (auto Err = graphifySections()) 78 return std::move(Err); 79 80 if (auto Err = graphifySymbols()) 81 return std::move(Err); 82 83 if (auto Err = addRelocations()) 84 return std::move(Err); 85 86 return std::move(G); 87 } 88 89 StringRef 90 COFFLinkGraphBuilder::getCOFFSectionName(COFFSectionIndex SectionIndex, 91 const object::coff_section *Sec, 92 object::COFFSymbolRef Sym) { 93 switch (SectionIndex) { 94 case COFF::IMAGE_SYM_UNDEFINED: { 95 if (Sym.getValue()) 96 return "(common)"; 97 else 98 return "(external)"; 99 } 100 case COFF::IMAGE_SYM_ABSOLUTE: 101 return "(absolute)"; 102 case COFF::IMAGE_SYM_DEBUG: { 103 // Used with .file symbol 104 return "(debug)"; 105 } 106 default: { 107 // Non reserved regular section numbers 108 if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(Sec)) 109 return *SecNameOrErr; 110 } 111 } 112 return ""; 113 } 114 115 Error COFFLinkGraphBuilder::graphifySections() { 116 LLVM_DEBUG(dbgs() << " Creating graph sections...\n"); 117 118 GraphBlocks.resize(Obj.getNumberOfSections() + 1); 119 // For each section... 120 for (COFFSectionIndex SecIndex = 1; SecIndex <= Obj.getNumberOfSections(); 121 SecIndex++) { 122 Expected<const object::coff_section *> Sec = Obj.getSection(SecIndex); 123 if (!Sec) 124 return Sec.takeError(); 125 126 StringRef SectionName; 127 if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(*Sec)) 128 SectionName = *SecNameOrErr; 129 130 bool IsDiscardable = 131 (*Sec)->Characteristics & 132 (COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_LNK_INFO); 133 if (IsDiscardable) { 134 LLVM_DEBUG(dbgs() << " " << SecIndex << ": \"" << SectionName 135 << "\" is discardable: " 136 "No graph section will be created.\n"); 137 continue; 138 } 139 140 // FIXME: Skip debug info sections 141 142 LLVM_DEBUG({ 143 dbgs() << " " 144 << "Creating section for \"" << SectionName << "\"\n"; 145 }); 146 147 // Get the section's memory protection flags. 148 MemProt Prot = MemProt::None; 149 if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE) 150 Prot |= MemProt::Exec; 151 if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_READ) 152 Prot |= MemProt::Read; 153 if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_WRITE) 154 Prot |= MemProt::Write; 155 156 // Look for existing sections first. 157 auto *GraphSec = G->findSectionByName(SectionName); 158 if (!GraphSec) 159 GraphSec = &G->createSection(SectionName, Prot); 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 B = &G->createContentBlock( 175 *GraphSec, 176 ArrayRef<char>(reinterpret_cast<const char *>(Data.data()), 177 Data.size()), 178 orc::ExecutorAddr(getSectionAddress(Obj, *Sec)), 179 (*Sec)->getAlignment(), 0); 180 } 181 182 setGraphBlock(SecIndex, B); 183 } 184 185 return Error::success(); 186 } 187 188 Error COFFLinkGraphBuilder::graphifySymbols() { 189 LLVM_DEBUG(dbgs() << " Creating graph symbols...\n"); 190 191 SymbolSets.resize(Obj.getNumberOfSections() + 1); 192 GraphSymbols.resize(Obj.getNumberOfSymbols()); 193 194 for (COFFSymbolIndex SymIndex = 0; SymIndex < Obj.getNumberOfSymbols(); 195 SymIndex++) { 196 Expected<object::COFFSymbolRef> Sym = Obj.getSymbol(SymIndex); 197 if (!Sym) 198 return Sym.takeError(); 199 200 StringRef SymbolName; 201 if (Expected<StringRef> SymNameOrErr = Obj.getSymbolName(*Sym)) 202 SymbolName = *SymNameOrErr; 203 204 COFFSectionIndex SectionIndex = Sym->getSectionNumber(); 205 const object::coff_section *Sec = nullptr; 206 207 if (!COFF::isReservedSectionNumber(SectionIndex)) { 208 auto SecOrErr = Obj.getSection(SectionIndex); 209 if (!SecOrErr) 210 return make_error<JITLinkError>( 211 "Invalid COFF section number:" + formatv("{0:d}: ", SectionIndex) + 212 " (" + toString(SecOrErr.takeError()) + ")"); 213 Sec = *SecOrErr; 214 } 215 216 // Create jitlink symbol 217 jitlink::Symbol *GSym = nullptr; 218 if (Sym->isFileRecord()) 219 LLVM_DEBUG({ 220 dbgs() << " " << SymIndex << ": Skipping FileRecord symbol \"" 221 << SymbolName << "\" in " 222 << getCOFFSectionName(SectionIndex, Sec, *Sym) 223 << " (index: " << SectionIndex << ") \n"; 224 }); 225 else if (Sym->isUndefined()) { 226 LLVM_DEBUG({ 227 dbgs() << " " << SymIndex 228 << ": Creating external graph symbol for COFF symbol \"" 229 << SymbolName << "\" in " 230 << getCOFFSectionName(SectionIndex, Sec, *Sym) 231 << " (index: " << SectionIndex << ") \n"; 232 }); 233 GSym = 234 &G->addExternalSymbol(SymbolName, Sym->getValue(), Linkage::Strong); 235 } else if (Sym->isWeakExternal()) { 236 COFFSymbolIndex TagIndex = 237 Sym->getAux<object::coff_aux_weak_external>()->TagIndex; 238 assert(Sym->getAux<object::coff_aux_weak_external>()->Characteristics != 239 COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY && 240 "IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY is not supported."); 241 assert(Sym->getAux<object::coff_aux_weak_external>()->Characteristics != 242 COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY && 243 "IMAGE_WEAK_EXTERN_SEARCH_LIBRARY is not supported."); 244 WeakAliasRequests.push_back({SymIndex, TagIndex, SymbolName}); 245 } else { 246 Expected<jitlink::Symbol *> NewGSym = 247 createDefinedSymbol(SymIndex, SymbolName, *Sym, Sec); 248 if (!NewGSym) 249 return NewGSym.takeError(); 250 GSym = *NewGSym; 251 if (GSym) { 252 LLVM_DEBUG({ 253 dbgs() << " " << SymIndex 254 << ": Creating defined graph symbol for COFF symbol \"" 255 << SymbolName << "\" in " 256 << getCOFFSectionName(SectionIndex, Sec, *Sym) 257 << " (index: " << SectionIndex << ") \n"; 258 dbgs() << " " << *GSym << "\n"; 259 }); 260 } 261 } 262 263 // Register the symbol 264 if (GSym) 265 setGraphSymbol(SectionIndex, SymIndex, *GSym); 266 SymIndex += Sym->getNumberOfAuxSymbols(); 267 } 268 269 if (auto Err = flushWeakAliasRequests()) 270 return Err; 271 272 if (auto Err = calculateImplicitSizeOfSymbols()) 273 return Err; 274 275 return Error::success(); 276 } 277 278 Error COFFLinkGraphBuilder::flushWeakAliasRequests() { 279 // Export the weak external symbols and alias it 280 for (auto &WeakAlias : WeakAliasRequests) { 281 if (auto *Target = getGraphSymbol(WeakAlias.Target)) { 282 Expected<object::COFFSymbolRef> AliasSymbol = 283 Obj.getSymbol(WeakAlias.Alias); 284 if (!AliasSymbol) 285 return AliasSymbol.takeError(); 286 287 // FIXME: Support this when there's a way to handle this. 288 if (!Target->isDefined()) 289 return make_error<JITLinkError>("Weak external symbol with external " 290 "symbol as alternative not supported."); 291 292 jitlink::Symbol *NewSymbol = &G->addDefinedSymbol( 293 Target->getBlock(), Target->getOffset(), WeakAlias.SymbolName, 294 Target->getSize(), Linkage::Weak, Scope::Default, 295 Target->isCallable(), false); 296 setGraphSymbol(AliasSymbol->getSectionNumber(), WeakAlias.Alias, 297 *NewSymbol); 298 LLVM_DEBUG({ 299 dbgs() << " " << WeakAlias.Alias 300 << ": Creating weak external symbol for COFF symbol \"" 301 << WeakAlias.SymbolName << "\" in section " 302 << AliasSymbol->getSectionNumber() << "\n"; 303 dbgs() << " " << *NewSymbol << "\n"; 304 }); 305 } else 306 return make_error<JITLinkError>("Weak symbol alias requested but actual " 307 "symbol not found for symbol " + 308 formatv("{0:d}", WeakAlias.Alias)); 309 } 310 return Error::success(); 311 } 312 313 // In COFF, most of the defined symbols don't contain the size information. 314 // Hence, we calculate the "implicit" size of symbol by taking the delta of 315 // offsets of consecutive symbols within a block. We maintain a balanced tree 316 // set of symbols sorted by offset per each block in order to achieve 317 // logarithmic time complexity of sorted symbol insertion. Symbol is inserted to 318 // the set once it's processed in graphifySymbols. In this function, we iterate 319 // each collected symbol in sorted order and calculate the implicit size. 320 Error COFFLinkGraphBuilder::calculateImplicitSizeOfSymbols() { 321 for (COFFSectionIndex SecIndex = 1; SecIndex <= Obj.getNumberOfSections(); 322 SecIndex++) { 323 auto &SymbolSet = SymbolSets[SecIndex]; 324 jitlink::Block *B = getGraphBlock(SecIndex); 325 orc::ExecutorAddrDiff LastOffset = B->getSize(); 326 orc::ExecutorAddrDiff LastDifferentOffset = B->getSize(); 327 orc::ExecutorAddrDiff LastSize = 0; 328 for (auto It = SymbolSet.rbegin(); It != SymbolSet.rend(); It++) { 329 orc::ExecutorAddrDiff Offset = It->first; 330 jitlink::Symbol *Symbol = It->second; 331 orc::ExecutorAddrDiff CandSize; 332 // Last offset can be same when aliasing happened 333 if (Symbol->getOffset() == LastOffset) 334 CandSize = LastSize; 335 else 336 CandSize = LastOffset - Offset; 337 338 LLVM_DEBUG({ 339 if (Offset + Symbol->getSize() > LastDifferentOffset) 340 dbgs() << " Overlapping symbol range generated for the following " 341 "symbol:" 342 << "\n" 343 << " " << *Symbol << "\n"; 344 }); 345 if (LastOffset != Offset) 346 LastDifferentOffset = Offset; 347 LastSize = CandSize; 348 LastOffset = Offset; 349 if (Symbol->getSize()) { 350 // Non empty symbol can happen in COMDAT symbol. 351 // We don't consider the possibility of overlapping symbol range that 352 // could be introduced by disparity between inferred symbol size and 353 // defined symbol size because symbol size information is currently only 354 // used by jitlink-check where we have control to not make overlapping 355 // ranges. 356 continue; 357 } 358 359 LLVM_DEBUG({ 360 if (!CandSize) 361 dbgs() << " Empty implicit symbol size generated for the following " 362 "symbol:" 363 << "\n" 364 << " " << *Symbol << "\n"; 365 }); 366 367 Symbol->setSize(CandSize); 368 } 369 } 370 return Error::success(); 371 } 372 373 Expected<Symbol *> COFFLinkGraphBuilder::createDefinedSymbol( 374 COFFSymbolIndex SymIndex, StringRef SymbolName, 375 object::COFFSymbolRef Symbol, const object::coff_section *Section) { 376 if (Symbol.isCommon()) { 377 // FIXME: correct alignment 378 return &G->addCommonSymbol(SymbolName, Scope::Default, getCommonSection(), 379 orc::ExecutorAddr(), Symbol.getValue(), 380 Symbol.getValue(), false); 381 } 382 if (Symbol.isAbsolute()) 383 return &G->addAbsoluteSymbol(SymbolName, 384 orc::ExecutorAddr(Symbol.getValue()), 0, 385 Linkage::Strong, Scope::Local, false); 386 387 if (llvm::COFF::isReservedSectionNumber(Symbol.getSectionNumber())) 388 return make_error<JITLinkError>( 389 "Reserved section number used in regular symbol " + 390 formatv("{0:d}", SymIndex)); 391 392 Block *B = getGraphBlock(Symbol.getSectionNumber()); 393 if (Symbol.isExternal()) { 394 // This is not a comdat sequence, export the symbol as it is 395 if (!isComdatSection(Section)) 396 return &G->addDefinedSymbol( 397 *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Default, 398 Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); 399 else { 400 if (!PendingComdatExport) 401 return make_error<JITLinkError>("No pending COMDAT export for symbol " + 402 formatv("{0:d}", SymIndex)); 403 if (PendingComdatExport->SectionIndex != Symbol.getSectionNumber()) 404 return make_error<JITLinkError>( 405 "COMDAT export section number mismatch for symbol " + 406 formatv("{0:d}", SymIndex)); 407 return exportCOMDATSymbol(SymIndex, SymbolName, Symbol); 408 } 409 } 410 411 if (Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC) { 412 const object::coff_aux_section_definition *Definition = 413 Symbol.getSectionDefinition(); 414 if (!Definition || !isComdatSection(Section)) { 415 // Handle typical static symbol 416 return &G->addDefinedSymbol( 417 *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local, 418 Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); 419 } 420 if (Definition->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { 421 // FIXME: don't dead strip this when parent section is alive 422 return &G->addDefinedSymbol( 423 *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local, 424 Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); 425 } 426 if (PendingComdatExport) 427 return make_error<JITLinkError>( 428 "COMDAT export request already exists before symbol " + 429 formatv("{0:d}", SymIndex)); 430 return createCOMDATExportRequest(SymIndex, Symbol, Definition); 431 } 432 return make_error<JITLinkError>("Unsupported storage class " + 433 formatv("{0:d}", Symbol.getStorageClass()) + 434 " in symbol " + formatv("{0:d}", SymIndex)); 435 } 436 437 // COMDAT handling: 438 // When IMAGE_SCN_LNK_COMDAT flag is set in the flags of a section, 439 // the section is called a COMDAT section. It contains two symbols 440 // in a sequence that specifes the behavior. First symbol is the section 441 // symbol which contains the size and name of the section. It also contains 442 // selection type that specifies how duplicate of the symbol is handled. 443 // Second symbol is COMDAT symbol which usually defines the external name and 444 // data type. 445 // 446 // Since two symbols always come in a specific order, we initiate pending COMDAT 447 // export request when we encounter the first symbol and actually exports it 448 // when we process the second symbol. 449 // 450 // Process the first symbol of COMDAT sequence. 451 Expected<Symbol *> COFFLinkGraphBuilder::createCOMDATExportRequest( 452 COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol, 453 const object::coff_aux_section_definition *Definition) { 454 Block *B = getGraphBlock(Symbol.getSectionNumber()); 455 Linkage L = Linkage::Strong; 456 switch (Definition->Selection) { 457 case COFF::IMAGE_COMDAT_SELECT_NODUPLICATES: { 458 L = Linkage::Strong; 459 break; 460 } 461 case COFF::IMAGE_COMDAT_SELECT_ANY: { 462 L = Linkage::Weak; 463 break; 464 } 465 case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH: 466 case COFF::IMAGE_COMDAT_SELECT_SAME_SIZE: { 467 // FIXME: Implement size/content validation when LinkGraph is able to 468 // handle this. 469 L = Linkage::Weak; 470 break; 471 } 472 case COFF::IMAGE_COMDAT_SELECT_LARGEST: { 473 // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST when LinkGraph is able to 474 // handle this. 475 return make_error<JITLinkError>( 476 "IMAGE_COMDAT_SELECT_LARGEST is not supported."); 477 } 478 case COFF::IMAGE_COMDAT_SELECT_NEWEST: { 479 // Even link.exe doesn't support this selection properly. 480 return make_error<JITLinkError>( 481 "IMAGE_COMDAT_SELECT_NEWEST is not supported."); 482 } 483 default: { 484 return make_error<JITLinkError>("Invalid comdat selection type: " + 485 formatv("{0:d}", Definition->Selection)); 486 } 487 } 488 PendingComdatExport = {SymIndex, Symbol.getSectionNumber(), L}; 489 return &G->addAnonymousSymbol(*B, Symbol.getValue(), Definition->Length, 490 false, false); 491 } 492 493 // Process the second symbol of COMDAT sequence. 494 Expected<Symbol *> 495 COFFLinkGraphBuilder::exportCOMDATSymbol(COFFSymbolIndex SymIndex, 496 StringRef SymbolName, 497 object::COFFSymbolRef Symbol) { 498 COFFSymbolIndex TargetIndex = PendingComdatExport->SymbolIndex; 499 Linkage L = PendingComdatExport->Linkage; 500 jitlink::Symbol *Target = getGraphSymbol(TargetIndex); 501 assert(Target && "COMDAT leaader is invalid."); 502 assert((llvm::count_if(G->defined_symbols(), 503 [&](const jitlink::Symbol *Sym) { 504 return Sym->getName() == SymbolName; 505 }) == 0) && 506 "Duplicate defined symbol"); 507 Target->setName(SymbolName); 508 Target->setLinkage(L); 509 Target->setCallable(Symbol.getComplexType() == 510 COFF::IMAGE_SYM_DTYPE_FUNCTION); 511 Target->setScope(Scope::Default); 512 LLVM_DEBUG({ 513 dbgs() << " " << SymIndex 514 << ": Exporting COMDAT graph symbol for COFF symbol \"" << SymbolName 515 << "\" in section " << Symbol.getSectionNumber() << "\n"; 516 dbgs() << " " << *Target << "\n"; 517 }); 518 PendingComdatExport = None; 519 return Target; 520 } 521 522 } // namespace jitlink 523 } // namespace llvm