1 //===- DLL.cpp ------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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.
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.
18 //===----------------------------------------------------------------------===//
21 #include "COFFLinkerContext.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"
30 using namespace llvm::object
;
31 using namespace llvm::support::endian
;
32 using namespace llvm::COFF
;
39 // A chunk for the import descriptor table.
40 class HintNameChunk
: public NonSectionChunk
{
42 HintNameChunk(StringRef n
, uint16_t h
) : name(n
), hint(h
) {}
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);
50 void writeTo(uint8_t *buf
) const override
{
51 memset(buf
, 0, getSize());
53 memcpy(buf
+ 2, name
.data(), name
.size());
61 // A chunk for the import descriptor table.
62 class LookupChunk
: public NonSectionChunk
{
64 explicit LookupChunk(COFFLinkerContext
&ctx
, Chunk
*c
)
65 : hintName(c
), ctx(ctx
) {
66 setAlignment(ctx
.config
.wordsize
);
68 size_t getSize() const override
{ return ctx
.config
.wordsize
; }
70 void writeTo(uint8_t *buf
) const override
{
71 if (ctx
.config
.is64())
72 write64le(buf
, hintName
->getRVA());
74 write32le(buf
, hintName
->getRVA());
80 COFFLinkerContext
&ctx
;
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
{
88 explicit OrdinalOnlyChunk(COFFLinkerContext
&c
, uint16_t v
)
89 : ordinal(v
), ctx(c
) {
90 setAlignment(ctx
.config
.wordsize
);
92 size_t getSize() const override
{ return ctx
.config
.wordsize
; }
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
);
100 write32le(buf
, (1ULL << 31) | ordinal
);
107 COFFLinkerContext
&ctx
;
110 // A chunk for the import descriptor table.
111 class ImportDirectoryChunk
: public NonSectionChunk
{
113 explicit ImportDirectoryChunk(Chunk
*n
) : dllName(n
) { setAlignment(4); }
114 size_t getSize() const override
{ return sizeof(ImportDirectoryTableEntry
); }
116 void writeTo(uint8_t *buf
) const override
{
117 memset(buf
, 0, getSize());
119 auto *e
= (coff_import_directory_table_entry
*)(buf
);
120 e
->ImportLookupTableRVA
= lookupTab
->getRVA();
121 e
->NameRVA
= dllName
->getRVA();
122 e
->ImportAddressTableRVA
= addressTab
->getRVA();
130 // A chunk representing null terminator in the import table.
131 // Contents of this chunk is always null bytes.
132 class NullChunk
: public NonSectionChunk
{
134 explicit NullChunk(size_t n
, uint32_t align
) : size(n
) {
138 explicit NullChunk(COFFLinkerContext
&ctx
)
139 : NullChunk(ctx
.config
.wordsize
, ctx
.config
.wordsize
) {}
140 explicit NullChunk(COFFLinkerContext
&ctx
, size_t n
)
141 : NullChunk(n
, ctx
.config
.wordsize
) {}
142 size_t getSize() const override
{ return size
; }
144 void writeTo(uint8_t *buf
) const override
{
145 memset(buf
, 0, size
);
152 // A chunk for ARM64EC auxiliary IAT.
153 class AuxImportChunk
: public NonSectionChunk
{
155 explicit AuxImportChunk(ImportFile
*file
) : file(file
) {
156 setAlignment(sizeof(uint64_t));
158 size_t getSize() const override
{ return sizeof(uint64_t); }
160 void writeTo(uint8_t *buf
) const override
{
161 uint64_t impchkVA
= 0;
162 if (file
->impchkThunk
)
163 impchkVA
= file
->impchkThunk
->getRVA() + file
->ctx
.config
.imageBase
;
164 write64le(buf
, impchkVA
);
167 void getBaserels(std::vector
<Baserel
> *res
) override
{
168 if (file
->impchkThunk
)
169 res
->emplace_back(rva
, file
->ctx
.config
.machine
);
176 static std::vector
<std::vector
<DefinedImportData
*>>
177 binImports(COFFLinkerContext
&ctx
,
178 const std::vector
<DefinedImportData
*> &imports
) {
179 // Group DLL-imported symbols by DLL name because that's how
180 // symbols are laid out in the import descriptor table.
181 auto less
= [&ctx
](const std::string
&a
, const std::string
&b
) {
182 return ctx
.config
.dllOrder
[a
] < ctx
.config
.dllOrder
[b
];
184 std::map
<std::string
, std::vector
<DefinedImportData
*>, decltype(less
)> m(
186 for (DefinedImportData
*sym
: imports
)
187 m
[sym
->getDLLName().lower()].push_back(sym
);
189 std::vector
<std::vector
<DefinedImportData
*>> v
;
191 // Sort symbols by name for each group.
192 std::vector
<DefinedImportData
*> &syms
= kv
.second
;
193 llvm::sort(syms
, [](DefinedImportData
*a
, DefinedImportData
*b
) {
194 auto getBaseName
= [](DefinedImportData
*sym
) {
195 StringRef name
= sym
->getName();
196 name
.consume_front("__imp_");
197 // Skip aux_ part of ARM64EC function symbol name.
198 if (sym
->file
->impchkThunk
)
199 name
.consume_front("aux_");
202 return getBaseName(a
) < getBaseName(b
);
204 v
.push_back(std::move(syms
));
209 // See Microsoft PE/COFF spec 4.3 for details.
211 // A chunk for the delay import descriptor table etnry.
212 class DelayDirectoryChunk
: public NonSectionChunk
{
214 explicit DelayDirectoryChunk(Chunk
*n
) : dllName(n
) { setAlignment(4); }
216 size_t getSize() const override
{
217 return sizeof(delay_import_directory_table_entry
);
220 void writeTo(uint8_t *buf
) const override
{
221 memset(buf
, 0, getSize());
223 auto *e
= (delay_import_directory_table_entry
*)(buf
);
225 e
->Name
= dllName
->getRVA();
226 e
->ModuleHandle
= moduleHandle
->getRVA();
227 e
->DelayImportAddressTable
= addressTab
->getRVA();
228 e
->DelayImportNameTable
= nameTab
->getRVA();
237 // Initial contents for delay-loaded functions.
238 // This code calls __delayLoadHelper2 function to resolve a symbol
239 // which then overwrites its jump table slot with the result
240 // for subsequent function calls.
241 static const uint8_t thunkX64
[] = {
242 0x48, 0x8D, 0x05, 0, 0, 0, 0, // lea rax, [__imp_<FUNCNAME>]
243 0xE9, 0, 0, 0, 0, // jmp __tailMerge_<lib>
246 static const uint8_t tailMergeX64
[] = {
249 0x41, 0x50, // push r8
250 0x41, 0x51, // push r9
251 0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h
252 0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0
253 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1
254 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2
255 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3
256 0x48, 0x8B, 0xD0, // mov rdx, rax
257 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...]
258 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2
259 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp]
260 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h]
261 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h]
262 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h]
263 0x48, 0x83, 0xC4, 0x48, // add rsp, 48h
264 0x41, 0x59, // pop r9
265 0x41, 0x58, // pop r8
268 0xFF, 0xE0, // jmp rax
271 static const uint8_t tailMergeUnwindInfoX64
[] = {
272 0x01, // Version=1, Flags=UNW_FLAG_NHANDLER
273 0x0a, // Size of prolog
274 0x05, // Count of unwind codes
275 0x00, // No frame register
276 0x0a, 0x82, // Offset 0xa: UWOP_ALLOC_SMALL(0x48)
277 0x06, 0x02, // Offset 6: UWOP_ALLOC_SMALL(8)
278 0x04, 0x02, // Offset 4: UWOP_ALLOC_SMALL(8)
279 0x02, 0x02, // Offset 2: UWOP_ALLOC_SMALL(8)
280 0x01, 0x02, // Offset 1: UWOP_ALLOC_SMALL(8)
281 0x00, 0x00 // Padding to align on 32-bits
284 static const uint8_t thunkX86
[] = {
285 0xB8, 0, 0, 0, 0, // mov eax, offset ___imp__<FUNCNAME>
286 0xE9, 0, 0, 0, 0, // jmp __tailMerge_<lib>
289 static const uint8_t tailMergeX86
[] = {
293 0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR_<DLLNAME>_dll
294 0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8
297 0xFF, 0xE0, // jmp eax
300 static const uint8_t thunkARM
[] = {
301 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 __imp_<FUNCNAME>
302 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 __imp_<FUNCNAME>
303 0x00, 0xf0, 0x00, 0xb8, // b.w __tailMerge_<lib>
306 static const uint8_t tailMergeARM
[] = {
307 0x2d, 0xe9, 0x0f, 0x48, // push.w {r0, r1, r2, r3, r11, lr}
308 0x0d, 0xf2, 0x10, 0x0b, // addw r11, sp, #16
309 0x2d, 0xed, 0x10, 0x0b, // vpush {d0, d1, d2, d3, d4, d5, d6, d7}
310 0x61, 0x46, // mov r1, ip
311 0x40, 0xf2, 0x00, 0x00, // mov.w r0, #0 DELAY_IMPORT_DESCRIPTOR
312 0xc0, 0xf2, 0x00, 0x00, // mov.t r0, #0 DELAY_IMPORT_DESCRIPTOR
313 0x00, 0xf0, 0x00, 0xd0, // bl #0 __delayLoadHelper2
314 0x84, 0x46, // mov ip, r0
315 0xbd, 0xec, 0x10, 0x0b, // vpop {d0, d1, d2, d3, d4, d5, d6, d7}
316 0xbd, 0xe8, 0x0f, 0x48, // pop.w {r0, r1, r2, r3, r11, lr}
320 static const uint8_t thunkARM64
[] = {
321 0x11, 0x00, 0x00, 0x90, // adrp x17, #0 __imp_<FUNCNAME>
322 0x31, 0x02, 0x00, 0x91, // add x17, x17, #0 :lo12:__imp_<FUNCNAME>
323 0x00, 0x00, 0x00, 0x14, // b __tailMerge_<lib>
326 static const uint8_t tailMergeARM64
[] = {
327 0xfd, 0x7b, 0xb3, 0xa9, // stp x29, x30, [sp, #-208]!
328 0xfd, 0x03, 0x00, 0x91, // mov x29, sp
329 0xe0, 0x07, 0x01, 0xa9, // stp x0, x1, [sp, #16]
330 0xe2, 0x0f, 0x02, 0xa9, // stp x2, x3, [sp, #32]
331 0xe4, 0x17, 0x03, 0xa9, // stp x4, x5, [sp, #48]
332 0xe6, 0x1f, 0x04, 0xa9, // stp x6, x7, [sp, #64]
333 0xe0, 0x87, 0x02, 0xad, // stp q0, q1, [sp, #80]
334 0xe2, 0x8f, 0x03, 0xad, // stp q2, q3, [sp, #112]
335 0xe4, 0x97, 0x04, 0xad, // stp q4, q5, [sp, #144]
336 0xe6, 0x9f, 0x05, 0xad, // stp q6, q7, [sp, #176]
337 0xe1, 0x03, 0x11, 0xaa, // mov x1, x17
338 0x00, 0x00, 0x00, 0x90, // adrp x0, #0 DELAY_IMPORT_DESCRIPTOR
339 0x00, 0x00, 0x00, 0x91, // add x0, x0, #0 :lo12:DELAY_IMPORT_DESCRIPTOR
340 0x00, 0x00, 0x00, 0x94, // bl #0 __delayLoadHelper2
341 0xf0, 0x03, 0x00, 0xaa, // mov x16, x0
342 0xe6, 0x9f, 0x45, 0xad, // ldp q6, q7, [sp, #176]
343 0xe4, 0x97, 0x44, 0xad, // ldp q4, q5, [sp, #144]
344 0xe2, 0x8f, 0x43, 0xad, // ldp q2, q3, [sp, #112]
345 0xe0, 0x87, 0x42, 0xad, // ldp q0, q1, [sp, #80]
346 0xe6, 0x1f, 0x44, 0xa9, // ldp x6, x7, [sp, #64]
347 0xe4, 0x17, 0x43, 0xa9, // ldp x4, x5, [sp, #48]
348 0xe2, 0x0f, 0x42, 0xa9, // ldp x2, x3, [sp, #32]
349 0xe0, 0x07, 0x41, 0xa9, // ldp x0, x1, [sp, #16]
350 0xfd, 0x7b, 0xcd, 0xa8, // ldp x29, x30, [sp], #208
351 0x00, 0x02, 0x1f, 0xd6, // br x16
354 // A chunk for the delay import thunk.
355 class ThunkChunkX64
: public NonSectionCodeChunk
{
357 ThunkChunkX64(Defined
*i
, Chunk
*tm
) : imp(i
), tailMerge(tm
) {}
359 size_t getSize() const override
{ return sizeof(thunkX64
); }
360 MachineTypes
getMachine() const override
{ return AMD64
; }
362 void writeTo(uint8_t *buf
) const override
{
363 memcpy(buf
, thunkX64
, sizeof(thunkX64
));
364 write32le(buf
+ 3, imp
->getRVA() - rva
- 7);
365 write32le(buf
+ 8, tailMerge
->getRVA() - rva
- 12);
368 Defined
*imp
= nullptr;
369 Chunk
*tailMerge
= nullptr;
372 class TailMergeChunkX64
: public NonSectionCodeChunk
{
374 TailMergeChunkX64(Chunk
*d
, Defined
*h
) : desc(d
), helper(h
) {}
376 size_t getSize() const override
{ return sizeof(tailMergeX64
); }
377 MachineTypes
getMachine() const override
{ return AMD64
; }
379 void writeTo(uint8_t *buf
) const override
{
380 memcpy(buf
, tailMergeX64
, sizeof(tailMergeX64
));
381 write32le(buf
+ 39, desc
->getRVA() - rva
- 43);
382 write32le(buf
+ 44, helper
->getRVA() - rva
- 48);
385 Chunk
*desc
= nullptr;
386 Defined
*helper
= nullptr;
389 class TailMergePDataChunkX64
: public NonSectionChunk
{
391 TailMergePDataChunkX64(Chunk
*tm
, Chunk
*unwind
) : tm(tm
), unwind(unwind
) {
393 // https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-runtime_function
397 size_t getSize() const override
{ return 3 * sizeof(uint32_t); }
398 MachineTypes
getMachine() const override
{ return AMD64
; }
400 void writeTo(uint8_t *buf
) const override
{
401 write32le(buf
+ 0, tm
->getRVA()); // TailMergeChunk start RVA
402 write32le(buf
+ 4, tm
->getRVA() + tm
->getSize()); // TailMergeChunk stop RVA
403 write32le(buf
+ 8, unwind
->getRVA()); // UnwindInfo RVA
407 Chunk
*unwind
= nullptr;
410 class TailMergeUnwindInfoX64
: public NonSectionChunk
{
412 TailMergeUnwindInfoX64() {
414 // https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_info
418 size_t getSize() const override
{ return sizeof(tailMergeUnwindInfoX64
); }
419 MachineTypes
getMachine() const override
{ return AMD64
; }
421 void writeTo(uint8_t *buf
) const override
{
422 memcpy(buf
, tailMergeUnwindInfoX64
, sizeof(tailMergeUnwindInfoX64
));
426 class ThunkChunkX86
: public NonSectionCodeChunk
{
428 ThunkChunkX86(COFFLinkerContext
&ctx
, Defined
*i
, Chunk
*tm
)
429 : imp(i
), tailMerge(tm
), ctx(ctx
) {}
431 size_t getSize() const override
{ return sizeof(thunkX86
); }
432 MachineTypes
getMachine() const override
{ return I386
; }
434 void writeTo(uint8_t *buf
) const override
{
435 memcpy(buf
, thunkX86
, sizeof(thunkX86
));
436 write32le(buf
+ 1, imp
->getRVA() + ctx
.config
.imageBase
);
437 write32le(buf
+ 6, tailMerge
->getRVA() - rva
- 10);
440 void getBaserels(std::vector
<Baserel
> *res
) override
{
441 res
->emplace_back(rva
+ 1, ctx
.config
.machine
);
444 Defined
*imp
= nullptr;
445 Chunk
*tailMerge
= nullptr;
448 const COFFLinkerContext
&ctx
;
451 class TailMergeChunkX86
: public NonSectionCodeChunk
{
453 TailMergeChunkX86(COFFLinkerContext
&ctx
, Chunk
*d
, Defined
*h
)
454 : desc(d
), helper(h
), ctx(ctx
) {}
456 size_t getSize() const override
{ return sizeof(tailMergeX86
); }
457 MachineTypes
getMachine() const override
{ return I386
; }
459 void writeTo(uint8_t *buf
) const override
{
460 memcpy(buf
, tailMergeX86
, sizeof(tailMergeX86
));
461 write32le(buf
+ 4, desc
->getRVA() + ctx
.config
.imageBase
);
462 write32le(buf
+ 9, helper
->getRVA() - rva
- 13);
465 void getBaserels(std::vector
<Baserel
> *res
) override
{
466 res
->emplace_back(rva
+ 4, ctx
.config
.machine
);
469 Chunk
*desc
= nullptr;
470 Defined
*helper
= nullptr;
473 const COFFLinkerContext
&ctx
;
476 class ThunkChunkARM
: public NonSectionCodeChunk
{
478 ThunkChunkARM(COFFLinkerContext
&ctx
, Defined
*i
, Chunk
*tm
)
479 : imp(i
), tailMerge(tm
), ctx(ctx
) {
483 size_t getSize() const override
{ return sizeof(thunkARM
); }
484 MachineTypes
getMachine() const override
{ return ARMNT
; }
486 void writeTo(uint8_t *buf
) const override
{
487 memcpy(buf
, thunkARM
, sizeof(thunkARM
));
488 applyMOV32T(buf
+ 0, imp
->getRVA() + ctx
.config
.imageBase
);
489 applyBranch24T(buf
+ 8, tailMerge
->getRVA() - rva
- 12);
492 void getBaserels(std::vector
<Baserel
> *res
) override
{
493 res
->emplace_back(rva
+ 0, IMAGE_REL_BASED_ARM_MOV32T
);
496 Defined
*imp
= nullptr;
497 Chunk
*tailMerge
= nullptr;
500 const COFFLinkerContext
&ctx
;
503 class TailMergeChunkARM
: public NonSectionCodeChunk
{
505 TailMergeChunkARM(COFFLinkerContext
&ctx
, Chunk
*d
, Defined
*h
)
506 : desc(d
), helper(h
), ctx(ctx
) {
510 size_t getSize() const override
{ return sizeof(tailMergeARM
); }
511 MachineTypes
getMachine() const override
{ return ARMNT
; }
513 void writeTo(uint8_t *buf
) const override
{
514 memcpy(buf
, tailMergeARM
, sizeof(tailMergeARM
));
515 applyMOV32T(buf
+ 14, desc
->getRVA() + ctx
.config
.imageBase
);
516 applyBranch24T(buf
+ 22, helper
->getRVA() - rva
- 26);
519 void getBaserels(std::vector
<Baserel
> *res
) override
{
520 res
->emplace_back(rva
+ 14, IMAGE_REL_BASED_ARM_MOV32T
);
523 Chunk
*desc
= nullptr;
524 Defined
*helper
= nullptr;
527 const COFFLinkerContext
&ctx
;
530 class ThunkChunkARM64
: public NonSectionCodeChunk
{
532 ThunkChunkARM64(Defined
*i
, Chunk
*tm
) : imp(i
), tailMerge(tm
) {
536 size_t getSize() const override
{ return sizeof(thunkARM64
); }
537 MachineTypes
getMachine() const override
{ return ARM64
; }
539 void writeTo(uint8_t *buf
) const override
{
540 memcpy(buf
, thunkARM64
, sizeof(thunkARM64
));
541 applyArm64Addr(buf
+ 0, imp
->getRVA(), rva
+ 0, 12);
542 applyArm64Imm(buf
+ 4, imp
->getRVA() & 0xfff, 0);
543 applyArm64Branch26(buf
+ 8, tailMerge
->getRVA() - rva
- 8);
546 Defined
*imp
= nullptr;
547 Chunk
*tailMerge
= nullptr;
550 class TailMergeChunkARM64
: public NonSectionCodeChunk
{
552 TailMergeChunkARM64(Chunk
*d
, Defined
*h
) : desc(d
), helper(h
) {
556 size_t getSize() const override
{ return sizeof(tailMergeARM64
); }
557 MachineTypes
getMachine() const override
{ return ARM64
; }
559 void writeTo(uint8_t *buf
) const override
{
560 memcpy(buf
, tailMergeARM64
, sizeof(tailMergeARM64
));
561 applyArm64Addr(buf
+ 44, desc
->getRVA(), rva
+ 44, 12);
562 applyArm64Imm(buf
+ 48, desc
->getRVA() & 0xfff, 0);
563 applyArm64Branch26(buf
+ 52, helper
->getRVA() - rva
- 52);
566 Chunk
*desc
= nullptr;
567 Defined
*helper
= nullptr;
570 // A chunk for the import descriptor table.
571 class DelayAddressChunk
: public NonSectionChunk
{
573 explicit DelayAddressChunk(COFFLinkerContext
&ctx
, Chunk
*c
)
574 : thunk(c
), ctx(ctx
) {
575 setAlignment(ctx
.config
.wordsize
);
577 size_t getSize() const override
{ return ctx
.config
.wordsize
; }
579 void writeTo(uint8_t *buf
) const override
{
580 if (ctx
.config
.is64()) {
581 write64le(buf
, thunk
->getRVA() + ctx
.config
.imageBase
);
584 // Pointer to thumb code must have the LSB set, so adjust it.
585 if (ctx
.config
.machine
== ARMNT
)
587 write32le(buf
, (thunk
->getRVA() + ctx
.config
.imageBase
) | bit
);
591 void getBaserels(std::vector
<Baserel
> *res
) override
{
592 res
->emplace_back(rva
, ctx
.config
.machine
);
598 const COFFLinkerContext
&ctx
;
602 // Read Microsoft PE/COFF spec 5.3 for details.
604 // A chunk for the export descriptor table.
605 class ExportDirectoryChunk
: public NonSectionChunk
{
607 ExportDirectoryChunk(int baseOrdinal
, int maxOrdinal
, int nameTabSize
,
608 Chunk
*d
, Chunk
*a
, Chunk
*n
, Chunk
*o
)
609 : baseOrdinal(baseOrdinal
), maxOrdinal(maxOrdinal
),
610 nameTabSize(nameTabSize
), dllName(d
), addressTab(a
), nameTab(n
),
613 size_t getSize() const override
{
614 return sizeof(export_directory_table_entry
);
617 void writeTo(uint8_t *buf
) const override
{
618 memset(buf
, 0, getSize());
620 auto *e
= (export_directory_table_entry
*)(buf
);
621 e
->NameRVA
= dllName
->getRVA();
622 e
->OrdinalBase
= baseOrdinal
;
623 e
->AddressTableEntries
= (maxOrdinal
- baseOrdinal
) + 1;
624 e
->NumberOfNamePointers
= nameTabSize
;
625 e
->ExportAddressTableRVA
= addressTab
->getRVA();
626 e
->NamePointerRVA
= nameTab
->getRVA();
627 e
->OrdinalTableRVA
= ordinalTab
->getRVA();
630 uint16_t baseOrdinal
;
632 uint16_t nameTabSize
;
639 class AddressTableChunk
: public NonSectionChunk
{
641 explicit AddressTableChunk(COFFLinkerContext
&ctx
, size_t baseOrdinal
,
643 : baseOrdinal(baseOrdinal
), size((maxOrdinal
- baseOrdinal
) + 1),
645 size_t getSize() const override
{ return size
* 4; }
647 void writeTo(uint8_t *buf
) const override
{
648 memset(buf
, 0, getSize());
650 for (const Export
&e
: ctx
.config
.exports
) {
651 assert(e
.ordinal
>= baseOrdinal
&& "Export symbol has invalid ordinal");
652 // Subtract the OrdinalBase to get the index.
653 uint8_t *p
= buf
+ (e
.ordinal
- baseOrdinal
) * 4;
655 // Pointer to thumb code must have the LSB set, so adjust it.
656 if (ctx
.config
.machine
== ARMNT
&& !e
.data
)
658 if (e
.forwardChunk
) {
659 write32le(p
, e
.forwardChunk
->getRVA() | bit
);
661 assert(cast
<Defined
>(e
.sym
)->getRVA() != 0 &&
662 "Exported symbol unmapped");
663 write32le(p
, cast
<Defined
>(e
.sym
)->getRVA() | bit
);
671 const COFFLinkerContext
&ctx
;
674 class NamePointersChunk
: public NonSectionChunk
{
676 explicit NamePointersChunk(std::vector
<Chunk
*> &v
) : chunks(v
) {}
677 size_t getSize() const override
{ return chunks
.size() * 4; }
679 void writeTo(uint8_t *buf
) const override
{
680 for (Chunk
*c
: chunks
) {
681 write32le(buf
, c
->getRVA());
687 std::vector
<Chunk
*> chunks
;
690 class ExportOrdinalChunk
: public NonSectionChunk
{
692 explicit ExportOrdinalChunk(const COFFLinkerContext
&ctx
, size_t baseOrdinal
,
694 : baseOrdinal(baseOrdinal
), size(tableSize
), ctx(ctx
) {}
695 size_t getSize() const override
{ return size
* 2; }
697 void writeTo(uint8_t *buf
) const override
{
698 for (const Export
&e
: ctx
.config
.exports
) {
701 assert(e
.ordinal
>= baseOrdinal
&& "Export symbol has invalid ordinal");
702 // This table stores unbiased indices, so subtract OrdinalBase.
703 write16le(buf
, e
.ordinal
- baseOrdinal
);
711 const COFFLinkerContext
&ctx
;
714 } // anonymous namespace
716 void IdataContents::create(COFFLinkerContext
&ctx
) {
717 std::vector
<std::vector
<DefinedImportData
*>> v
= binImports(ctx
, imports
);
719 // Create .idata contents for each DLL.
720 for (std::vector
<DefinedImportData
*> &syms
: v
) {
721 // Create lookup and address tables. If they have external names,
722 // we need to create hintName chunks to store the names.
723 // If they don't (if they are import-by-ordinals), we store only
724 // ordinal values to the table.
725 size_t base
= lookups
.size();
726 for (DefinedImportData
*s
: syms
) {
727 uint16_t ord
= s
->getOrdinal();
728 if (s
->getExternalName().empty()) {
729 lookups
.push_back(make
<OrdinalOnlyChunk
>(ctx
, ord
));
730 addresses
.push_back(make
<OrdinalOnlyChunk
>(ctx
, ord
));
732 auto *c
= make
<HintNameChunk
>(s
->getExternalName(), ord
);
733 lookups
.push_back(make
<LookupChunk
>(ctx
, c
));
734 addresses
.push_back(make
<LookupChunk
>(ctx
, c
));
738 if (s
->file
->impECSym
) {
739 auto chunk
= make
<AuxImportChunk
>(s
->file
);
740 auxIat
.push_back(chunk
);
741 s
->file
->impECSym
->setLocation(chunk
);
743 chunk
= make
<AuxImportChunk
>(s
->file
);
744 auxIatCopy
.push_back(chunk
);
745 s
->file
->auxImpCopySym
->setLocation(chunk
);
748 // Terminate with null values.
749 lookups
.push_back(make
<NullChunk
>(ctx
));
750 addresses
.push_back(make
<NullChunk
>(ctx
));
751 if (ctx
.config
.machine
== ARM64EC
) {
752 auxIat
.push_back(make
<NullChunk
>(ctx
));
753 auxIatCopy
.push_back(make
<NullChunk
>(ctx
));
756 for (int i
= 0, e
= syms
.size(); i
< e
; ++i
)
757 syms
[i
]->setLocation(addresses
[base
+ i
]);
759 // Create the import table header.
760 dllNames
.push_back(make
<StringChunk
>(syms
[0]->getDLLName()));
761 auto *dir
= make
<ImportDirectoryChunk
>(dllNames
.back());
762 dir
->lookupTab
= lookups
[base
];
763 dir
->addressTab
= addresses
[base
];
766 // Add null terminator.
767 dirs
.push_back(make
<NullChunk
>(sizeof(ImportDirectoryTableEntry
), 4));
770 std::vector
<Chunk
*> DelayLoadContents::getChunks() {
771 std::vector
<Chunk
*> v
;
772 v
.insert(v
.end(), dirs
.begin(), dirs
.end());
773 v
.insert(v
.end(), names
.begin(), names
.end());
774 v
.insert(v
.end(), hintNames
.begin(), hintNames
.end());
775 v
.insert(v
.end(), dllNames
.begin(), dllNames
.end());
779 std::vector
<Chunk
*> DelayLoadContents::getDataChunks() {
780 std::vector
<Chunk
*> v
;
781 v
.insert(v
.end(), moduleHandles
.begin(), moduleHandles
.end());
782 v
.insert(v
.end(), addresses
.begin(), addresses
.end());
786 uint64_t DelayLoadContents::getDirSize() {
787 return dirs
.size() * sizeof(delay_import_directory_table_entry
);
790 void DelayLoadContents::create(Defined
*h
) {
792 std::vector
<std::vector
<DefinedImportData
*>> v
= binImports(ctx
, imports
);
794 Chunk
*unwind
= newTailMergeUnwindInfoChunk();
796 // Create .didat contents for each DLL.
797 for (std::vector
<DefinedImportData
*> &syms
: v
) {
798 // Create the delay import table header.
799 dllNames
.push_back(make
<StringChunk
>(syms
[0]->getDLLName()));
800 auto *dir
= make
<DelayDirectoryChunk
>(dllNames
.back());
802 size_t base
= addresses
.size();
803 Chunk
*tm
= newTailMergeChunk(dir
);
804 Chunk
*pdataChunk
= unwind
? newTailMergePDataChunk(tm
, unwind
) : nullptr;
805 for (DefinedImportData
*s
: syms
) {
806 Chunk
*t
= newThunkChunk(s
, tm
);
807 auto *a
= make
<DelayAddressChunk
>(ctx
, t
);
808 addresses
.push_back(a
);
810 StringRef extName
= s
->getExternalName();
811 if (extName
.empty()) {
812 names
.push_back(make
<OrdinalOnlyChunk
>(ctx
, s
->getOrdinal()));
814 auto *c
= make
<HintNameChunk
>(extName
, 0);
815 names
.push_back(make
<LookupChunk
>(ctx
, c
));
816 hintNames
.push_back(c
);
817 // Add a synthetic symbol for this load thunk, using the "__imp___load"
818 // prefix, in case this thunk needs to be added to the list of valid
819 // call targets for Control Flow Guard.
820 StringRef symName
= saver().save("__imp___load_" + extName
);
822 cast
<DefinedSynthetic
>(ctx
.symtab
.addSynthetic(symName
, t
));
825 if (s
->file
->impECSym
) {
826 auto chunk
= make
<AuxImportChunk
>(s
->file
);
827 auxIat
.push_back(chunk
);
828 s
->file
->impECSym
->setLocation(chunk
);
830 chunk
= make
<AuxImportChunk
>(s
->file
);
831 auxIatCopy
.push_back(chunk
);
832 s
->file
->auxImpCopySym
->setLocation(chunk
);
835 thunks
.push_back(tm
);
837 pdata
.push_back(pdataChunk
);
839 saver().save("__tailMerge_" + syms
[0]->getDLLName().lower());
840 ctx
.symtab
.addSynthetic(tmName
, tm
);
841 // Terminate with null values.
842 addresses
.push_back(make
<NullChunk
>(ctx
, 8));
843 names
.push_back(make
<NullChunk
>(ctx
, 8));
844 if (ctx
.config
.machine
== ARM64EC
) {
845 auxIat
.push_back(make
<NullChunk
>(ctx
, 8));
846 auxIatCopy
.push_back(make
<NullChunk
>(ctx
, 8));
849 for (int i
= 0, e
= syms
.size(); i
< e
; ++i
)
850 syms
[i
]->setLocation(addresses
[base
+ i
]);
851 auto *mh
= make
<NullChunk
>(8, 8);
852 moduleHandles
.push_back(mh
);
854 // Fill the delay import table header fields.
855 dir
->moduleHandle
= mh
;
856 dir
->addressTab
= addresses
[base
];
857 dir
->nameTab
= names
[base
];
862 unwindinfo
.push_back(unwind
);
863 // Add null terminator.
865 make
<NullChunk
>(sizeof(delay_import_directory_table_entry
), 4));
868 Chunk
*DelayLoadContents::newTailMergeChunk(Chunk
*dir
) {
869 switch (ctx
.config
.machine
) {
872 return make
<TailMergeChunkX64
>(dir
, helper
);
874 return make
<TailMergeChunkX86
>(ctx
, dir
, helper
);
876 return make
<TailMergeChunkARM
>(ctx
, dir
, helper
);
878 return make
<TailMergeChunkARM64
>(dir
, helper
);
880 llvm_unreachable("unsupported machine type");
884 Chunk
*DelayLoadContents::newTailMergeUnwindInfoChunk() {
885 switch (ctx
.config
.machine
) {
888 return make
<TailMergeUnwindInfoX64
>();
889 // FIXME: Add support for other architectures.
891 return nullptr; // Just don't generate unwind info.
894 Chunk
*DelayLoadContents::newTailMergePDataChunk(Chunk
*tm
, Chunk
*unwind
) {
895 switch (ctx
.config
.machine
) {
898 return make
<TailMergePDataChunkX64
>(tm
, unwind
);
899 // FIXME: Add support for other architectures.
901 return nullptr; // Just don't generate unwind info.
905 Chunk
*DelayLoadContents::newThunkChunk(DefinedImportData
*s
,
907 switch (ctx
.config
.machine
) {
910 return make
<ThunkChunkX64
>(s
, tailMerge
);
912 return make
<ThunkChunkX86
>(ctx
, s
, tailMerge
);
914 return make
<ThunkChunkARM
>(ctx
, s
, tailMerge
);
916 return make
<ThunkChunkARM64
>(s
, tailMerge
);
918 llvm_unreachable("unsupported machine type");
922 EdataContents::EdataContents(COFFLinkerContext
&ctx
) : ctx(ctx
) {
923 unsigned baseOrdinal
= 1 << 16, maxOrdinal
= 0;
924 for (Export
&e
: ctx
.config
.exports
) {
925 baseOrdinal
= std::min(baseOrdinal
, (unsigned)e
.ordinal
);
926 maxOrdinal
= std::max(maxOrdinal
, (unsigned)e
.ordinal
);
928 // Ordinals must start at 1 as suggested in:
929 // https://learn.microsoft.com/en-us/cpp/build/reference/export-exports-a-function?view=msvc-170
930 assert(baseOrdinal
>= 1);
932 auto *dllName
= make
<StringChunk
>(sys::path::filename(ctx
.config
.outputFile
));
933 auto *addressTab
= make
<AddressTableChunk
>(ctx
, baseOrdinal
, maxOrdinal
);
934 std::vector
<Chunk
*> names
;
935 for (Export
&e
: ctx
.config
.exports
)
937 names
.push_back(make
<StringChunk
>(e
.exportName
));
939 std::vector
<Chunk
*> forwards
;
940 for (Export
&e
: ctx
.config
.exports
) {
941 if (e
.forwardTo
.empty())
943 e
.forwardChunk
= make
<StringChunk
>(e
.forwardTo
);
944 forwards
.push_back(e
.forwardChunk
);
947 auto *nameTab
= make
<NamePointersChunk
>(names
);
948 auto *ordinalTab
= make
<ExportOrdinalChunk
>(ctx
, baseOrdinal
, names
.size());
950 make
<ExportDirectoryChunk
>(baseOrdinal
, maxOrdinal
, names
.size(), dllName
,
951 addressTab
, nameTab
, ordinalTab
);
952 chunks
.push_back(dir
);
953 chunks
.push_back(dllName
);
954 chunks
.push_back(addressTab
);
955 chunks
.push_back(nameTab
);
956 chunks
.push_back(ordinalTab
);
957 chunks
.insert(chunks
.end(), names
.begin(), names
.end());
958 chunks
.insert(chunks
.end(), forwards
.begin(), forwards
.end());
961 } // namespace lld::coff