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