xref: /llvm-project/llvm/lib/Object/COFFImportFile.cpp (revision b26bfcc1ecc3c56d36fe6e525788024d1fdee01c)
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