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