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 Machine; 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 : Machine(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 187 // Create a weak external file which is described in PE/COFF Aux Format 3. 188 NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp); 189 }; 190 } // namespace 191 192 NewArchiveMember 193 ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) { 194 const uint32_t NumberOfSections = 2; 195 const uint32_t NumberOfSymbols = 7; 196 const uint32_t NumberOfRelocations = 3; 197 198 // COFF Header 199 coff_file_header Header{ 200 u16(Machine), 201 u16(NumberOfSections), 202 u32(0), 203 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 204 // .idata$2 205 sizeof(coff_import_directory_table_entry) + 206 NumberOfRelocations * sizeof(coff_relocation) + 207 // .idata$4 208 (ImportName.size() + 1)), 209 u32(NumberOfSymbols), 210 u16(0), 211 u16(is64Bit(Machine) ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 212 }; 213 append(Buffer, Header); 214 215 // Section Header Table 216 const coff_section SectionTable[NumberOfSections] = { 217 {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}, 218 u32(0), 219 u32(0), 220 u32(sizeof(coff_import_directory_table_entry)), 221 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), 222 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 223 sizeof(coff_import_directory_table_entry)), 224 u32(0), 225 u16(NumberOfRelocations), 226 u16(0), 227 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 228 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 229 {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}, 230 u32(0), 231 u32(0), 232 u32(ImportName.size() + 1), 233 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 234 sizeof(coff_import_directory_table_entry) + 235 NumberOfRelocations * sizeof(coff_relocation)), 236 u32(0), 237 u32(0), 238 u16(0), 239 u16(0), 240 u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 241 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 242 }; 243 append(Buffer, SectionTable); 244 245 // .idata$2 246 const coff_import_directory_table_entry ImportDescriptor{ 247 u32(0), u32(0), u32(0), u32(0), u32(0), 248 }; 249 append(Buffer, ImportDescriptor); 250 251 const coff_relocation RelocationTable[NumberOfRelocations] = { 252 {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2), 253 u16(getImgRelRelocation(Machine))}, 254 {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)), 255 u32(3), u16(getImgRelRelocation(Machine))}, 256 {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)), 257 u32(4), u16(getImgRelRelocation(Machine))}, 258 }; 259 append(Buffer, RelocationTable); 260 261 // .idata$6 262 auto S = Buffer.size(); 263 Buffer.resize(S + ImportName.size() + 1); 264 memcpy(&Buffer[S], ImportName.data(), ImportName.size()); 265 Buffer[S + ImportName.size()] = '\0'; 266 267 // Symbol Table 268 coff_symbol16 SymbolTable[NumberOfSymbols] = { 269 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 270 u32(0), 271 u16(1), 272 u16(0), 273 IMAGE_SYM_CLASS_EXTERNAL, 274 0}, 275 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}}, 276 u32(0), 277 u16(1), 278 u16(0), 279 IMAGE_SYM_CLASS_SECTION, 280 0}, 281 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}}, 282 u32(0), 283 u16(2), 284 u16(0), 285 IMAGE_SYM_CLASS_STATIC, 286 0}, 287 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}}, 288 u32(0), 289 u16(0), 290 u16(0), 291 IMAGE_SYM_CLASS_SECTION, 292 0}, 293 {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}}, 294 u32(0), 295 u16(0), 296 u16(0), 297 IMAGE_SYM_CLASS_SECTION, 298 0}, 299 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 300 u32(0), 301 u16(0), 302 u16(0), 303 IMAGE_SYM_CLASS_EXTERNAL, 304 0}, 305 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 306 u32(0), 307 u16(0), 308 u16(0), 309 IMAGE_SYM_CLASS_EXTERNAL, 310 0}, 311 }; 312 // TODO: Name.Offset.Offset here and in the all similar places below 313 // suggests a names refactoring. Maybe StringTableOffset.Value? 314 SymbolTable[0].Name.Offset.Offset = 315 sizeof(uint32_t); 316 SymbolTable[5].Name.Offset.Offset = 317 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1; 318 SymbolTable[6].Name.Offset.Offset = 319 sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 + 320 NullImportDescriptorSymbolName.length() + 1; 321 append(Buffer, SymbolTable); 322 323 // String Table 324 writeStringTable(Buffer, 325 {ImportDescriptorSymbolName, NullImportDescriptorSymbolName, 326 NullThunkSymbolName}); 327 328 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 329 return {MemoryBufferRef(F, ImportName)}; 330 } 331 332 NewArchiveMember 333 ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) { 334 const uint32_t NumberOfSections = 1; 335 const uint32_t NumberOfSymbols = 1; 336 337 // COFF Header 338 coff_file_header Header{ 339 u16(Machine), 340 u16(NumberOfSections), 341 u32(0), 342 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 343 // .idata$3 344 sizeof(coff_import_directory_table_entry)), 345 u32(NumberOfSymbols), 346 u16(0), 347 u16(is64Bit(Machine) ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 348 }; 349 append(Buffer, Header); 350 351 // Section Header Table 352 const coff_section SectionTable[NumberOfSections] = { 353 {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'}, 354 u32(0), 355 u32(0), 356 u32(sizeof(coff_import_directory_table_entry)), 357 u32(sizeof(coff_file_header) + 358 (NumberOfSections * sizeof(coff_section))), 359 u32(0), 360 u32(0), 361 u16(0), 362 u16(0), 363 u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | 364 IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, 365 }; 366 append(Buffer, SectionTable); 367 368 // .idata$3 369 const coff_import_directory_table_entry ImportDescriptor{ 370 u32(0), u32(0), u32(0), u32(0), u32(0), 371 }; 372 append(Buffer, ImportDescriptor); 373 374 // Symbol Table 375 coff_symbol16 SymbolTable[NumberOfSymbols] = { 376 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 377 u32(0), 378 u16(1), 379 u16(0), 380 IMAGE_SYM_CLASS_EXTERNAL, 381 0}, 382 }; 383 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t); 384 append(Buffer, SymbolTable); 385 386 // String Table 387 writeStringTable(Buffer, {NullImportDescriptorSymbolName}); 388 389 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 390 return {MemoryBufferRef(F, ImportName)}; 391 } 392 393 NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) { 394 const uint32_t NumberOfSections = 2; 395 const uint32_t NumberOfSymbols = 1; 396 uint32_t VASize = is64Bit(Machine) ? 8 : 4; 397 398 // COFF Header 399 coff_file_header Header{ 400 u16(Machine), 401 u16(NumberOfSections), 402 u32(0), 403 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + 404 // .idata$5 405 VASize + 406 // .idata$4 407 VASize), 408 u32(NumberOfSymbols), 409 u16(0), 410 u16(is64Bit(Machine) ? C_Invalid : IMAGE_FILE_32BIT_MACHINE), 411 }; 412 append(Buffer, Header); 413 414 // Section Header Table 415 const coff_section SectionTable[NumberOfSections] = { 416 {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}, 417 u32(0), 418 u32(0), 419 u32(VASize), 420 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), 421 u32(0), 422 u32(0), 423 u16(0), 424 u16(0), 425 u32((is64Bit(Machine) ? IMAGE_SCN_ALIGN_8BYTES 426 : IMAGE_SCN_ALIGN_4BYTES) | 427 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | 428 IMAGE_SCN_MEM_WRITE)}, 429 {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}, 430 u32(0), 431 u32(0), 432 u32(VASize), 433 u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + 434 VASize), 435 u32(0), 436 u32(0), 437 u16(0), 438 u16(0), 439 u32((is64Bit(Machine) ? IMAGE_SCN_ALIGN_8BYTES 440 : IMAGE_SCN_ALIGN_4BYTES) | 441 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | 442 IMAGE_SCN_MEM_WRITE)}, 443 }; 444 append(Buffer, SectionTable); 445 446 // .idata$5, ILT 447 append(Buffer, u32(0)); 448 if (is64Bit(Machine)) 449 append(Buffer, u32(0)); 450 451 // .idata$4, IAT 452 append(Buffer, u32(0)); 453 if (is64Bit(Machine)) 454 append(Buffer, u32(0)); 455 456 // Symbol Table 457 coff_symbol16 SymbolTable[NumberOfSymbols] = { 458 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 459 u32(0), 460 u16(1), 461 u16(0), 462 IMAGE_SYM_CLASS_EXTERNAL, 463 0}, 464 }; 465 SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t); 466 append(Buffer, SymbolTable); 467 468 // String Table 469 writeStringTable(Buffer, {NullThunkSymbolName}); 470 471 StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()}; 472 return {MemoryBufferRef{F, ImportName}}; 473 } 474 475 NewArchiveMember ObjectFactory::createShortImport(StringRef Sym, 476 uint16_t Ordinal, 477 ImportType ImportType, 478 ImportNameType NameType) { 479 size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs 480 size_t Size = sizeof(coff_import_header) + ImpSize; 481 char *Buf = Alloc.Allocate<char>(Size); 482 memset(Buf, 0, Size); 483 char *P = Buf; 484 485 // Write short import library. 486 auto *Imp = reinterpret_cast<coff_import_header *>(P); 487 P += sizeof(*Imp); 488 Imp->Sig2 = 0xFFFF; 489 Imp->Machine = Machine; 490 Imp->SizeOfData = ImpSize; 491 if (Ordinal > 0) 492 Imp->OrdinalHint = Ordinal; 493 Imp->TypeInfo = (NameType << 2) | ImportType; 494 495 // Write symbol name and DLL name. 496 memcpy(P, Sym.data(), Sym.size()); 497 P += Sym.size() + 1; 498 memcpy(P, ImportName.data(), ImportName.size()); 499 500 return {MemoryBufferRef(StringRef(Buf, Size), ImportName)}; 501 } 502 503 NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym, 504 StringRef Weak, bool Imp) { 505 std::vector<uint8_t> Buffer; 506 const uint32_t NumberOfSections = 1; 507 const uint32_t NumberOfSymbols = 5; 508 509 // COFF Header 510 coff_file_header Header{ 511 u16(Machine), 512 u16(NumberOfSections), 513 u32(0), 514 u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))), 515 u32(NumberOfSymbols), 516 u16(0), 517 u16(0), 518 }; 519 append(Buffer, Header); 520 521 // Section Header Table 522 const coff_section SectionTable[NumberOfSections] = { 523 {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'}, 524 u32(0), 525 u32(0), 526 u32(0), 527 u32(0), 528 u32(0), 529 u32(0), 530 u16(0), 531 u16(0), 532 u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}}; 533 append(Buffer, SectionTable); 534 535 // Symbol Table 536 coff_symbol16 SymbolTable[NumberOfSymbols] = { 537 {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}}, 538 u32(0), 539 u16(0xFFFF), 540 u16(0), 541 IMAGE_SYM_CLASS_STATIC, 542 0}, 543 {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}}, 544 u32(0), 545 u16(0xFFFF), 546 u16(0), 547 IMAGE_SYM_CLASS_STATIC, 548 0}, 549 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 550 u32(0), 551 u16(0), 552 u16(0), 553 IMAGE_SYM_CLASS_EXTERNAL, 554 0}, 555 {{{0, 0, 0, 0, 0, 0, 0, 0}}, 556 u32(0), 557 u16(0), 558 u16(0), 559 IMAGE_SYM_CLASS_WEAK_EXTERNAL, 560 1}, 561 {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}}, 562 u32(0), 563 u16(0), 564 u16(0), 565 IMAGE_SYM_CLASS_NULL, 566 0}, 567 }; 568 SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t); 569 570 //__imp_ String Table 571 StringRef Prefix = Imp ? "__imp_" : ""; 572 SymbolTable[3].Name.Offset.Offset = 573 sizeof(uint32_t) + Sym.size() + Prefix.size() + 1; 574 append(Buffer, SymbolTable); 575 writeStringTable(Buffer, {(Prefix + Sym).str(), 576 (Prefix + Weak).str()}); 577 578 // Copied here so we can still use writeStringTable 579 char *Buf = Alloc.Allocate<char>(Buffer.size()); 580 memcpy(Buf, Buffer.data(), Buffer.size()); 581 return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)}; 582 } 583 584 Error writeImportLibrary(StringRef ImportName, StringRef Path, 585 ArrayRef<COFFShortExport> Exports, 586 MachineTypes Machine, bool MinGW) { 587 588 std::vector<NewArchiveMember> Members; 589 ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine); 590 591 std::vector<uint8_t> ImportDescriptor; 592 Members.push_back(OF.createImportDescriptor(ImportDescriptor)); 593 594 std::vector<uint8_t> NullImportDescriptor; 595 Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor)); 596 597 std::vector<uint8_t> NullThunk; 598 Members.push_back(OF.createNullThunk(NullThunk)); 599 600 for (const COFFShortExport &E : Exports) { 601 if (E.Private) 602 continue; 603 604 ImportType ImportType = IMPORT_CODE; 605 if (E.Data) 606 ImportType = IMPORT_DATA; 607 if (E.Constant) 608 ImportType = IMPORT_CONST; 609 610 StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName; 611 ImportNameType NameType = E.Noname 612 ? IMPORT_ORDINAL 613 : getNameType(SymbolName, E.Name, 614 Machine, MinGW); 615 Expected<std::string> Name = E.ExtName.empty() 616 ? std::string(SymbolName) 617 : replace(SymbolName, E.Name, E.ExtName); 618 619 if (!Name) 620 return Name.takeError(); 621 622 if (!E.AliasTarget.empty() && *Name != E.AliasTarget) { 623 Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, false)); 624 Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, true)); 625 continue; 626 } 627 628 Members.push_back( 629 OF.createShortImport(*Name, E.Ordinal, ImportType, NameType)); 630 } 631 632 return writeArchive(Path, Members, SymtabWritingMode::NormalSymtab, 633 MinGW ? object::Archive::K_GNU : object::Archive::K_COFF, 634 /*Deterministic*/ true, /*Thin*/ false, 635 /*OldArchiveBuf*/ nullptr, isArm64EC(Machine)); 636 } 637 638 } // namespace object 639 } // namespace llvm 640