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
getFileFormatName() const36 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
getExportName() const55 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
getImgRelRelocation(MachineTypes Machine)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
append(std::vector<uint8_t> & B,const T & Data)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
writeStringTable(std::vector<uint8_t> & B,ArrayRef<const std::string_view> Strings)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
getNameType(StringRef Sym,StringRef ExtName,MachineTypes Machine,bool MinGW)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
replace(StringRef S,StringRef From,StringRef To)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:
ObjectFactory(StringRef S,MachineTypes M)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
is64Bit() const223 bool is64Bit() const { return COFF::is64Bit(NativeMachine); }
224 };
225 } // namespace
226
227 NewArchiveMember
createImportDescriptor(std::vector<uint8_t> & Buffer)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
createNullImportDescriptor(std::vector<uint8_t> & Buffer)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
createNullThunk(std::vector<uint8_t> & Buffer)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
createShortImport(StringRef Sym,uint16_t Ordinal,ImportType ImportType,ImportNameType NameType,StringRef ExportName,MachineTypes Machine)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
createWeakExternal(StringRef Sym,StringRef Weak,bool Imp,MachineTypes Machine)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
writeImportLibrary(StringRef ImportName,StringRef Path,ArrayRef<COFFShortExport> Exports,MachineTypes Machine,bool MinGW)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