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