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