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