1 //===- COFFImportFile.cpp - COFF short import file implementation ---------===// 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 // This file defines the writeImportLibrary function. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/Object/COFFImportFile.h" 14 #include "llvm/ADT/ArrayRef.h" 15 #include "llvm/ADT/Twine.h" 16 #include "llvm/Object/Archive.h" 17 #include "llvm/Object/ArchiveWriter.h" 18 #include "llvm/Object/COFF.h" 19 #include "llvm/Support/Allocator.h" 20 #include "llvm/Support/Endian.h" 21 #include "llvm/Support/Error.h" 22 #include "llvm/Support/ErrorHandling.h" 23 #include "llvm/Support/Path.h" 24 25 #include <cstdint> 26 #include <string> 27 #include <vector> 28 29 using namespace llvm::COFF; 30 using namespace llvm::object; 31 using namespace llvm; 32 33 namespace llvm { 34 namespace object { 35 36 StringRef COFFImportFile::getFileFormatName() const { 37 switch (getMachine()) { 38 case COFF::IMAGE_FILE_MACHINE_I386: 39 return "COFF-import-file-i386"; 40 case COFF::IMAGE_FILE_MACHINE_AMD64: 41 return "COFF-import-file-x86-64"; 42 case COFF::IMAGE_FILE_MACHINE_ARMNT: 43 return "COFF-import-file-ARM"; 44 case COFF::IMAGE_FILE_MACHINE_ARM64: 45 return "COFF-import-file-ARM64"; 46 case COFF::IMAGE_FILE_MACHINE_ARM64EC: 47 return "COFF-import-file-ARM64EC"; 48 case COFF::IMAGE_FILE_MACHINE_ARM64X: 49 return "COFF-import-file-ARM64X"; 50 default: 51 return "COFF-import-file-<unknown arch>"; 52 } 53 } 54 55 static StringRef applyNameType(ImportNameType Type, StringRef name) { 56 auto ltrim1 = [](StringRef s, StringRef chars) { 57 return !s.empty() && chars.contains(s[0]) ? s.substr(1) : s; 58 }; 59 60 switch (Type) { 61 case IMPORT_NAME_NOPREFIX: 62 name = ltrim1(name, "?@_"); 63 break; 64 case IMPORT_NAME_UNDECORATE: 65 name = ltrim1(name, "?@_"); 66 name = name.substr(0, name.find('@')); 67 break; 68 default: 69 break; 70 } 71 return name; 72 } 73 74 StringRef COFFImportFile::getExportName() const { 75 const coff_import_header *hdr = getCOFFImportHeader(); 76 StringRef name = Data.getBuffer().substr(sizeof(*hdr)).split('\0').first; 77 78 switch (hdr->getNameType()) { 79 case IMPORT_ORDINAL: 80 name = ""; 81 break; 82 case IMPORT_NAME_NOPREFIX: 83 case IMPORT_NAME_UNDECORATE: 84 name = applyNameType(static_cast<ImportNameType>(hdr->getNameType()), name); 85 break; 86 case IMPORT_NAME_EXPORTAS: { 87 // Skip DLL name 88 name = Data.getBuffer().substr(sizeof(*hdr) + name.size() + 1); 89 name = name.split('\0').second.split('\0').first; 90 break; 91 } 92 default: 93 break; 94 } 95 96 return name; 97 } 98 99 Error COFFImportFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const { 100 switch (Symb.p) { 101 case ImpSymbol: 102 OS << "__imp_"; 103 break; 104 case ECAuxSymbol: 105 OS << "__imp_aux_"; 106 break; 107 } 108 const char *Name = Data.getBufferStart() + sizeof(coff_import_header); 109 if (Symb.p != ECThunkSymbol && COFF::isArm64EC(getMachine())) { 110 if (std::optional<std::string> DemangledName = 111 getArm64ECDemangledFunctionName(Name)) { 112 OS << StringRef(*DemangledName); 113 return Error::success(); 114 } 115 } 116 OS << StringRef(Name); 117 return Error::success(); 118 } 119 120 static uint16_t getImgRelRelocation(MachineTypes Machine) { 121 switch (Machine) { 122 default: 123 llvm_unreachable("unsupported machine"); 124 case IMAGE_FILE_MACHINE_AMD64: 125 return IMAGE_REL_AMD64_ADDR32NB; 126 case IMAGE_FILE_MACHINE_ARMNT: 127 return IMAGE_REL_ARM_ADDR32NB; 128 case IMAGE_FILE_MACHINE_ARM64: 129 case IMAGE_FILE_MACHINE_ARM64EC: 130 case IMAGE_FILE_MACHINE_ARM64X: 131 return IMAGE_REL_ARM64_ADDR32NB; 132 case IMAGE_FILE_MACHINE_I386: 133 return IMAGE_REL_I386_DIR32NB; 134 } 135 } 136 137 template <class T> static void append(std::vector<uint8_t> &B, const T &Data) { 138 size_t S = B.size(); 139 B.resize(S + sizeof(T)); 140 memcpy(&B[S], &Data, sizeof(T)); 141 } 142 143 static void writeStringTable(std::vector<uint8_t> &B, 144 ArrayRef<const std::string_view> Strings) { 145 // The COFF string table consists of a 4-byte value which is the size of the 146 // table, including the length field itself. This value is followed by the 147 // string content itself, which is an array of null-terminated C-style 148 // strings. The termination is important as they are referenced to by offset 149 // by the symbol entity in the file format. 150 151 size_t Pos = B.size(); 152 size_t Offset = B.size(); 153 154 // Skip over the length field, we will fill it in later as we will have 155 // computed the length while emitting the string content itself. 156 Pos += sizeof(uint32_t); 157 158 for (const auto &S : Strings) { 159 B.resize(Pos + S.length() + 1); 160 std::copy(S.begin(), S.end(), std::next(B.begin(), Pos)); 161 B[Pos + S.length()] = 0; 162 Pos += S.length() + 1; 163 } 164 165 // Backfill the length of the table now that it has been computed. 166 support::ulittle32_t Length(B.size() - Offset); 167 support::endian::write32le(&B[Offset], Length); 168 } 169 170 static ImportNameType getNameType(StringRef Sym, StringRef ExtName, 171 MachineTypes Machine, bool MinGW) { 172 // A decorated stdcall function in MSVC is exported with the 173 // type IMPORT_NAME, and the exported function name includes the 174 // the leading underscore. In MinGW on the other hand, a decorated 175 // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX). 176 // See the comment in isDecorated in COFFModuleDefinition.cpp for more 177 // details. 178 if (ExtName.starts_with("_") && ExtName.contains('@') && !MinGW) 179 return IMPORT_NAME; 180 if (Sym != ExtName) 181 return IMPORT_NAME_UNDECORATE; 182 if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.starts_with("_")) 183 return IMPORT_NAME_NOPREFIX; 184 return IMPORT_NAME; 185 } 186 187 static Expected<std::string> replace(StringRef S, StringRef From, 188 StringRef To) { 189 size_t Pos = S.find(From); 190 191 // From and To may be mangled, but substrings in S may not. 192 if (Pos == StringRef::npos && From.starts_with("_") && To.starts_with("_")) { 193 From = From.substr(1); 194 To = To.substr(1); 195 Pos = S.find(From); 196 } 197 198 if (Pos == StringRef::npos) { 199 return make_error<StringError>( 200 StringRef(Twine(S + ": replacing '" + From + 201 "' with '" + To + "' failed").str()), object_error::parse_failed); 202 } 203 204 return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str(); 205 } 206 207 namespace { 208 // This class constructs various small object files necessary to support linking 209 // symbols imported from a DLL. The contents are pretty strictly defined and 210 // nearly entirely static. The details of the structures files are defined in 211 // WINNT.h and the PE/COFF specification. 212 class ObjectFactory { 213 using u16 = support::ulittle16_t; 214 using u32 = support::ulittle32_t; 215 MachineTypes NativeMachine; 216 BumpPtrAllocator Alloc; 217 StringRef ImportName; 218 StringRef Library; 219 std::string ImportDescriptorSymbolName; 220 std::string NullThunkSymbolName; 221 222 public: 223 ObjectFactory(StringRef S, MachineTypes M) 224 : NativeMachine(M), ImportName(S), Library(llvm::sys::path::stem(S)), 225 ImportDescriptorSymbolName((ImportDescriptorPrefix + Library).str()), 226 NullThunkSymbolName( 227 (NullThunkDataPrefix + Library + NullThunkDataSuffix).str()) {} 228 229 // Creates an Import Descriptor. This is a small object file which contains a 230 // reference to the terminators and contains the library name (entry) for the 231 // import name table. It will force the linker to construct the necessary 232 // structure to import symbols from the DLL. 233 NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer); 234 235 // Creates a NULL import descriptor. This is a small object file whcih 236 // contains a NULL import descriptor. It is used to terminate the imports 237 // from a specific DLL. 238 NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer); 239 240 // Create a NULL Thunk Entry. This is a small object file which contains a 241 // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It 242 // is used to terminate the IAT and ILT. 243 NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer); 244 245 // Create a short import file which is described in PE/COFF spec 7. Import 246 // Library Format. 247 NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal, 248 ImportType Type, ImportNameType NameType, 249 StringRef ExportName, 250 MachineTypes Machine); 251 252 // Create a weak external file which is described in PE/COFF Aux Format 3. 253 NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp, 254 MachineTypes Machine); 255 256 bool is64Bit() const { return COFF::is64Bit(NativeMachine); } 257 }; 258 } // namespace 259 260 NewArchiveMember 261 ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) { 262 const uint32_t NumberOfSections = 2; 263 const uint32_t NumberOfSymbols = 7; 264 const uint32_t NumberOfRelocations = 3; 265 266 // COFF Header 267 coff_file_header Header{ 268 u16(NativeMachine), 269 u16(NumberOfSections), 270 u32(0), 271 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 272 // .idata$2 273 sizeof(coff_import_directory_table_entry) + 274 NumberOfRelocations * sizeof(coff_relocation) + 275 // .idata$4 276 (ImportName.size() + 1)), 277 u32(NumberOfSymbols), 278 u16(0), 279 u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 280 }; 281 append(Buffer, Header); 282 283 // Section Header Table 284 const coff_section SectionTable[NumberOfSections] = { 285 {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}, 286 u32(0), 287 u32(0), 288 u32(sizeof(coff_import_directory_table_entry)), 289 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), 290 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 291 sizeof(coff_import_directory_table_entry)), 292 u32(0), 293 u16(NumberOfRelocations), 294 u16(0), 295 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 296 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 297 {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}, 298 u32(0), 299 u32(0), 300 u32(ImportName.size() + 1), 301 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 302 sizeof(coff_import_directory_table_entry) + 303 NumberOfRelocations * sizeof(coff_relocation)), 304 u32(0), 305 u32(0), 306 u16(0), 307 u16(0), 308 u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 309 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 310 }; 311 append(Buffer, SectionTable); 312 313 // .idata$2 314 const coff_import_directory_table_entry ImportDescriptor{ 315 u32(0), u32(0), u32(0), u32(0), u32(0), 316 }; 317 append(Buffer, ImportDescriptor); 318 319 const coff_relocation RelocationTable[NumberOfRelocations] = { 320 {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2), 321 u16(getImgRelRelocation(NativeMachine))}, 322 {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)), 323 u32(3), u16(getImgRelRelocation(NativeMachine))}, 324 {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)), 325 u32(4), u16(getImgRelRelocation(NativeMachine))}, 326 }; 327 append(Buffer, RelocationTable); 328 329 // .idata$6 330 auto S = Buffer.size(); 331 Buffer.resize(S + ImportName.size() + 1); 332 memcpy(&Buffer[S], ImportName.data(), ImportName.size()); 333 Buffer[S + ImportName.size()] = '\0'; 334 335 // Symbol Table 336 coff_symbol16 SymbolTable[NumberOfSymbols] = { 337 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 338 u32(0), 339 u16(1), 340 u16(0), 341 IMAGE_SYM_CLASS_EXTERNAL, 342 0}, 343 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}}, 344 u32(0), 345 u16(1), 346 u16(0), 347 IMAGE_SYM_CLASS_SECTION, 348 0}, 349 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}}, 350 u32(0), 351 u16(2), 352 u16(0), 353 IMAGE_SYM_CLASS_STATIC, 354 0}, 355 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}}, 356 u32(0), 357 u16(0), 358 u16(0), 359 IMAGE_SYM_CLASS_SECTION, 360 0}, 361 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}}, 362 u32(0), 363 u16(0), 364 u16(0), 365 IMAGE_SYM_CLASS_SECTION, 366 0}, 367 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 368 u32(0), 369 u16(0), 370 u16(0), 371 IMAGE_SYM_CLASS_EXTERNAL, 372 0}, 373 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 374 u32(0), 375 u16(0), 376 u16(0), 377 IMAGE_SYM_CLASS_EXTERNAL, 378 0}, 379 }; 380 // TODO: Name.Offset.Offset here and in the all similar places below 381 // suggests a names refactoring. Maybe StringTableOffset.Value? 382 SymbolTable[0].Name.Offset.Offset = 383 sizeof(uint32_t); 384 SymbolTable[5].Name.Offset.Offset = 385 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1; 386 SymbolTable[6].Name.Offset.Offset = 387 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 + 388 NullImportDescriptorSymbolName.length() + 1; 389 append(Buffer, SymbolTable); 390 391 // String Table 392 writeStringTable(Buffer, 393 {ImportDescriptorSymbolName, NullImportDescriptorSymbolName, 394 NullThunkSymbolName}); 395 396 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 397 return {MemoryBufferRef(F, ImportName)}; 398 } 399 400 NewArchiveMember 401 ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) { 402 const uint32_t NumberOfSections = 1; 403 const uint32_t NumberOfSymbols = 1; 404 405 // COFF Header 406 coff_file_header Header{ 407 u16(NativeMachine), 408 u16(NumberOfSections), 409 u32(0), 410 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 411 // .idata$3 412 sizeof(coff_import_directory_table_entry)), 413 u32(NumberOfSymbols), 414 u16(0), 415 u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 416 }; 417 append(Buffer, Header); 418 419 // Section Header Table 420 const coff_section SectionTable[NumberOfSections] = { 421 {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'}, 422 u32(0), 423 u32(0), 424 u32(sizeof(coff_import_directory_table_entry)), 425 u32(sizeof(coff_file_header) + 426 (NumberOfSections * sizeof(coff_section))), 427 u32(0), 428 u32(0), 429 u16(0), 430 u16(0), 431 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 432 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 433 }; 434 append(Buffer, SectionTable); 435 436 // .idata$3 437 const coff_import_directory_table_entry ImportDescriptor{ 438 u32(0), u32(0), u32(0), u32(0), u32(0), 439 }; 440 append(Buffer, ImportDescriptor); 441 442 // Symbol Table 443 coff_symbol16 SymbolTable[NumberOfSymbols] = { 444 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 445 u32(0), 446 u16(1), 447 u16(0), 448 IMAGE_SYM_CLASS_EXTERNAL, 449 0}, 450 }; 451 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t); 452 append(Buffer, SymbolTable); 453 454 // String Table 455 writeStringTable(Buffer, {NullImportDescriptorSymbolName}); 456 457 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 458 return {MemoryBufferRef(F, ImportName)}; 459 } 460 461 NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) { 462 const uint32_t NumberOfSections = 2; 463 const uint32_t NumberOfSymbols = 1; 464 uint32_t VASize = is64Bit() ? 8 : 4; 465 466 // COFF Header 467 coff_file_header Header{ 468 u16(NativeMachine), 469 u16(NumberOfSections), 470 u32(0), 471 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 472 // .idata$5 473 VASize + 474 // .idata$4 475 VASize), 476 u32(NumberOfSymbols), 477 u16(0), 478 u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 479 }; 480 append(Buffer, Header); 481 482 // Section Header Table 483 const coff_section SectionTable[NumberOfSections] = { 484 {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}, 485 u32(0), 486 u32(0), 487 u32(VASize), 488 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), 489 u32(0), 490 u32(0), 491 u16(0), 492 u16(0), 493 u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) | 494 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | 495 IMAGE_SCN_MEM_WRITE)}, 496 {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}, 497 u32(0), 498 u32(0), 499 u32(VASize), 500 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 501 VASize), 502 u32(0), 503 u32(0), 504 u16(0), 505 u16(0), 506 u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) | 507 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | 508 IMAGE_SCN_MEM_WRITE)}, 509 }; 510 append(Buffer, SectionTable); 511 512 // .idata$5, ILT 513 append(Buffer, u32(0)); 514 if (is64Bit()) 515 append(Buffer, u32(0)); 516 517 // .idata$4, IAT 518 append(Buffer, u32(0)); 519 if (is64Bit()) 520 append(Buffer, u32(0)); 521 522 // Symbol Table 523 coff_symbol16 SymbolTable[NumberOfSymbols] = { 524 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 525 u32(0), 526 u16(1), 527 u16(0), 528 IMAGE_SYM_CLASS_EXTERNAL, 529 0}, 530 }; 531 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t); 532 append(Buffer, SymbolTable); 533 534 // String Table 535 writeStringTable(Buffer, {NullThunkSymbolName}); 536 537 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 538 return {MemoryBufferRef{F, ImportName}}; 539 } 540 541 NewArchiveMember 542 ObjectFactory::createShortImport(StringRef Sym, uint16_t Ordinal, 543 ImportType ImportType, ImportNameType NameType, 544 StringRef ExportName, MachineTypes Machine) { 545 size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs 546 if (!ExportName.empty()) 547 ImpSize += ExportName.size() + 1; 548 size_t Size = sizeof(coff_import_header) + ImpSize; 549 char *Buf = Alloc.Allocate<char>(Size); 550 memset(Buf, 0, Size); 551 char *P = Buf; 552 553 // Write short import library. 554 auto *Imp = reinterpret_cast<coff_import_header *>(P); 555 P += sizeof(*Imp); 556 Imp->Sig2 = 0xFFFF; 557 Imp->Machine = Machine; 558 Imp->SizeOfData = ImpSize; 559 if (Ordinal > 0) 560 Imp->OrdinalHint = Ordinal; 561 Imp->TypeInfo = (NameType << 2) | ImportType; 562 563 // Write symbol name and DLL name. 564 memcpy(P, Sym.data(), Sym.size()); 565 P += Sym.size() + 1; 566 memcpy(P, ImportName.data(), ImportName.size()); 567 if (!ExportName.empty()) { 568 P += ImportName.size() + 1; 569 memcpy(P, ExportName.data(), ExportName.size()); 570 } 571 572 return {MemoryBufferRef(StringRef(Buf, Size), ImportName)}; 573 } 574 575 NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym, 576 StringRef Weak, bool Imp, 577 MachineTypes Machine) { 578 std::vector<uint8_t> Buffer; 579 const uint32_t NumberOfSections = 1; 580 const uint32_t NumberOfSymbols = 5; 581 582 // COFF Header 583 coff_file_header Header{ 584 u16(Machine), 585 u16(NumberOfSections), 586 u32(0), 587 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))), 588 u32(NumberOfSymbols), 589 u16(0), 590 u16(0), 591 }; 592 append(Buffer, Header); 593 594 // Section Header Table 595 const coff_section SectionTable[NumberOfSections] = { 596 {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'}, 597 u32(0), 598 u32(0), 599 u32(0), 600 u32(0), 601 u32(0), 602 u32(0), 603 u16(0), 604 u16(0), 605 u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}}; 606 append(Buffer, SectionTable); 607 608 // Symbol Table 609 coff_symbol16 SymbolTable[NumberOfSymbols] = { 610 {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}}, 611 u32(0), 612 u16(0xFFFF), 613 u16(0), 614 IMAGE_SYM_CLASS_STATIC, 615 0}, 616 {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}}, 617 u32(0), 618 u16(0xFFFF), 619 u16(0), 620 IMAGE_SYM_CLASS_STATIC, 621 0}, 622 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 623 u32(0), 624 u16(0), 625 u16(0), 626 IMAGE_SYM_CLASS_EXTERNAL, 627 0}, 628 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 629 u32(0), 630 u16(0), 631 u16(0), 632 IMAGE_SYM_CLASS_WEAK_EXTERNAL, 633 1}, 634 {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}}, 635 u32(0), 636 u16(0), 637 u16(0), 638 IMAGE_SYM_CLASS_NULL, 639 0}, 640 }; 641 SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t); 642 643 //__imp_ String Table 644 StringRef Prefix = Imp ? "__imp_" : ""; 645 SymbolTable[3].Name.Offset.Offset = 646 sizeof(uint32_t) + Sym.size() + Prefix.size() + 1; 647 append(Buffer, SymbolTable); 648 writeStringTable(Buffer, {(Prefix + Sym).str(), 649 (Prefix + Weak).str()}); 650 651 // Copied here so we can still use writeStringTable 652 char *Buf = Alloc.Allocate<char>(Buffer.size()); 653 memcpy(Buf, Buffer.data(), Buffer.size()); 654 return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)}; 655 } 656 657 Error writeImportLibrary(StringRef ImportName, StringRef Path, 658 ArrayRef<COFFShortExport> Exports, 659 MachineTypes Machine, bool MinGW, 660 ArrayRef<COFFShortExport> NativeExports, 661 bool AddUnderscores) { 662 663 MachineTypes NativeMachine = Machine; 664 if (isArm64EC(Machine)) { 665 NativeMachine = IMAGE_FILE_MACHINE_ARM64; 666 Machine = IMAGE_FILE_MACHINE_ARM64EC; 667 } 668 669 std::vector<NewArchiveMember> Members; 670 ObjectFactory OF(llvm::sys::path::filename(ImportName), NativeMachine); 671 672 std::vector<uint8_t> ImportDescriptor; 673 Members.push_back(OF.createImportDescriptor(ImportDescriptor)); 674 675 std::vector<uint8_t> NullImportDescriptor; 676 Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor)); 677 678 std::vector<uint8_t> NullThunk; 679 Members.push_back(OF.createNullThunk(NullThunk)); 680 681 auto addExports = [&](ArrayRef<COFFShortExport> Exp, 682 MachineTypes M) -> Error { 683 for (const COFFShortExport &E : Exp) { 684 if (E.Private) 685 continue; 686 687 ImportType ImportType = IMPORT_CODE; 688 if (E.Data) 689 ImportType = IMPORT_DATA; 690 if (E.Constant) 691 ImportType = IMPORT_CONST; 692 693 StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName; 694 std::string Name; 695 696 if (E.ExtName.empty()) { 697 Name = std::string(SymbolName); 698 } else { 699 Expected<std::string> ReplacedName = 700 replace(SymbolName, E.Name, E.ExtName); 701 if (!ReplacedName) 702 return ReplacedName.takeError(); 703 Name.swap(*ReplacedName); 704 } 705 706 ImportNameType NameType; 707 std::string ExportName; 708 if (E.Noname) { 709 NameType = IMPORT_ORDINAL; 710 } else if (!E.ExportAs.empty()) { 711 NameType = IMPORT_NAME_EXPORTAS; 712 ExportName = E.ExportAs; 713 } else if (!E.ImportName.empty()) { 714 // If we need to import from a specific ImportName, we may need to use 715 // a weak alias (which needs another import to point at). But if we can 716 // express ImportName based on the symbol name and a specific NameType, 717 // prefer that over an alias. 718 if (Machine == IMAGE_FILE_MACHINE_I386 && 719 applyNameType(IMPORT_NAME_UNDECORATE, Name) == E.ImportName) 720 NameType = IMPORT_NAME_UNDECORATE; 721 else if (Machine == IMAGE_FILE_MACHINE_I386 && 722 applyNameType(IMPORT_NAME_NOPREFIX, Name) == E.ImportName) 723 NameType = IMPORT_NAME_NOPREFIX; 724 else if (Name == E.ImportName) 725 NameType = IMPORT_NAME; 726 else { 727 StringRef Prefix = ""; 728 if (Machine == IMAGE_FILE_MACHINE_I386 && AddUnderscores) 729 Prefix = "_"; 730 731 if (ImportType == IMPORT_CODE) 732 Members.push_back(OF.createWeakExternal( 733 (Prefix + E.ImportName).str(), Name, false, M)); 734 Members.push_back(OF.createWeakExternal((Prefix + E.ImportName).str(), 735 Name, true, M)); 736 continue; 737 } 738 } else { 739 NameType = getNameType(SymbolName, E.Name, M, MinGW); 740 } 741 742 // On ARM64EC, use EXPORTAS to import demangled name for mangled symbols. 743 if (ImportType == IMPORT_CODE && isArm64EC(M)) { 744 if (std::optional<std::string> MangledName = 745 getArm64ECMangledFunctionName(Name)) { 746 if (!E.Noname && ExportName.empty()) { 747 NameType = IMPORT_NAME_EXPORTAS; 748 ExportName.swap(Name); 749 } 750 Name = std::move(*MangledName); 751 } else if (!E.Noname && ExportName.empty()) { 752 NameType = IMPORT_NAME_EXPORTAS; 753 ExportName = std::move(*getArm64ECDemangledFunctionName(Name)); 754 } 755 } 756 757 Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType, 758 NameType, ExportName, M)); 759 } 760 return Error::success(); 761 }; 762 763 if (Error e = addExports(Exports, Machine)) 764 return e; 765 if (Error e = addExports(NativeExports, NativeMachine)) 766 return e; 767 768 return writeArchive(Path, Members, SymtabWritingMode::NormalSymtab, 769 object::Archive::K_COFF, 770 /*Deterministic*/ true, /*Thin*/ false, 771 /*OldArchiveBuf*/ nullptr, isArm64EC(Machine)); 772 } 773 774 } // namespace object 775 } // namespace llvm 776