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