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