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