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 
is32bit(MachineTypes Machine)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 
getImgRelRelocation(MachineTypes Machine)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 
append(std::vector<uint8_t> & B,const T & Data)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 
writeStringTable(std::vector<uint8_t> & B,ArrayRef<const std::string> Strings)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 
getNameType(StringRef Sym,StringRef ExtName,MachineTypes Machine,bool MinGW)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 
replace(StringRef S,StringRef From,StringRef To)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:
ObjectFactory(StringRef S,MachineTypes M)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
createImportDescriptor(std::vector<uint8_t> & Buffer)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
createNullImportDescriptor(std::vector<uint8_t> & Buffer)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 
createNullThunk(std::vector<uint8_t> & Buffer)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 
createShortImport(StringRef Sym,uint16_t Ordinal,ImportType ImportType,ImportNameType NameType)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 
createWeakExternal(StringRef Sym,StringRef Weak,bool Imp)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 
writeImportLibrary(StringRef ImportName,StringRef Path,ArrayRef<COFFShortExport> Exports,MachineTypes Machine,bool MinGW)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