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