Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lld/COFF/DLL.cpp
34870 views
1
//===- DLL.cpp ------------------------------------------------------------===//
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 various types of chunks for the DLL import or export
10
// descriptor tables. They are inherently Windows-specific.
11
// You need to read Microsoft PE/COFF spec to understand details
12
// about the data structures.
13
//
14
// If you are not particularly interested in linking against Windows
15
// DLL, you can skip this file, and you should still be able to
16
// understand the rest of the linker.
17
//
18
//===----------------------------------------------------------------------===//
19
20
#include "DLL.h"
21
#include "COFFLinkerContext.h"
22
#include "Chunks.h"
23
#include "SymbolTable.h"
24
#include "llvm/ADT/STLExtras.h"
25
#include "llvm/Object/COFF.h"
26
#include "llvm/Support/Endian.h"
27
#include "llvm/Support/Path.h"
28
29
using namespace llvm;
30
using namespace llvm::object;
31
using namespace llvm::support::endian;
32
using namespace llvm::COFF;
33
34
namespace lld::coff {
35
namespace {
36
37
// Import table
38
39
// A chunk for the import descriptor table.
40
class HintNameChunk : public NonSectionChunk {
41
public:
42
HintNameChunk(StringRef n, uint16_t h) : name(n), hint(h) {}
43
44
size_t getSize() const override {
45
// Starts with 2 byte Hint field, followed by a null-terminated string,
46
// ends with 0 or 1 byte padding.
47
return alignTo(name.size() + 3, 2);
48
}
49
50
void writeTo(uint8_t *buf) const override {
51
memset(buf, 0, getSize());
52
write16le(buf, hint);
53
memcpy(buf + 2, name.data(), name.size());
54
}
55
56
private:
57
StringRef name;
58
uint16_t hint;
59
};
60
61
// A chunk for the import descriptor table.
62
class LookupChunk : public NonSectionChunk {
63
public:
64
explicit LookupChunk(COFFLinkerContext &ctx, Chunk *c)
65
: hintName(c), ctx(ctx) {
66
setAlignment(ctx.config.wordsize);
67
}
68
size_t getSize() const override { return ctx.config.wordsize; }
69
70
void writeTo(uint8_t *buf) const override {
71
if (ctx.config.is64())
72
write64le(buf, hintName->getRVA());
73
else
74
write32le(buf, hintName->getRVA());
75
}
76
77
Chunk *hintName;
78
79
private:
80
COFFLinkerContext &ctx;
81
};
82
83
// A chunk for the import descriptor table.
84
// This chunk represent import-by-ordinal symbols.
85
// See Microsoft PE/COFF spec 7.1. Import Header for details.
86
class OrdinalOnlyChunk : public NonSectionChunk {
87
public:
88
explicit OrdinalOnlyChunk(COFFLinkerContext &c, uint16_t v)
89
: ordinal(v), ctx(c) {
90
setAlignment(ctx.config.wordsize);
91
}
92
size_t getSize() const override { return ctx.config.wordsize; }
93
94
void writeTo(uint8_t *buf) const override {
95
// An import-by-ordinal slot has MSB 1 to indicate that
96
// this is import-by-ordinal (and not import-by-name).
97
if (ctx.config.is64()) {
98
write64le(buf, (1ULL << 63) | ordinal);
99
} else {
100
write32le(buf, (1ULL << 31) | ordinal);
101
}
102
}
103
104
uint16_t ordinal;
105
106
private:
107
COFFLinkerContext &ctx;
108
};
109
110
// A chunk for the import descriptor table.
111
class ImportDirectoryChunk : public NonSectionChunk {
112
public:
113
explicit ImportDirectoryChunk(Chunk *n) : dllName(n) { setAlignment(4); }
114
size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); }
115
116
void writeTo(uint8_t *buf) const override {
117
memset(buf, 0, getSize());
118
119
auto *e = (coff_import_directory_table_entry *)(buf);
120
e->ImportLookupTableRVA = lookupTab->getRVA();
121
e->NameRVA = dllName->getRVA();
122
e->ImportAddressTableRVA = addressTab->getRVA();
123
}
124
125
Chunk *dllName;
126
Chunk *lookupTab;
127
Chunk *addressTab;
128
};
129
130
// A chunk representing null terminator in the import table.
131
// Contents of this chunk is always null bytes.
132
class NullChunk : public NonSectionChunk {
133
public:
134
explicit NullChunk(size_t n) : size(n) { hasData = false; }
135
size_t getSize() const override { return size; }
136
137
void writeTo(uint8_t *buf) const override {
138
memset(buf, 0, size);
139
}
140
141
private:
142
size_t size;
143
};
144
145
static std::vector<std::vector<DefinedImportData *>>
146
binImports(COFFLinkerContext &ctx,
147
const std::vector<DefinedImportData *> &imports) {
148
// Group DLL-imported symbols by DLL name because that's how
149
// symbols are laid out in the import descriptor table.
150
auto less = [&ctx](const std::string &a, const std::string &b) {
151
return ctx.config.dllOrder[a] < ctx.config.dllOrder[b];
152
};
153
std::map<std::string, std::vector<DefinedImportData *>, decltype(less)> m(
154
less);
155
for (DefinedImportData *sym : imports)
156
m[sym->getDLLName().lower()].push_back(sym);
157
158
std::vector<std::vector<DefinedImportData *>> v;
159
for (auto &kv : m) {
160
// Sort symbols by name for each group.
161
std::vector<DefinedImportData *> &syms = kv.second;
162
llvm::sort(syms, [](DefinedImportData *a, DefinedImportData *b) {
163
return a->getName() < b->getName();
164
});
165
v.push_back(std::move(syms));
166
}
167
return v;
168
}
169
170
// See Microsoft PE/COFF spec 4.3 for details.
171
172
// A chunk for the delay import descriptor table etnry.
173
class DelayDirectoryChunk : public NonSectionChunk {
174
public:
175
explicit DelayDirectoryChunk(Chunk *n) : dllName(n) { setAlignment(4); }
176
177
size_t getSize() const override {
178
return sizeof(delay_import_directory_table_entry);
179
}
180
181
void writeTo(uint8_t *buf) const override {
182
memset(buf, 0, getSize());
183
184
auto *e = (delay_import_directory_table_entry *)(buf);
185
e->Attributes = 1;
186
e->Name = dllName->getRVA();
187
e->ModuleHandle = moduleHandle->getRVA();
188
e->DelayImportAddressTable = addressTab->getRVA();
189
e->DelayImportNameTable = nameTab->getRVA();
190
}
191
192
Chunk *dllName;
193
Chunk *moduleHandle;
194
Chunk *addressTab;
195
Chunk *nameTab;
196
};
197
198
// Initial contents for delay-loaded functions.
199
// This code calls __delayLoadHelper2 function to resolve a symbol
200
// which then overwrites its jump table slot with the result
201
// for subsequent function calls.
202
static const uint8_t thunkX64[] = {
203
0x48, 0x8D, 0x05, 0, 0, 0, 0, // lea rax, [__imp_<FUNCNAME>]
204
0xE9, 0, 0, 0, 0, // jmp __tailMerge_<lib>
205
};
206
207
static const uint8_t tailMergeX64[] = {
208
0x51, // push rcx
209
0x52, // push rdx
210
0x41, 0x50, // push r8
211
0x41, 0x51, // push r9
212
0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h
213
0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0
214
0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1
215
0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2
216
0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3
217
0x48, 0x8B, 0xD0, // mov rdx, rax
218
0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...]
219
0xE8, 0, 0, 0, 0, // call __delayLoadHelper2
220
0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp]
221
0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h]
222
0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h]
223
0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h]
224
0x48, 0x83, 0xC4, 0x48, // add rsp, 48h
225
0x41, 0x59, // pop r9
226
0x41, 0x58, // pop r8
227
0x5A, // pop rdx
228
0x59, // pop rcx
229
0xFF, 0xE0, // jmp rax
230
};
231
232
static const uint8_t tailMergeUnwindInfoX64[] = {
233
0x01, // Version=1, Flags=UNW_FLAG_NHANDLER
234
0x0a, // Size of prolog
235
0x05, // Count of unwind codes
236
0x00, // No frame register
237
0x0a, 0x82, // Offset 0xa: UWOP_ALLOC_SMALL(0x48)
238
0x06, 0x02, // Offset 6: UWOP_ALLOC_SMALL(8)
239
0x04, 0x02, // Offset 4: UWOP_ALLOC_SMALL(8)
240
0x02, 0x02, // Offset 2: UWOP_ALLOC_SMALL(8)
241
0x01, 0x02, // Offset 1: UWOP_ALLOC_SMALL(8)
242
0x00, 0x00 // Padding to align on 32-bits
243
};
244
245
static const uint8_t thunkX86[] = {
246
0xB8, 0, 0, 0, 0, // mov eax, offset ___imp__<FUNCNAME>
247
0xE9, 0, 0, 0, 0, // jmp __tailMerge_<lib>
248
};
249
250
static const uint8_t tailMergeX86[] = {
251
0x51, // push ecx
252
0x52, // push edx
253
0x50, // push eax
254
0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR_<DLLNAME>_dll
255
0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8
256
0x5A, // pop edx
257
0x59, // pop ecx
258
0xFF, 0xE0, // jmp eax
259
};
260
261
static const uint8_t thunkARM[] = {
262
0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 __imp_<FUNCNAME>
263
0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 __imp_<FUNCNAME>
264
0x00, 0xf0, 0x00, 0xb8, // b.w __tailMerge_<lib>
265
};
266
267
static const uint8_t tailMergeARM[] = {
268
0x2d, 0xe9, 0x0f, 0x48, // push.w {r0, r1, r2, r3, r11, lr}
269
0x0d, 0xf2, 0x10, 0x0b, // addw r11, sp, #16
270
0x2d, 0xed, 0x10, 0x0b, // vpush {d0, d1, d2, d3, d4, d5, d6, d7}
271
0x61, 0x46, // mov r1, ip
272
0x40, 0xf2, 0x00, 0x00, // mov.w r0, #0 DELAY_IMPORT_DESCRIPTOR
273
0xc0, 0xf2, 0x00, 0x00, // mov.t r0, #0 DELAY_IMPORT_DESCRIPTOR
274
0x00, 0xf0, 0x00, 0xd0, // bl #0 __delayLoadHelper2
275
0x84, 0x46, // mov ip, r0
276
0xbd, 0xec, 0x10, 0x0b, // vpop {d0, d1, d2, d3, d4, d5, d6, d7}
277
0xbd, 0xe8, 0x0f, 0x48, // pop.w {r0, r1, r2, r3, r11, lr}
278
0x60, 0x47, // bx ip
279
};
280
281
static const uint8_t thunkARM64[] = {
282
0x11, 0x00, 0x00, 0x90, // adrp x17, #0 __imp_<FUNCNAME>
283
0x31, 0x02, 0x00, 0x91, // add x17, x17, #0 :lo12:__imp_<FUNCNAME>
284
0x00, 0x00, 0x00, 0x14, // b __tailMerge_<lib>
285
};
286
287
static const uint8_t tailMergeARM64[] = {
288
0xfd, 0x7b, 0xb3, 0xa9, // stp x29, x30, [sp, #-208]!
289
0xfd, 0x03, 0x00, 0x91, // mov x29, sp
290
0xe0, 0x07, 0x01, 0xa9, // stp x0, x1, [sp, #16]
291
0xe2, 0x0f, 0x02, 0xa9, // stp x2, x3, [sp, #32]
292
0xe4, 0x17, 0x03, 0xa9, // stp x4, x5, [sp, #48]
293
0xe6, 0x1f, 0x04, 0xa9, // stp x6, x7, [sp, #64]
294
0xe0, 0x87, 0x02, 0xad, // stp q0, q1, [sp, #80]
295
0xe2, 0x8f, 0x03, 0xad, // stp q2, q3, [sp, #112]
296
0xe4, 0x97, 0x04, 0xad, // stp q4, q5, [sp, #144]
297
0xe6, 0x9f, 0x05, 0xad, // stp q6, q7, [sp, #176]
298
0xe1, 0x03, 0x11, 0xaa, // mov x1, x17
299
0x00, 0x00, 0x00, 0x90, // adrp x0, #0 DELAY_IMPORT_DESCRIPTOR
300
0x00, 0x00, 0x00, 0x91, // add x0, x0, #0 :lo12:DELAY_IMPORT_DESCRIPTOR
301
0x00, 0x00, 0x00, 0x94, // bl #0 __delayLoadHelper2
302
0xf0, 0x03, 0x00, 0xaa, // mov x16, x0
303
0xe6, 0x9f, 0x45, 0xad, // ldp q6, q7, [sp, #176]
304
0xe4, 0x97, 0x44, 0xad, // ldp q4, q5, [sp, #144]
305
0xe2, 0x8f, 0x43, 0xad, // ldp q2, q3, [sp, #112]
306
0xe0, 0x87, 0x42, 0xad, // ldp q0, q1, [sp, #80]
307
0xe6, 0x1f, 0x44, 0xa9, // ldp x6, x7, [sp, #64]
308
0xe4, 0x17, 0x43, 0xa9, // ldp x4, x5, [sp, #48]
309
0xe2, 0x0f, 0x42, 0xa9, // ldp x2, x3, [sp, #32]
310
0xe0, 0x07, 0x41, 0xa9, // ldp x0, x1, [sp, #16]
311
0xfd, 0x7b, 0xcd, 0xa8, // ldp x29, x30, [sp], #208
312
0x00, 0x02, 0x1f, 0xd6, // br x16
313
};
314
315
// A chunk for the delay import thunk.
316
class ThunkChunkX64 : public NonSectionCodeChunk {
317
public:
318
ThunkChunkX64(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {}
319
320
size_t getSize() const override { return sizeof(thunkX64); }
321
MachineTypes getMachine() const override { return AMD64; }
322
323
void writeTo(uint8_t *buf) const override {
324
memcpy(buf, thunkX64, sizeof(thunkX64));
325
write32le(buf + 3, imp->getRVA() - rva - 7);
326
write32le(buf + 8, tailMerge->getRVA() - rva - 12);
327
}
328
329
Defined *imp = nullptr;
330
Chunk *tailMerge = nullptr;
331
};
332
333
class TailMergeChunkX64 : public NonSectionCodeChunk {
334
public:
335
TailMergeChunkX64(Chunk *d, Defined *h) : desc(d), helper(h) {}
336
337
size_t getSize() const override { return sizeof(tailMergeX64); }
338
MachineTypes getMachine() const override { return AMD64; }
339
340
void writeTo(uint8_t *buf) const override {
341
memcpy(buf, tailMergeX64, sizeof(tailMergeX64));
342
write32le(buf + 39, desc->getRVA() - rva - 43);
343
write32le(buf + 44, helper->getRVA() - rva - 48);
344
}
345
346
Chunk *desc = nullptr;
347
Defined *helper = nullptr;
348
};
349
350
class TailMergePDataChunkX64 : public NonSectionChunk {
351
public:
352
TailMergePDataChunkX64(Chunk *tm, Chunk *unwind) : tm(tm), unwind(unwind) {
353
// See
354
// https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-runtime_function
355
setAlignment(4);
356
}
357
358
size_t getSize() const override { return 3 * sizeof(uint32_t); }
359
360
void writeTo(uint8_t *buf) const override {
361
write32le(buf + 0, tm->getRVA()); // TailMergeChunk start RVA
362
write32le(buf + 4, tm->getRVA() + tm->getSize()); // TailMergeChunk stop RVA
363
write32le(buf + 8, unwind->getRVA()); // UnwindInfo RVA
364
}
365
366
Chunk *tm = nullptr;
367
Chunk *unwind = nullptr;
368
};
369
370
class TailMergeUnwindInfoX64 : public NonSectionChunk {
371
public:
372
TailMergeUnwindInfoX64() {
373
// See
374
// https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_info
375
setAlignment(4);
376
}
377
378
size_t getSize() const override { return sizeof(tailMergeUnwindInfoX64); }
379
380
void writeTo(uint8_t *buf) const override {
381
memcpy(buf, tailMergeUnwindInfoX64, sizeof(tailMergeUnwindInfoX64));
382
}
383
};
384
385
class ThunkChunkX86 : public NonSectionCodeChunk {
386
public:
387
ThunkChunkX86(COFFLinkerContext &ctx, Defined *i, Chunk *tm)
388
: imp(i), tailMerge(tm), ctx(ctx) {}
389
390
size_t getSize() const override { return sizeof(thunkX86); }
391
MachineTypes getMachine() const override { return I386; }
392
393
void writeTo(uint8_t *buf) const override {
394
memcpy(buf, thunkX86, sizeof(thunkX86));
395
write32le(buf + 1, imp->getRVA() + ctx.config.imageBase);
396
write32le(buf + 6, tailMerge->getRVA() - rva - 10);
397
}
398
399
void getBaserels(std::vector<Baserel> *res) override {
400
res->emplace_back(rva + 1, ctx.config.machine);
401
}
402
403
Defined *imp = nullptr;
404
Chunk *tailMerge = nullptr;
405
406
private:
407
const COFFLinkerContext &ctx;
408
};
409
410
class TailMergeChunkX86 : public NonSectionCodeChunk {
411
public:
412
TailMergeChunkX86(COFFLinkerContext &ctx, Chunk *d, Defined *h)
413
: desc(d), helper(h), ctx(ctx) {}
414
415
size_t getSize() const override { return sizeof(tailMergeX86); }
416
MachineTypes getMachine() const override { return I386; }
417
418
void writeTo(uint8_t *buf) const override {
419
memcpy(buf, tailMergeX86, sizeof(tailMergeX86));
420
write32le(buf + 4, desc->getRVA() + ctx.config.imageBase);
421
write32le(buf + 9, helper->getRVA() - rva - 13);
422
}
423
424
void getBaserels(std::vector<Baserel> *res) override {
425
res->emplace_back(rva + 4, ctx.config.machine);
426
}
427
428
Chunk *desc = nullptr;
429
Defined *helper = nullptr;
430
431
private:
432
const COFFLinkerContext &ctx;
433
};
434
435
class ThunkChunkARM : public NonSectionCodeChunk {
436
public:
437
ThunkChunkARM(COFFLinkerContext &ctx, Defined *i, Chunk *tm)
438
: imp(i), tailMerge(tm), ctx(ctx) {
439
setAlignment(2);
440
}
441
442
size_t getSize() const override { return sizeof(thunkARM); }
443
MachineTypes getMachine() const override { return ARMNT; }
444
445
void writeTo(uint8_t *buf) const override {
446
memcpy(buf, thunkARM, sizeof(thunkARM));
447
applyMOV32T(buf + 0, imp->getRVA() + ctx.config.imageBase);
448
applyBranch24T(buf + 8, tailMerge->getRVA() - rva - 12);
449
}
450
451
void getBaserels(std::vector<Baserel> *res) override {
452
res->emplace_back(rva + 0, IMAGE_REL_BASED_ARM_MOV32T);
453
}
454
455
Defined *imp = nullptr;
456
Chunk *tailMerge = nullptr;
457
458
private:
459
const COFFLinkerContext &ctx;
460
};
461
462
class TailMergeChunkARM : public NonSectionCodeChunk {
463
public:
464
TailMergeChunkARM(COFFLinkerContext &ctx, Chunk *d, Defined *h)
465
: desc(d), helper(h), ctx(ctx) {
466
setAlignment(2);
467
}
468
469
size_t getSize() const override { return sizeof(tailMergeARM); }
470
MachineTypes getMachine() const override { return ARMNT; }
471
472
void writeTo(uint8_t *buf) const override {
473
memcpy(buf, tailMergeARM, sizeof(tailMergeARM));
474
applyMOV32T(buf + 14, desc->getRVA() + ctx.config.imageBase);
475
applyBranch24T(buf + 22, helper->getRVA() - rva - 26);
476
}
477
478
void getBaserels(std::vector<Baserel> *res) override {
479
res->emplace_back(rva + 14, IMAGE_REL_BASED_ARM_MOV32T);
480
}
481
482
Chunk *desc = nullptr;
483
Defined *helper = nullptr;
484
485
private:
486
const COFFLinkerContext &ctx;
487
};
488
489
class ThunkChunkARM64 : public NonSectionCodeChunk {
490
public:
491
ThunkChunkARM64(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {
492
setAlignment(4);
493
}
494
495
size_t getSize() const override { return sizeof(thunkARM64); }
496
MachineTypes getMachine() const override { return ARM64; }
497
498
void writeTo(uint8_t *buf) const override {
499
memcpy(buf, thunkARM64, sizeof(thunkARM64));
500
applyArm64Addr(buf + 0, imp->getRVA(), rva + 0, 12);
501
applyArm64Imm(buf + 4, imp->getRVA() & 0xfff, 0);
502
applyArm64Branch26(buf + 8, tailMerge->getRVA() - rva - 8);
503
}
504
505
Defined *imp = nullptr;
506
Chunk *tailMerge = nullptr;
507
};
508
509
class TailMergeChunkARM64 : public NonSectionCodeChunk {
510
public:
511
TailMergeChunkARM64(Chunk *d, Defined *h) : desc(d), helper(h) {
512
setAlignment(4);
513
}
514
515
size_t getSize() const override { return sizeof(tailMergeARM64); }
516
MachineTypes getMachine() const override { return ARM64; }
517
518
void writeTo(uint8_t *buf) const override {
519
memcpy(buf, tailMergeARM64, sizeof(tailMergeARM64));
520
applyArm64Addr(buf + 44, desc->getRVA(), rva + 44, 12);
521
applyArm64Imm(buf + 48, desc->getRVA() & 0xfff, 0);
522
applyArm64Branch26(buf + 52, helper->getRVA() - rva - 52);
523
}
524
525
Chunk *desc = nullptr;
526
Defined *helper = nullptr;
527
};
528
529
// A chunk for the import descriptor table.
530
class DelayAddressChunk : public NonSectionChunk {
531
public:
532
explicit DelayAddressChunk(COFFLinkerContext &ctx, Chunk *c)
533
: thunk(c), ctx(ctx) {
534
setAlignment(ctx.config.wordsize);
535
}
536
size_t getSize() const override { return ctx.config.wordsize; }
537
538
void writeTo(uint8_t *buf) const override {
539
if (ctx.config.is64()) {
540
write64le(buf, thunk->getRVA() + ctx.config.imageBase);
541
} else {
542
uint32_t bit = 0;
543
// Pointer to thumb code must have the LSB set, so adjust it.
544
if (ctx.config.machine == ARMNT)
545
bit = 1;
546
write32le(buf, (thunk->getRVA() + ctx.config.imageBase) | bit);
547
}
548
}
549
550
void getBaserels(std::vector<Baserel> *res) override {
551
res->emplace_back(rva, ctx.config.machine);
552
}
553
554
Chunk *thunk;
555
556
private:
557
const COFFLinkerContext &ctx;
558
};
559
560
// Export table
561
// Read Microsoft PE/COFF spec 5.3 for details.
562
563
// A chunk for the export descriptor table.
564
class ExportDirectoryChunk : public NonSectionChunk {
565
public:
566
ExportDirectoryChunk(int baseOrdinal, int maxOrdinal, int nameTabSize,
567
Chunk *d, Chunk *a, Chunk *n, Chunk *o)
568
: baseOrdinal(baseOrdinal), maxOrdinal(maxOrdinal),
569
nameTabSize(nameTabSize), dllName(d), addressTab(a), nameTab(n),
570
ordinalTab(o) {}
571
572
size_t getSize() const override {
573
return sizeof(export_directory_table_entry);
574
}
575
576
void writeTo(uint8_t *buf) const override {
577
memset(buf, 0, getSize());
578
579
auto *e = (export_directory_table_entry *)(buf);
580
e->NameRVA = dllName->getRVA();
581
e->OrdinalBase = baseOrdinal;
582
e->AddressTableEntries = (maxOrdinal - baseOrdinal) + 1;
583
e->NumberOfNamePointers = nameTabSize;
584
e->ExportAddressTableRVA = addressTab->getRVA();
585
e->NamePointerRVA = nameTab->getRVA();
586
e->OrdinalTableRVA = ordinalTab->getRVA();
587
}
588
589
uint16_t baseOrdinal;
590
uint16_t maxOrdinal;
591
uint16_t nameTabSize;
592
Chunk *dllName;
593
Chunk *addressTab;
594
Chunk *nameTab;
595
Chunk *ordinalTab;
596
};
597
598
class AddressTableChunk : public NonSectionChunk {
599
public:
600
explicit AddressTableChunk(COFFLinkerContext &ctx, size_t baseOrdinal,
601
size_t maxOrdinal)
602
: baseOrdinal(baseOrdinal), size((maxOrdinal - baseOrdinal) + 1),
603
ctx(ctx) {}
604
size_t getSize() const override { return size * 4; }
605
606
void writeTo(uint8_t *buf) const override {
607
memset(buf, 0, getSize());
608
609
for (const Export &e : ctx.config.exports) {
610
assert(e.ordinal >= baseOrdinal && "Export symbol has invalid ordinal");
611
// Subtract the OrdinalBase to get the index.
612
uint8_t *p = buf + (e.ordinal - baseOrdinal) * 4;
613
uint32_t bit = 0;
614
// Pointer to thumb code must have the LSB set, so adjust it.
615
if (ctx.config.machine == ARMNT && !e.data)
616
bit = 1;
617
if (e.forwardChunk) {
618
write32le(p, e.forwardChunk->getRVA() | bit);
619
} else {
620
assert(cast<Defined>(e.sym)->getRVA() != 0 &&
621
"Exported symbol unmapped");
622
write32le(p, cast<Defined>(e.sym)->getRVA() | bit);
623
}
624
}
625
}
626
627
private:
628
size_t baseOrdinal;
629
size_t size;
630
const COFFLinkerContext &ctx;
631
};
632
633
class NamePointersChunk : public NonSectionChunk {
634
public:
635
explicit NamePointersChunk(std::vector<Chunk *> &v) : chunks(v) {}
636
size_t getSize() const override { return chunks.size() * 4; }
637
638
void writeTo(uint8_t *buf) const override {
639
for (Chunk *c : chunks) {
640
write32le(buf, c->getRVA());
641
buf += 4;
642
}
643
}
644
645
private:
646
std::vector<Chunk *> chunks;
647
};
648
649
class ExportOrdinalChunk : public NonSectionChunk {
650
public:
651
explicit ExportOrdinalChunk(const COFFLinkerContext &ctx, size_t baseOrdinal,
652
size_t tableSize)
653
: baseOrdinal(baseOrdinal), size(tableSize), ctx(ctx) {}
654
size_t getSize() const override { return size * 2; }
655
656
void writeTo(uint8_t *buf) const override {
657
for (const Export &e : ctx.config.exports) {
658
if (e.noname)
659
continue;
660
assert(e.ordinal >= baseOrdinal && "Export symbol has invalid ordinal");
661
// This table stores unbiased indices, so subtract OrdinalBase.
662
write16le(buf, e.ordinal - baseOrdinal);
663
buf += 2;
664
}
665
}
666
667
private:
668
size_t baseOrdinal;
669
size_t size;
670
const COFFLinkerContext &ctx;
671
};
672
673
} // anonymous namespace
674
675
void IdataContents::create(COFFLinkerContext &ctx) {
676
std::vector<std::vector<DefinedImportData *>> v = binImports(ctx, imports);
677
678
// Create .idata contents for each DLL.
679
for (std::vector<DefinedImportData *> &syms : v) {
680
// Create lookup and address tables. If they have external names,
681
// we need to create hintName chunks to store the names.
682
// If they don't (if they are import-by-ordinals), we store only
683
// ordinal values to the table.
684
size_t base = lookups.size();
685
for (DefinedImportData *s : syms) {
686
uint16_t ord = s->getOrdinal();
687
if (s->getExternalName().empty()) {
688
lookups.push_back(make<OrdinalOnlyChunk>(ctx, ord));
689
addresses.push_back(make<OrdinalOnlyChunk>(ctx, ord));
690
continue;
691
}
692
auto *c = make<HintNameChunk>(s->getExternalName(), ord);
693
lookups.push_back(make<LookupChunk>(ctx, c));
694
addresses.push_back(make<LookupChunk>(ctx, c));
695
hints.push_back(c);
696
}
697
// Terminate with null values.
698
lookups.push_back(make<NullChunk>(ctx.config.wordsize));
699
addresses.push_back(make<NullChunk>(ctx.config.wordsize));
700
701
for (int i = 0, e = syms.size(); i < e; ++i)
702
syms[i]->setLocation(addresses[base + i]);
703
704
// Create the import table header.
705
dllNames.push_back(make<StringChunk>(syms[0]->getDLLName()));
706
auto *dir = make<ImportDirectoryChunk>(dllNames.back());
707
dir->lookupTab = lookups[base];
708
dir->addressTab = addresses[base];
709
dirs.push_back(dir);
710
}
711
// Add null terminator.
712
dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry)));
713
}
714
715
std::vector<Chunk *> DelayLoadContents::getChunks() {
716
std::vector<Chunk *> v;
717
v.insert(v.end(), dirs.begin(), dirs.end());
718
v.insert(v.end(), names.begin(), names.end());
719
v.insert(v.end(), hintNames.begin(), hintNames.end());
720
v.insert(v.end(), dllNames.begin(), dllNames.end());
721
return v;
722
}
723
724
std::vector<Chunk *> DelayLoadContents::getDataChunks() {
725
std::vector<Chunk *> v;
726
v.insert(v.end(), moduleHandles.begin(), moduleHandles.end());
727
v.insert(v.end(), addresses.begin(), addresses.end());
728
return v;
729
}
730
731
uint64_t DelayLoadContents::getDirSize() {
732
return dirs.size() * sizeof(delay_import_directory_table_entry);
733
}
734
735
void DelayLoadContents::create(Defined *h) {
736
helper = h;
737
std::vector<std::vector<DefinedImportData *>> v = binImports(ctx, imports);
738
739
Chunk *unwind = newTailMergeUnwindInfoChunk();
740
741
// Create .didat contents for each DLL.
742
for (std::vector<DefinedImportData *> &syms : v) {
743
// Create the delay import table header.
744
dllNames.push_back(make<StringChunk>(syms[0]->getDLLName()));
745
auto *dir = make<DelayDirectoryChunk>(dllNames.back());
746
747
size_t base = addresses.size();
748
Chunk *tm = newTailMergeChunk(dir);
749
Chunk *pdataChunk = unwind ? newTailMergePDataChunk(tm, unwind) : nullptr;
750
for (DefinedImportData *s : syms) {
751
Chunk *t = newThunkChunk(s, tm);
752
auto *a = make<DelayAddressChunk>(ctx, t);
753
addresses.push_back(a);
754
thunks.push_back(t);
755
StringRef extName = s->getExternalName();
756
if (extName.empty()) {
757
names.push_back(make<OrdinalOnlyChunk>(ctx, s->getOrdinal()));
758
} else {
759
auto *c = make<HintNameChunk>(extName, 0);
760
names.push_back(make<LookupChunk>(ctx, c));
761
hintNames.push_back(c);
762
// Add a synthetic symbol for this load thunk, using the "__imp___load"
763
// prefix, in case this thunk needs to be added to the list of valid
764
// call targets for Control Flow Guard.
765
StringRef symName = saver().save("__imp___load_" + extName);
766
s->loadThunkSym =
767
cast<DefinedSynthetic>(ctx.symtab.addSynthetic(symName, t));
768
}
769
}
770
thunks.push_back(tm);
771
if (pdataChunk)
772
pdata.push_back(pdataChunk);
773
StringRef tmName =
774
saver().save("__tailMerge_" + syms[0]->getDLLName().lower());
775
ctx.symtab.addSynthetic(tmName, tm);
776
// Terminate with null values.
777
addresses.push_back(make<NullChunk>(8));
778
names.push_back(make<NullChunk>(8));
779
780
for (int i = 0, e = syms.size(); i < e; ++i)
781
syms[i]->setLocation(addresses[base + i]);
782
auto *mh = make<NullChunk>(8);
783
mh->setAlignment(8);
784
moduleHandles.push_back(mh);
785
786
// Fill the delay import table header fields.
787
dir->moduleHandle = mh;
788
dir->addressTab = addresses[base];
789
dir->nameTab = names[base];
790
dirs.push_back(dir);
791
}
792
793
if (unwind)
794
unwindinfo.push_back(unwind);
795
// Add null terminator.
796
dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry)));
797
}
798
799
Chunk *DelayLoadContents::newTailMergeChunk(Chunk *dir) {
800
switch (ctx.config.machine) {
801
case AMD64:
802
return make<TailMergeChunkX64>(dir, helper);
803
case I386:
804
return make<TailMergeChunkX86>(ctx, dir, helper);
805
case ARMNT:
806
return make<TailMergeChunkARM>(ctx, dir, helper);
807
case ARM64:
808
return make<TailMergeChunkARM64>(dir, helper);
809
default:
810
llvm_unreachable("unsupported machine type");
811
}
812
}
813
814
Chunk *DelayLoadContents::newTailMergeUnwindInfoChunk() {
815
switch (ctx.config.machine) {
816
case AMD64:
817
return make<TailMergeUnwindInfoX64>();
818
// FIXME: Add support for other architectures.
819
default:
820
return nullptr; // Just don't generate unwind info.
821
}
822
}
823
Chunk *DelayLoadContents::newTailMergePDataChunk(Chunk *tm, Chunk *unwind) {
824
switch (ctx.config.machine) {
825
case AMD64:
826
return make<TailMergePDataChunkX64>(tm, unwind);
827
// FIXME: Add support for other architectures.
828
default:
829
return nullptr; // Just don't generate unwind info.
830
}
831
}
832
833
Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *s,
834
Chunk *tailMerge) {
835
switch (ctx.config.machine) {
836
case AMD64:
837
return make<ThunkChunkX64>(s, tailMerge);
838
case I386:
839
return make<ThunkChunkX86>(ctx, s, tailMerge);
840
case ARMNT:
841
return make<ThunkChunkARM>(ctx, s, tailMerge);
842
case ARM64:
843
return make<ThunkChunkARM64>(s, tailMerge);
844
default:
845
llvm_unreachable("unsupported machine type");
846
}
847
}
848
849
EdataContents::EdataContents(COFFLinkerContext &ctx) : ctx(ctx) {
850
unsigned baseOrdinal = 1 << 16, maxOrdinal = 0;
851
for (Export &e : ctx.config.exports) {
852
baseOrdinal = std::min(baseOrdinal, (unsigned)e.ordinal);
853
maxOrdinal = std::max(maxOrdinal, (unsigned)e.ordinal);
854
}
855
// Ordinals must start at 1 as suggested in:
856
// https://learn.microsoft.com/en-us/cpp/build/reference/export-exports-a-function?view=msvc-170
857
assert(baseOrdinal >= 1);
858
859
auto *dllName = make<StringChunk>(sys::path::filename(ctx.config.outputFile));
860
auto *addressTab = make<AddressTableChunk>(ctx, baseOrdinal, maxOrdinal);
861
std::vector<Chunk *> names;
862
for (Export &e : ctx.config.exports)
863
if (!e.noname)
864
names.push_back(make<StringChunk>(e.exportName));
865
866
std::vector<Chunk *> forwards;
867
for (Export &e : ctx.config.exports) {
868
if (e.forwardTo.empty())
869
continue;
870
e.forwardChunk = make<StringChunk>(e.forwardTo);
871
forwards.push_back(e.forwardChunk);
872
}
873
874
auto *nameTab = make<NamePointersChunk>(names);
875
auto *ordinalTab = make<ExportOrdinalChunk>(ctx, baseOrdinal, names.size());
876
auto *dir =
877
make<ExportDirectoryChunk>(baseOrdinal, maxOrdinal, names.size(), dllName,
878
addressTab, nameTab, ordinalTab);
879
chunks.push_back(dir);
880
chunks.push_back(dllName);
881
chunks.push_back(addressTab);
882
chunks.push_back(nameTab);
883
chunks.push_back(ordinalTab);
884
chunks.insert(chunks.end(), names.begin(), names.end());
885
chunks.insert(chunks.end(), forwards.begin(), forwards.end());
886
}
887
888
} // namespace lld::coff
889
890