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