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