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