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