xref: /freebsd/contrib/llvm-project/llvm/lib/Object/COFFImportFile.cpp (revision 357378bbdedf24ce2b90e9bd831af4a9db3ec70a)
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_view> 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 namespace {
175 // This class constructs various small object files necessary to support linking
176 // symbols imported from a DLL.  The contents are pretty strictly defined and
177 // nearly entirely static.  The details of the structures files are defined in
178 // WINNT.h and the PE/COFF specification.
179 class ObjectFactory {
180   using u16 = support::ulittle16_t;
181   using u32 = support::ulittle32_t;
182   MachineTypes NativeMachine;
183   BumpPtrAllocator Alloc;
184   StringRef ImportName;
185   StringRef Library;
186   std::string ImportDescriptorSymbolName;
187   std::string NullThunkSymbolName;
188 
189 public:
190   ObjectFactory(StringRef S, MachineTypes M)
191       : NativeMachine(M), ImportName(S), Library(llvm::sys::path::stem(S)),
192         ImportDescriptorSymbolName((ImportDescriptorPrefix + Library).str()),
193         NullThunkSymbolName(
194             (NullThunkDataPrefix + Library + NullThunkDataSuffix).str()) {}
195 
196   // Creates an Import Descriptor.  This is a small object file which contains a
197   // reference to the terminators and contains the library name (entry) for the
198   // import name table.  It will force the linker to construct the necessary
199   // structure to import symbols from the DLL.
200   NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
201 
202   // Creates a NULL import descriptor.  This is a small object file whcih
203   // contains a NULL import descriptor.  It is used to terminate the imports
204   // from a specific DLL.
205   NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
206 
207   // Create a NULL Thunk Entry.  This is a small object file which contains a
208   // NULL Import Address Table entry and a NULL Import Lookup Table Entry.  It
209   // is used to terminate the IAT and ILT.
210   NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
211 
212   // Create a short import file which is described in PE/COFF spec 7. Import
213   // Library Format.
214   NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
215                                      ImportType Type, ImportNameType NameType,
216                                      StringRef ExportName,
217                                      MachineTypes Machine);
218 
219   // Create a weak external file which is described in PE/COFF Aux Format 3.
220   NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp,
221                                       MachineTypes Machine);
222 
223   bool is64Bit() const { return COFF::is64Bit(NativeMachine); }
224 };
225 } // namespace
226 
227 NewArchiveMember
228 ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
229   const uint32_t NumberOfSections = 2;
230   const uint32_t NumberOfSymbols = 7;
231   const uint32_t NumberOfRelocations = 3;
232 
233   // COFF Header
234   coff_file_header Header{
235       u16(NativeMachine),
236       u16(NumberOfSections),
237       u32(0),
238       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
239           // .idata$2
240           sizeof(coff_import_directory_table_entry) +
241           NumberOfRelocations * sizeof(coff_relocation) +
242           // .idata$4
243           (ImportName.size() + 1)),
244       u32(NumberOfSymbols),
245       u16(0),
246       u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE),
247   };
248   append(Buffer, Header);
249 
250   // Section Header Table
251   const coff_section SectionTable[NumberOfSections] = {
252       {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
253        u32(0),
254        u32(0),
255        u32(sizeof(coff_import_directory_table_entry)),
256        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
257        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
258            sizeof(coff_import_directory_table_entry)),
259        u32(0),
260        u16(NumberOfRelocations),
261        u16(0),
262        u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
263            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
264       {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
265        u32(0),
266        u32(0),
267        u32(ImportName.size() + 1),
268        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
269            sizeof(coff_import_directory_table_entry) +
270            NumberOfRelocations * sizeof(coff_relocation)),
271        u32(0),
272        u32(0),
273        u16(0),
274        u16(0),
275        u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
276            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
277   };
278   append(Buffer, SectionTable);
279 
280   // .idata$2
281   const coff_import_directory_table_entry ImportDescriptor{
282       u32(0), u32(0), u32(0), u32(0), u32(0),
283   };
284   append(Buffer, ImportDescriptor);
285 
286   const coff_relocation RelocationTable[NumberOfRelocations] = {
287       {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
288        u16(getImgRelRelocation(NativeMachine))},
289       {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
290        u32(3), u16(getImgRelRelocation(NativeMachine))},
291       {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
292        u32(4), u16(getImgRelRelocation(NativeMachine))},
293   };
294   append(Buffer, RelocationTable);
295 
296   // .idata$6
297   auto S = Buffer.size();
298   Buffer.resize(S + ImportName.size() + 1);
299   memcpy(&Buffer[S], ImportName.data(), ImportName.size());
300   Buffer[S + ImportName.size()] = '\0';
301 
302   // Symbol Table
303   coff_symbol16 SymbolTable[NumberOfSymbols] = {
304       {{{0, 0, 0, 0, 0, 0, 0, 0}},
305        u32(0),
306        u16(1),
307        u16(0),
308        IMAGE_SYM_CLASS_EXTERNAL,
309        0},
310       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
311        u32(0),
312        u16(1),
313        u16(0),
314        IMAGE_SYM_CLASS_SECTION,
315        0},
316       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
317        u32(0),
318        u16(2),
319        u16(0),
320        IMAGE_SYM_CLASS_STATIC,
321        0},
322       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
323        u32(0),
324        u16(0),
325        u16(0),
326        IMAGE_SYM_CLASS_SECTION,
327        0},
328       {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
329        u32(0),
330        u16(0),
331        u16(0),
332        IMAGE_SYM_CLASS_SECTION,
333        0},
334       {{{0, 0, 0, 0, 0, 0, 0, 0}},
335        u32(0),
336        u16(0),
337        u16(0),
338        IMAGE_SYM_CLASS_EXTERNAL,
339        0},
340       {{{0, 0, 0, 0, 0, 0, 0, 0}},
341        u32(0),
342        u16(0),
343        u16(0),
344        IMAGE_SYM_CLASS_EXTERNAL,
345        0},
346   };
347   // TODO: Name.Offset.Offset here and in the all similar places below
348   // suggests a names refactoring. Maybe StringTableOffset.Value?
349   SymbolTable[0].Name.Offset.Offset =
350       sizeof(uint32_t);
351   SymbolTable[5].Name.Offset.Offset =
352       sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
353   SymbolTable[6].Name.Offset.Offset =
354       sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
355       NullImportDescriptorSymbolName.length() + 1;
356   append(Buffer, SymbolTable);
357 
358   // String Table
359   writeStringTable(Buffer,
360                    {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
361                     NullThunkSymbolName});
362 
363   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
364   return {MemoryBufferRef(F, ImportName)};
365 }
366 
367 NewArchiveMember
368 ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
369   const uint32_t NumberOfSections = 1;
370   const uint32_t NumberOfSymbols = 1;
371 
372   // COFF Header
373   coff_file_header Header{
374       u16(NativeMachine),
375       u16(NumberOfSections),
376       u32(0),
377       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
378           // .idata$3
379           sizeof(coff_import_directory_table_entry)),
380       u32(NumberOfSymbols),
381       u16(0),
382       u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE),
383   };
384   append(Buffer, Header);
385 
386   // Section Header Table
387   const coff_section SectionTable[NumberOfSections] = {
388       {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
389        u32(0),
390        u32(0),
391        u32(sizeof(coff_import_directory_table_entry)),
392        u32(sizeof(coff_file_header) +
393            (NumberOfSections * sizeof(coff_section))),
394        u32(0),
395        u32(0),
396        u16(0),
397        u16(0),
398        u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
399            IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
400   };
401   append(Buffer, SectionTable);
402 
403   // .idata$3
404   const coff_import_directory_table_entry ImportDescriptor{
405       u32(0), u32(0), u32(0), u32(0), u32(0),
406   };
407   append(Buffer, ImportDescriptor);
408 
409   // Symbol Table
410   coff_symbol16 SymbolTable[NumberOfSymbols] = {
411       {{{0, 0, 0, 0, 0, 0, 0, 0}},
412        u32(0),
413        u16(1),
414        u16(0),
415        IMAGE_SYM_CLASS_EXTERNAL,
416        0},
417   };
418   SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
419   append(Buffer, SymbolTable);
420 
421   // String Table
422   writeStringTable(Buffer, {NullImportDescriptorSymbolName});
423 
424   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
425   return {MemoryBufferRef(F, ImportName)};
426 }
427 
428 NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
429   const uint32_t NumberOfSections = 2;
430   const uint32_t NumberOfSymbols = 1;
431   uint32_t VASize = is64Bit() ? 8 : 4;
432 
433   // COFF Header
434   coff_file_header Header{
435       u16(NativeMachine),
436       u16(NumberOfSections),
437       u32(0),
438       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
439           // .idata$5
440           VASize +
441           // .idata$4
442           VASize),
443       u32(NumberOfSymbols),
444       u16(0),
445       u16(is64Bit() ? C_Invalid : IMAGE_FILE_32BIT_MACHINE),
446   };
447   append(Buffer, Header);
448 
449   // Section Header Table
450   const coff_section SectionTable[NumberOfSections] = {
451       {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
452        u32(0),
453        u32(0),
454        u32(VASize),
455        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
456        u32(0),
457        u32(0),
458        u16(0),
459        u16(0),
460        u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) |
461            IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
462            IMAGE_SCN_MEM_WRITE)},
463       {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
464        u32(0),
465        u32(0),
466        u32(VASize),
467        u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
468            VASize),
469        u32(0),
470        u32(0),
471        u16(0),
472        u16(0),
473        u32((is64Bit() ? IMAGE_SCN_ALIGN_8BYTES : IMAGE_SCN_ALIGN_4BYTES) |
474            IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
475            IMAGE_SCN_MEM_WRITE)},
476   };
477   append(Buffer, SectionTable);
478 
479   // .idata$5, ILT
480   append(Buffer, u32(0));
481   if (is64Bit())
482     append(Buffer, u32(0));
483 
484   // .idata$4, IAT
485   append(Buffer, u32(0));
486   if (is64Bit())
487     append(Buffer, u32(0));
488 
489   // Symbol Table
490   coff_symbol16 SymbolTable[NumberOfSymbols] = {
491       {{{0, 0, 0, 0, 0, 0, 0, 0}},
492        u32(0),
493        u16(1),
494        u16(0),
495        IMAGE_SYM_CLASS_EXTERNAL,
496        0},
497   };
498   SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
499   append(Buffer, SymbolTable);
500 
501   // String Table
502   writeStringTable(Buffer, {NullThunkSymbolName});
503 
504   StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
505   return {MemoryBufferRef{F, ImportName}};
506 }
507 
508 NewArchiveMember
509 ObjectFactory::createShortImport(StringRef Sym, uint16_t Ordinal,
510                                  ImportType ImportType, ImportNameType NameType,
511                                  StringRef ExportName, MachineTypes Machine) {
512   size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
513   if (!ExportName.empty())
514     ImpSize += ExportName.size() + 1;
515   size_t Size = sizeof(coff_import_header) + ImpSize;
516   char *Buf = Alloc.Allocate<char>(Size);
517   memset(Buf, 0, Size);
518   char *P = Buf;
519 
520   // Write short import library.
521   auto *Imp = reinterpret_cast<coff_import_header *>(P);
522   P += sizeof(*Imp);
523   Imp->Sig2 = 0xFFFF;
524   Imp->Machine = Machine;
525   Imp->SizeOfData = ImpSize;
526   if (Ordinal > 0)
527     Imp->OrdinalHint = Ordinal;
528   Imp->TypeInfo = (NameType << 2) | ImportType;
529 
530   // Write symbol name and DLL name.
531   memcpy(P, Sym.data(), Sym.size());
532   P += Sym.size() + 1;
533   memcpy(P, ImportName.data(), ImportName.size());
534   if (!ExportName.empty()) {
535     P += ImportName.size() + 1;
536     memcpy(P, ExportName.data(), ExportName.size());
537   }
538 
539   return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
540 }
541 
542 NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
543                                                    StringRef Weak, bool Imp,
544                                                    MachineTypes Machine) {
545   std::vector<uint8_t> Buffer;
546   const uint32_t NumberOfSections = 1;
547   const uint32_t NumberOfSymbols = 5;
548 
549   // COFF Header
550   coff_file_header Header{
551       u16(Machine),
552       u16(NumberOfSections),
553       u32(0),
554       u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),
555       u32(NumberOfSymbols),
556       u16(0),
557       u16(0),
558   };
559   append(Buffer, Header);
560 
561   // Section Header Table
562   const coff_section SectionTable[NumberOfSections] = {
563       {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
564        u32(0),
565        u32(0),
566        u32(0),
567        u32(0),
568        u32(0),
569        u32(0),
570        u16(0),
571        u16(0),
572        u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};
573   append(Buffer, SectionTable);
574 
575   // Symbol Table
576   coff_symbol16 SymbolTable[NumberOfSymbols] = {
577       {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
578        u32(0),
579        u16(0xFFFF),
580        u16(0),
581        IMAGE_SYM_CLASS_STATIC,
582        0},
583       {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
584        u32(0),
585        u16(0xFFFF),
586        u16(0),
587        IMAGE_SYM_CLASS_STATIC,
588        0},
589       {{{0, 0, 0, 0, 0, 0, 0, 0}},
590        u32(0),
591        u16(0),
592        u16(0),
593        IMAGE_SYM_CLASS_EXTERNAL,
594        0},
595       {{{0, 0, 0, 0, 0, 0, 0, 0}},
596        u32(0),
597        u16(0),
598        u16(0),
599        IMAGE_SYM_CLASS_WEAK_EXTERNAL,
600        1},
601       {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}},
602        u32(0),
603        u16(0),
604        u16(0),
605        IMAGE_SYM_CLASS_NULL,
606        0},
607   };
608   SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);
609 
610   //__imp_ String Table
611   StringRef Prefix = Imp ? "__imp_" : "";
612   SymbolTable[3].Name.Offset.Offset =
613       sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;
614   append(Buffer, SymbolTable);
615   writeStringTable(Buffer, {(Prefix + Sym).str(),
616                             (Prefix + Weak).str()});
617 
618   // Copied here so we can still use writeStringTable
619   char *Buf = Alloc.Allocate<char>(Buffer.size());
620   memcpy(Buf, Buffer.data(), Buffer.size());
621   return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};
622 }
623 
624 Error writeImportLibrary(StringRef ImportName, StringRef Path,
625                          ArrayRef<COFFShortExport> Exports,
626                          MachineTypes Machine, bool MinGW) {
627 
628   MachineTypes NativeMachine =
629       isArm64EC(Machine) ? IMAGE_FILE_MACHINE_ARM64 : Machine;
630 
631   std::vector<NewArchiveMember> Members;
632   ObjectFactory OF(llvm::sys::path::filename(ImportName), NativeMachine);
633 
634   std::vector<uint8_t> ImportDescriptor;
635   Members.push_back(OF.createImportDescriptor(ImportDescriptor));
636 
637   std::vector<uint8_t> NullImportDescriptor;
638   Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
639 
640   std::vector<uint8_t> NullThunk;
641   Members.push_back(OF.createNullThunk(NullThunk));
642 
643   for (const COFFShortExport &E : Exports) {
644     if (E.Private)
645       continue;
646 
647     ImportType ImportType = IMPORT_CODE;
648     if (E.Data)
649       ImportType = IMPORT_DATA;
650     if (E.Constant)
651       ImportType = IMPORT_CONST;
652 
653     StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;
654     std::string Name;
655 
656     if (E.ExtName.empty()) {
657       Name = std::string(SymbolName);
658     } else {
659       Expected<std::string> ReplacedName =
660           replace(SymbolName, E.Name, E.ExtName);
661       if (!ReplacedName)
662         return ReplacedName.takeError();
663       Name.swap(*ReplacedName);
664     }
665 
666     if (!E.AliasTarget.empty() && Name != E.AliasTarget) {
667       Members.push_back(
668           OF.createWeakExternal(E.AliasTarget, Name, false, Machine));
669       Members.push_back(
670           OF.createWeakExternal(E.AliasTarget, Name, true, Machine));
671       continue;
672     }
673 
674     ImportNameType NameType;
675     std::string ExportName;
676     if (E.Noname) {
677       NameType = IMPORT_ORDINAL;
678     } else {
679       NameType = getNameType(SymbolName, E.Name, Machine, MinGW);
680     }
681 
682     // On ARM64EC, use EXPORTAS to import demangled name for mangled symbols.
683     if (ImportType == IMPORT_CODE && isArm64EC(Machine)) {
684       if (std::optional<std::string> MangledName =
685               getArm64ECMangledFunctionName(Name)) {
686         if (ExportName.empty()) {
687           NameType = IMPORT_NAME_EXPORTAS;
688           ExportName.swap(Name);
689         }
690         Name = std::move(*MangledName);
691       } else if (ExportName.empty()) {
692         NameType = IMPORT_NAME_EXPORTAS;
693         ExportName = std::move(*getArm64ECDemangledFunctionName(Name));
694       }
695     }
696 
697     Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType,
698                                            NameType, ExportName, Machine));
699   }
700 
701   return writeArchive(Path, Members, SymtabWritingMode::NormalSymtab,
702                       MinGW ? object::Archive::K_GNU : object::Archive::K_COFF,
703                       /*Deterministic*/ true, /*Thin*/ false,
704                       /*OldArchiveBuf*/ nullptr, isArm64EC(Machine));
705 }
706 
707 } // namespace object
708 } // namespace llvm
709