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