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