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