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