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