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
)
164 file
->impchkThunk
->getRVA() + file
->symtab
.ctx
.config
.imageBase
;
165 write64le(buf
, impchkVA
);
168 void getBaserels(std::vector
<Baserel
> *res
) override
{
169 if (file
->impchkThunk
)
170 res
->emplace_back(rva
, file
->symtab
.machine
);
177 static std::vector
<std::vector
<DefinedImportData
*>>
178 binImports(COFFLinkerContext
&ctx
,
179 const std::vector
<DefinedImportData
*> &imports
) {
180 // Group DLL-imported symbols by DLL name because that's how
181 // symbols are laid out in the import descriptor table.
182 auto less
= [&ctx
](const std::string
&a
, const std::string
&b
) {
183 return ctx
.config
.dllOrder
[a
] < ctx
.config
.dllOrder
[b
];
185 std::map
<std::string
, std::vector
<DefinedImportData
*>, decltype(less
)> m(
187 for (DefinedImportData
*sym
: imports
)
188 m
[sym
->getDLLName().lower()].push_back(sym
);
190 std::vector
<std::vector
<DefinedImportData
*>> v
;
192 // Sort symbols by name for each group.
193 std::vector
<DefinedImportData
*> &syms
= kv
.second
;
194 llvm::sort(syms
, [](DefinedImportData
*a
, DefinedImportData
*b
) {
195 auto getBaseName
= [](DefinedImportData
*sym
) {
196 StringRef name
= sym
->getName();
197 name
.consume_front("__imp_");
198 // Skip aux_ part of ARM64EC function symbol name.
199 if (sym
->file
->impchkThunk
)
200 name
.consume_front("aux_");
203 return getBaseName(a
) < getBaseName(b
);
205 v
.push_back(std::move(syms
));
210 // See Microsoft PE/COFF spec 4.3 for details.
212 // A chunk for the delay import descriptor table etnry.
213 class DelayDirectoryChunk
: public NonSectionChunk
{
215 explicit DelayDirectoryChunk(Chunk
*n
) : dllName(n
) { setAlignment(4); }
217 size_t getSize() const override
{
218 return sizeof(delay_import_directory_table_entry
);
221 void writeTo(uint8_t *buf
) const override
{
222 memset(buf
, 0, getSize());
224 auto *e
= (delay_import_directory_table_entry
*)(buf
);
226 e
->Name
= dllName
->getRVA();
227 e
->ModuleHandle
= moduleHandle
->getRVA();
228 e
->DelayImportAddressTable
= addressTab
->getRVA();
229 e
->DelayImportNameTable
= nameTab
->getRVA();
238 // Initial contents for delay-loaded functions.
239 // This code calls __delayLoadHelper2 function to resolve a symbol
240 // which then overwrites its jump table slot with the result
241 // for subsequent function calls.
242 static const uint8_t thunkX64
[] = {
243 0x48, 0x8D, 0x05, 0, 0, 0, 0, // lea rax, [__imp_<FUNCNAME>]
244 0xE9, 0, 0, 0, 0, // jmp __tailMerge_<lib>
247 static const uint8_t tailMergeX64
[] = {
250 0x41, 0x50, // push r8
251 0x41, 0x51, // push r9
252 0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h
253 0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0
254 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1
255 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2
256 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3
257 0x48, 0x8B, 0xD0, // mov rdx, rax
258 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...]
259 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2
260 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp]
261 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h]
262 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h]
263 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h]
264 0x48, 0x83, 0xC4, 0x48, // add rsp, 48h
265 0x41, 0x59, // pop r9
266 0x41, 0x58, // pop r8
269 0xFF, 0xE0, // jmp rax
272 static const uint8_t tailMergeUnwindInfoX64
[] = {
273 0x01, // Version=1, Flags=UNW_FLAG_NHANDLER
274 0x0a, // Size of prolog
275 0x05, // Count of unwind codes
276 0x00, // No frame register
277 0x0a, 0x82, // Offset 0xa: UWOP_ALLOC_SMALL(0x48)
278 0x06, 0x02, // Offset 6: UWOP_ALLOC_SMALL(8)
279 0x04, 0x02, // Offset 4: UWOP_ALLOC_SMALL(8)
280 0x02, 0x02, // Offset 2: UWOP_ALLOC_SMALL(8)
281 0x01, 0x02, // Offset 1: UWOP_ALLOC_SMALL(8)
282 0x00, 0x00 // Padding to align on 32-bits
285 static const uint8_t thunkX86
[] = {
286 0xB8, 0, 0, 0, 0, // mov eax, offset ___imp__<FUNCNAME>
287 0xE9, 0, 0, 0, 0, // jmp __tailMerge_<lib>
290 static const uint8_t tailMergeX86
[] = {
294 0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR_<DLLNAME>_dll
295 0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8
298 0xFF, 0xE0, // jmp eax
301 static const uint8_t thunkARM
[] = {
302 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 __imp_<FUNCNAME>
303 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 __imp_<FUNCNAME>
304 0x00, 0xf0, 0x00, 0xb8, // b.w __tailMerge_<lib>
307 static const uint8_t tailMergeARM
[] = {
308 0x2d, 0xe9, 0x0f, 0x48, // push.w {r0, r1, r2, r3, r11, lr}
309 0x0d, 0xf2, 0x10, 0x0b, // addw r11, sp, #16
310 0x2d, 0xed, 0x10, 0x0b, // vpush {d0, d1, d2, d3, d4, d5, d6, d7}
311 0x61, 0x46, // mov r1, ip
312 0x40, 0xf2, 0x00, 0x00, // mov.w r0, #0 DELAY_IMPORT_DESCRIPTOR
313 0xc0, 0xf2, 0x00, 0x00, // mov.t r0, #0 DELAY_IMPORT_DESCRIPTOR
314 0x00, 0xf0, 0x00, 0xd0, // bl #0 __delayLoadHelper2
315 0x84, 0x46, // mov ip, r0
316 0xbd, 0xec, 0x10, 0x0b, // vpop {d0, d1, d2, d3, d4, d5, d6, d7}
317 0xbd, 0xe8, 0x0f, 0x48, // pop.w {r0, r1, r2, r3, r11, lr}
321 static const uint8_t thunkARM64
[] = {
322 0x11, 0x00, 0x00, 0x90, // adrp x17, #0 __imp_<FUNCNAME>
323 0x31, 0x02, 0x00, 0x91, // add x17, x17, #0 :lo12:__imp_<FUNCNAME>
324 0x00, 0x00, 0x00, 0x14, // b __tailMerge_<lib>
327 static const uint8_t tailMergeARM64
[] = {
328 0xfd, 0x7b, 0xb3, 0xa9, // stp x29, x30, [sp, #-208]!
329 0xfd, 0x03, 0x00, 0x91, // mov x29, sp
330 0xe0, 0x07, 0x01, 0xa9, // stp x0, x1, [sp, #16]
331 0xe2, 0x0f, 0x02, 0xa9, // stp x2, x3, [sp, #32]
332 0xe4, 0x17, 0x03, 0xa9, // stp x4, x5, [sp, #48]
333 0xe6, 0x1f, 0x04, 0xa9, // stp x6, x7, [sp, #64]
334 0xe0, 0x87, 0x02, 0xad, // stp q0, q1, [sp, #80]
335 0xe2, 0x8f, 0x03, 0xad, // stp q2, q3, [sp, #112]
336 0xe4, 0x97, 0x04, 0xad, // stp q4, q5, [sp, #144]
337 0xe6, 0x9f, 0x05, 0xad, // stp q6, q7, [sp, #176]
338 0xe1, 0x03, 0x11, 0xaa, // mov x1, x17
339 0x00, 0x00, 0x00, 0x90, // adrp x0, #0 DELAY_IMPORT_DESCRIPTOR
340 0x00, 0x00, 0x00, 0x91, // add x0, x0, #0 :lo12:DELAY_IMPORT_DESCRIPTOR
341 0x00, 0x00, 0x00, 0x94, // bl #0 __delayLoadHelper2
342 0xf0, 0x03, 0x00, 0xaa, // mov x16, x0
343 0xe6, 0x9f, 0x45, 0xad, // ldp q6, q7, [sp, #176]
344 0xe4, 0x97, 0x44, 0xad, // ldp q4, q5, [sp, #144]
345 0xe2, 0x8f, 0x43, 0xad, // ldp q2, q3, [sp, #112]
346 0xe0, 0x87, 0x42, 0xad, // ldp q0, q1, [sp, #80]
347 0xe6, 0x1f, 0x44, 0xa9, // ldp x6, x7, [sp, #64]
348 0xe4, 0x17, 0x43, 0xa9, // ldp x4, x5, [sp, #48]
349 0xe2, 0x0f, 0x42, 0xa9, // ldp x2, x3, [sp, #32]
350 0xe0, 0x07, 0x41, 0xa9, // ldp x0, x1, [sp, #16]
351 0xfd, 0x7b, 0xcd, 0xa8, // ldp x29, x30, [sp], #208
352 0x00, 0x02, 0x1f, 0xd6, // br x16
355 // A chunk for the delay import thunk.
356 class ThunkChunkX64
: public NonSectionCodeChunk
{
358 ThunkChunkX64(Defined
*i
, Chunk
*tm
) : imp(i
), tailMerge(tm
) {}
360 size_t getSize() const override
{ return sizeof(thunkX64
); }
361 MachineTypes
getMachine() const override
{ return AMD64
; }
363 void writeTo(uint8_t *buf
) const override
{
364 memcpy(buf
, thunkX64
, sizeof(thunkX64
));
365 write32le(buf
+ 3, imp
->getRVA() - rva
- 7);
366 write32le(buf
+ 8, tailMerge
->getRVA() - rva
- 12);
369 Defined
*imp
= nullptr;
370 Chunk
*tailMerge
= nullptr;
373 class TailMergeChunkX64
: public NonSectionCodeChunk
{
375 TailMergeChunkX64(Chunk
*d
, Defined
*h
) : desc(d
), helper(h
) {}
377 size_t getSize() const override
{ return sizeof(tailMergeX64
); }
378 MachineTypes
getMachine() const override
{ return AMD64
; }
380 void writeTo(uint8_t *buf
) const override
{
381 memcpy(buf
, tailMergeX64
, sizeof(tailMergeX64
));
382 write32le(buf
+ 39, desc
->getRVA() - rva
- 43);
383 write32le(buf
+ 44, helper
->getRVA() - rva
- 48);
386 Chunk
*desc
= nullptr;
387 Defined
*helper
= nullptr;
390 class TailMergePDataChunkX64
: public NonSectionChunk
{
392 TailMergePDataChunkX64(Chunk
*tm
, Chunk
*unwind
) : tm(tm
), unwind(unwind
) {
394 // https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-runtime_function
398 size_t getSize() const override
{ return 3 * sizeof(uint32_t); }
399 MachineTypes
getMachine() const override
{ return AMD64
; }
401 void writeTo(uint8_t *buf
) const override
{
402 write32le(buf
+ 0, tm
->getRVA()); // TailMergeChunk start RVA
403 write32le(buf
+ 4, tm
->getRVA() + tm
->getSize()); // TailMergeChunk stop RVA
404 write32le(buf
+ 8, unwind
->getRVA()); // UnwindInfo RVA
408 Chunk
*unwind
= nullptr;
411 class TailMergeUnwindInfoX64
: public NonSectionChunk
{
413 TailMergeUnwindInfoX64() {
415 // https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_info
419 size_t getSize() const override
{ return sizeof(tailMergeUnwindInfoX64
); }
420 MachineTypes
getMachine() const override
{ return AMD64
; }
422 void writeTo(uint8_t *buf
) const override
{
423 memcpy(buf
, tailMergeUnwindInfoX64
, sizeof(tailMergeUnwindInfoX64
));
427 class ThunkChunkX86
: public NonSectionCodeChunk
{
429 ThunkChunkX86(COFFLinkerContext
&ctx
, Defined
*i
, Chunk
*tm
)
430 : imp(i
), tailMerge(tm
), ctx(ctx
) {}
432 size_t getSize() const override
{ return sizeof(thunkX86
); }
433 MachineTypes
getMachine() const override
{ return I386
; }
435 void writeTo(uint8_t *buf
) const override
{
436 memcpy(buf
, thunkX86
, sizeof(thunkX86
));
437 write32le(buf
+ 1, imp
->getRVA() + ctx
.config
.imageBase
);
438 write32le(buf
+ 6, tailMerge
->getRVA() - rva
- 10);
441 void getBaserels(std::vector
<Baserel
> *res
) override
{
442 res
->emplace_back(rva
+ 1, ctx
.config
.machine
);
445 Defined
*imp
= nullptr;
446 Chunk
*tailMerge
= nullptr;
449 const COFFLinkerContext
&ctx
;
452 class TailMergeChunkX86
: public NonSectionCodeChunk
{
454 TailMergeChunkX86(COFFLinkerContext
&ctx
, Chunk
*d
, Defined
*h
)
455 : desc(d
), helper(h
), ctx(ctx
) {}
457 size_t getSize() const override
{ return sizeof(tailMergeX86
); }
458 MachineTypes
getMachine() const override
{ return I386
; }
460 void writeTo(uint8_t *buf
) const override
{
461 memcpy(buf
, tailMergeX86
, sizeof(tailMergeX86
));
462 write32le(buf
+ 4, desc
->getRVA() + ctx
.config
.imageBase
);
463 write32le(buf
+ 9, helper
->getRVA() - rva
- 13);
466 void getBaserels(std::vector
<Baserel
> *res
) override
{
467 res
->emplace_back(rva
+ 4, ctx
.config
.machine
);
470 Chunk
*desc
= nullptr;
471 Defined
*helper
= nullptr;
474 const COFFLinkerContext
&ctx
;
477 class ThunkChunkARM
: public NonSectionCodeChunk
{
479 ThunkChunkARM(COFFLinkerContext
&ctx
, Defined
*i
, Chunk
*tm
)
480 : imp(i
), tailMerge(tm
), ctx(ctx
) {
484 size_t getSize() const override
{ return sizeof(thunkARM
); }
485 MachineTypes
getMachine() const override
{ return ARMNT
; }
487 void writeTo(uint8_t *buf
) const override
{
488 memcpy(buf
, thunkARM
, sizeof(thunkARM
));
489 applyMOV32T(buf
+ 0, imp
->getRVA() + ctx
.config
.imageBase
);
490 applyBranch24T(buf
+ 8, tailMerge
->getRVA() - rva
- 12);
493 void getBaserels(std::vector
<Baserel
> *res
) override
{
494 res
->emplace_back(rva
+ 0, IMAGE_REL_BASED_ARM_MOV32T
);
497 Defined
*imp
= nullptr;
498 Chunk
*tailMerge
= nullptr;
501 const COFFLinkerContext
&ctx
;
504 class TailMergeChunkARM
: public NonSectionCodeChunk
{
506 TailMergeChunkARM(COFFLinkerContext
&ctx
, Chunk
*d
, Defined
*h
)
507 : desc(d
), helper(h
), ctx(ctx
) {
511 size_t getSize() const override
{ return sizeof(tailMergeARM
); }
512 MachineTypes
getMachine() const override
{ return ARMNT
; }
514 void writeTo(uint8_t *buf
) const override
{
515 memcpy(buf
, tailMergeARM
, sizeof(tailMergeARM
));
516 applyMOV32T(buf
+ 14, desc
->getRVA() + ctx
.config
.imageBase
);
517 applyBranch24T(buf
+ 22, helper
->getRVA() - rva
- 26);
520 void getBaserels(std::vector
<Baserel
> *res
) override
{
521 res
->emplace_back(rva
+ 14, IMAGE_REL_BASED_ARM_MOV32T
);
524 Chunk
*desc
= nullptr;
525 Defined
*helper
= nullptr;
528 const COFFLinkerContext
&ctx
;
531 class ThunkChunkARM64
: public NonSectionCodeChunk
{
533 ThunkChunkARM64(Defined
*i
, Chunk
*tm
) : imp(i
), tailMerge(tm
) {
537 size_t getSize() const override
{ return sizeof(thunkARM64
); }
538 MachineTypes
getMachine() const override
{ return ARM64
; }
540 void writeTo(uint8_t *buf
) const override
{
541 memcpy(buf
, thunkARM64
, sizeof(thunkARM64
));
542 applyArm64Addr(buf
+ 0, imp
->getRVA(), rva
+ 0, 12);
543 applyArm64Imm(buf
+ 4, imp
->getRVA() & 0xfff, 0);
544 applyArm64Branch26(buf
+ 8, tailMerge
->getRVA() - rva
- 8);
547 Defined
*imp
= nullptr;
548 Chunk
*tailMerge
= nullptr;
551 class TailMergeChunkARM64
: public NonSectionCodeChunk
{
553 TailMergeChunkARM64(Chunk
*d
, Defined
*h
) : desc(d
), helper(h
) {
557 size_t getSize() const override
{ return sizeof(tailMergeARM64
); }
558 MachineTypes
getMachine() const override
{ return ARM64
; }
560 void writeTo(uint8_t *buf
) const override
{
561 memcpy(buf
, tailMergeARM64
, sizeof(tailMergeARM64
));
562 applyArm64Addr(buf
+ 44, desc
->getRVA(), rva
+ 44, 12);
563 applyArm64Imm(buf
+ 48, desc
->getRVA() & 0xfff, 0);
564 applyArm64Branch26(buf
+ 52, helper
->getRVA() - rva
- 52);
567 Chunk
*desc
= nullptr;
568 Defined
*helper
= nullptr;
571 // A chunk for the import descriptor table.
572 class DelayAddressChunk
: public NonSectionChunk
{
574 explicit DelayAddressChunk(COFFLinkerContext
&ctx
, Chunk
*c
)
575 : thunk(c
), ctx(ctx
) {
576 setAlignment(ctx
.config
.wordsize
);
578 size_t getSize() const override
{ return ctx
.config
.wordsize
; }
580 void writeTo(uint8_t *buf
) const override
{
581 if (ctx
.config
.is64()) {
582 write64le(buf
, thunk
->getRVA() + ctx
.config
.imageBase
);
585 // Pointer to thumb code must have the LSB set, so adjust it.
586 if (ctx
.config
.machine
== ARMNT
)
588 write32le(buf
, (thunk
->getRVA() + ctx
.config
.imageBase
) | bit
);
592 void getBaserels(std::vector
<Baserel
> *res
) override
{
593 res
->emplace_back(rva
, ctx
.config
.machine
);
599 const COFFLinkerContext
&ctx
;
603 // Read Microsoft PE/COFF spec 5.3 for details.
605 // A chunk for the export descriptor table.
606 class ExportDirectoryChunk
: public NonSectionChunk
{
608 ExportDirectoryChunk(int baseOrdinal
, int maxOrdinal
, int nameTabSize
,
609 Chunk
*d
, Chunk
*a
, Chunk
*n
, Chunk
*o
)
610 : baseOrdinal(baseOrdinal
), maxOrdinal(maxOrdinal
),
611 nameTabSize(nameTabSize
), dllName(d
), addressTab(a
), nameTab(n
),
614 size_t getSize() const override
{
615 return sizeof(export_directory_table_entry
);
618 void writeTo(uint8_t *buf
) const override
{
619 memset(buf
, 0, getSize());
621 auto *e
= (export_directory_table_entry
*)(buf
);
622 e
->NameRVA
= dllName
->getRVA();
623 e
->OrdinalBase
= baseOrdinal
;
624 e
->AddressTableEntries
= (maxOrdinal
- baseOrdinal
) + 1;
625 e
->NumberOfNamePointers
= nameTabSize
;
626 e
->ExportAddressTableRVA
= addressTab
->getRVA();
627 e
->NamePointerRVA
= nameTab
->getRVA();
628 e
->OrdinalTableRVA
= ordinalTab
->getRVA();
631 uint16_t baseOrdinal
;
633 uint16_t nameTabSize
;
640 class AddressTableChunk
: public NonSectionChunk
{
642 explicit AddressTableChunk(COFFLinkerContext
&ctx
, size_t baseOrdinal
,
644 : baseOrdinal(baseOrdinal
), size((maxOrdinal
- baseOrdinal
) + 1),
646 size_t getSize() const override
{ return size
* 4; }
648 void writeTo(uint8_t *buf
) const override
{
649 memset(buf
, 0, getSize());
651 for (const Export
&e
: ctx
.config
.exports
) {
652 assert(e
.ordinal
>= baseOrdinal
&& "Export symbol has invalid ordinal");
653 // Subtract the OrdinalBase to get the index.
654 uint8_t *p
= buf
+ (e
.ordinal
- baseOrdinal
) * 4;
656 // Pointer to thumb code must have the LSB set, so adjust it.
657 if (ctx
.config
.machine
== ARMNT
&& !e
.data
)
659 if (e
.forwardChunk
) {
660 write32le(p
, e
.forwardChunk
->getRVA() | bit
);
662 assert(cast
<Defined
>(e
.sym
)->getRVA() != 0 &&
663 "Exported symbol unmapped");
664 write32le(p
, cast
<Defined
>(e
.sym
)->getRVA() | bit
);
672 const COFFLinkerContext
&ctx
;
675 class NamePointersChunk
: public NonSectionChunk
{
677 explicit NamePointersChunk(std::vector
<Chunk
*> &v
) : chunks(v
) {}
678 size_t getSize() const override
{ return chunks
.size() * 4; }
680 void writeTo(uint8_t *buf
) const override
{
681 for (Chunk
*c
: chunks
) {
682 write32le(buf
, c
->getRVA());
688 std::vector
<Chunk
*> chunks
;
691 class ExportOrdinalChunk
: public NonSectionChunk
{
693 explicit ExportOrdinalChunk(const COFFLinkerContext
&ctx
, size_t baseOrdinal
,
695 : baseOrdinal(baseOrdinal
), size(tableSize
), ctx(ctx
) {}
696 size_t getSize() const override
{ return size
* 2; }
698 void writeTo(uint8_t *buf
) const override
{
699 for (const Export
&e
: ctx
.config
.exports
) {
702 assert(e
.ordinal
>= baseOrdinal
&& "Export symbol has invalid ordinal");
703 // This table stores unbiased indices, so subtract OrdinalBase.
704 write16le(buf
, e
.ordinal
- baseOrdinal
);
712 const COFFLinkerContext
&ctx
;
715 } // anonymous namespace
717 void IdataContents::create(COFFLinkerContext
&ctx
) {
718 std::vector
<std::vector
<DefinedImportData
*>> v
= binImports(ctx
, imports
);
720 // Create .idata contents for each DLL.
721 for (std::vector
<DefinedImportData
*> &syms
: v
) {
722 // Create lookup and address tables. If they have external names,
723 // we need to create hintName chunks to store the names.
724 // If they don't (if they are import-by-ordinals), we store only
725 // ordinal values to the table.
726 size_t base
= lookups
.size();
727 for (DefinedImportData
*s
: syms
) {
728 uint16_t ord
= s
->getOrdinal();
729 if (s
->getExternalName().empty()) {
730 lookups
.push_back(make
<OrdinalOnlyChunk
>(ctx
, ord
));
731 addresses
.push_back(make
<OrdinalOnlyChunk
>(ctx
, ord
));
733 auto *c
= make
<HintNameChunk
>(s
->getExternalName(), ord
);
734 lookups
.push_back(make
<LookupChunk
>(ctx
, c
));
735 addresses
.push_back(make
<LookupChunk
>(ctx
, c
));
739 if (s
->file
->impECSym
) {
740 auto chunk
= make
<AuxImportChunk
>(s
->file
);
741 auxIat
.push_back(chunk
);
742 s
->file
->impECSym
->setLocation(chunk
);
744 chunk
= make
<AuxImportChunk
>(s
->file
);
745 auxIatCopy
.push_back(chunk
);
746 s
->file
->auxImpCopySym
->setLocation(chunk
);
749 // Terminate with null values.
750 lookups
.push_back(make
<NullChunk
>(ctx
));
751 addresses
.push_back(make
<NullChunk
>(ctx
));
752 if (ctx
.config
.machine
== ARM64EC
) {
753 auxIat
.push_back(make
<NullChunk
>(ctx
));
754 auxIatCopy
.push_back(make
<NullChunk
>(ctx
));
757 for (int i
= 0, e
= syms
.size(); i
< e
; ++i
)
758 syms
[i
]->setLocation(addresses
[base
+ i
]);
760 // Create the import table header.
761 dllNames
.push_back(make
<StringChunk
>(syms
[0]->getDLLName()));
762 auto *dir
= make
<ImportDirectoryChunk
>(dllNames
.back());
763 dir
->lookupTab
= lookups
[base
];
764 dir
->addressTab
= addresses
[base
];
767 // Add null terminator.
768 dirs
.push_back(make
<NullChunk
>(sizeof(ImportDirectoryTableEntry
), 4));
771 std::vector
<Chunk
*> DelayLoadContents::getChunks() {
772 std::vector
<Chunk
*> v
;
773 v
.insert(v
.end(), dirs
.begin(), dirs
.end());
774 v
.insert(v
.end(), names
.begin(), names
.end());
775 v
.insert(v
.end(), hintNames
.begin(), hintNames
.end());
776 v
.insert(v
.end(), dllNames
.begin(), dllNames
.end());
780 std::vector
<Chunk
*> DelayLoadContents::getDataChunks() {
781 std::vector
<Chunk
*> v
;
782 v
.insert(v
.end(), moduleHandles
.begin(), moduleHandles
.end());
783 v
.insert(v
.end(), addresses
.begin(), addresses
.end());
787 uint64_t DelayLoadContents::getDirSize() {
788 return dirs
.size() * sizeof(delay_import_directory_table_entry
);
791 void DelayLoadContents::create(Defined
*h
) {
793 std::vector
<std::vector
<DefinedImportData
*>> v
= binImports(ctx
, imports
);
795 Chunk
*unwind
= newTailMergeUnwindInfoChunk();
797 // Create .didat contents for each DLL.
798 for (std::vector
<DefinedImportData
*> &syms
: v
) {
799 // Create the delay import table header.
800 dllNames
.push_back(make
<StringChunk
>(syms
[0]->getDLLName()));
801 auto *dir
= make
<DelayDirectoryChunk
>(dllNames
.back());
803 size_t base
= addresses
.size();
804 Chunk
*tm
= newTailMergeChunk(dir
);
805 Chunk
*pdataChunk
= unwind
? newTailMergePDataChunk(tm
, unwind
) : nullptr;
806 for (DefinedImportData
*s
: syms
) {
807 Chunk
*t
= newThunkChunk(s
, tm
);
808 auto *a
= make
<DelayAddressChunk
>(ctx
, t
);
809 addresses
.push_back(a
);
811 StringRef extName
= s
->getExternalName();
812 if (extName
.empty()) {
813 names
.push_back(make
<OrdinalOnlyChunk
>(ctx
, s
->getOrdinal()));
815 auto *c
= make
<HintNameChunk
>(extName
, 0);
816 names
.push_back(make
<LookupChunk
>(ctx
, c
));
817 hintNames
.push_back(c
);
818 // Add a synthetic symbol for this load thunk, using the "__imp___load"
819 // prefix, in case this thunk needs to be added to the list of valid
820 // call targets for Control Flow Guard.
821 StringRef symName
= saver().save("__imp___load_" + extName
);
823 cast
<DefinedSynthetic
>(ctx
.symtab
.addSynthetic(symName
, t
));
826 if (s
->file
->impECSym
) {
827 auto chunk
= make
<AuxImportChunk
>(s
->file
);
828 auxIat
.push_back(chunk
);
829 s
->file
->impECSym
->setLocation(chunk
);
831 chunk
= make
<AuxImportChunk
>(s
->file
);
832 auxIatCopy
.push_back(chunk
);
833 s
->file
->auxImpCopySym
->setLocation(chunk
);
836 thunks
.push_back(tm
);
838 pdata
.push_back(pdataChunk
);
840 saver().save("__tailMerge_" + syms
[0]->getDLLName().lower());
841 ctx
.symtab
.addSynthetic(tmName
, tm
);
842 // Terminate with null values.
843 addresses
.push_back(make
<NullChunk
>(ctx
, 8));
844 names
.push_back(make
<NullChunk
>(ctx
, 8));
845 if (ctx
.config
.machine
== ARM64EC
) {
846 auxIat
.push_back(make
<NullChunk
>(ctx
, 8));
847 auxIatCopy
.push_back(make
<NullChunk
>(ctx
, 8));
850 for (int i
= 0, e
= syms
.size(); i
< e
; ++i
)
851 syms
[i
]->setLocation(addresses
[base
+ i
]);
852 auto *mh
= make
<NullChunk
>(8, 8);
853 moduleHandles
.push_back(mh
);
855 // Fill the delay import table header fields.
856 dir
->moduleHandle
= mh
;
857 dir
->addressTab
= addresses
[base
];
858 dir
->nameTab
= names
[base
];
863 unwindinfo
.push_back(unwind
);
864 // Add null terminator.
866 make
<NullChunk
>(sizeof(delay_import_directory_table_entry
), 4));
869 Chunk
*DelayLoadContents::newTailMergeChunk(Chunk
*dir
) {
870 switch (ctx
.config
.machine
) {
873 return make
<TailMergeChunkX64
>(dir
, helper
);
875 return make
<TailMergeChunkX86
>(ctx
, dir
, helper
);
877 return make
<TailMergeChunkARM
>(ctx
, dir
, helper
);
879 return make
<TailMergeChunkARM64
>(dir
, helper
);
881 llvm_unreachable("unsupported machine type");
885 Chunk
*DelayLoadContents::newTailMergeUnwindInfoChunk() {
886 switch (ctx
.config
.machine
) {
889 return make
<TailMergeUnwindInfoX64
>();
890 // FIXME: Add support for other architectures.
892 return nullptr; // Just don't generate unwind info.
895 Chunk
*DelayLoadContents::newTailMergePDataChunk(Chunk
*tm
, Chunk
*unwind
) {
896 switch (ctx
.config
.machine
) {
899 return make
<TailMergePDataChunkX64
>(tm
, unwind
);
900 // FIXME: Add support for other architectures.
902 return nullptr; // Just don't generate unwind info.
906 Chunk
*DelayLoadContents::newThunkChunk(DefinedImportData
*s
,
908 switch (ctx
.config
.machine
) {
911 return make
<ThunkChunkX64
>(s
, tailMerge
);
913 return make
<ThunkChunkX86
>(ctx
, s
, tailMerge
);
915 return make
<ThunkChunkARM
>(ctx
, s
, tailMerge
);
917 return make
<ThunkChunkARM64
>(s
, tailMerge
);
919 llvm_unreachable("unsupported machine type");
923 EdataContents::EdataContents(COFFLinkerContext
&ctx
) : ctx(ctx
) {
924 unsigned baseOrdinal
= 1 << 16, maxOrdinal
= 0;
925 for (Export
&e
: ctx
.config
.exports
) {
926 baseOrdinal
= std::min(baseOrdinal
, (unsigned)e
.ordinal
);
927 maxOrdinal
= std::max(maxOrdinal
, (unsigned)e
.ordinal
);
929 // Ordinals must start at 1 as suggested in:
930 // https://learn.microsoft.com/en-us/cpp/build/reference/export-exports-a-function?view=msvc-170
931 assert(baseOrdinal
>= 1);
933 auto *dllName
= make
<StringChunk
>(sys::path::filename(ctx
.config
.outputFile
));
934 auto *addressTab
= make
<AddressTableChunk
>(ctx
, baseOrdinal
, maxOrdinal
);
935 std::vector
<Chunk
*> names
;
936 for (Export
&e
: ctx
.config
.exports
)
938 names
.push_back(make
<StringChunk
>(e
.exportName
));
940 std::vector
<Chunk
*> forwards
;
941 for (Export
&e
: ctx
.config
.exports
) {
942 if (e
.forwardTo
.empty())
944 e
.forwardChunk
= make
<StringChunk
>(e
.forwardTo
);
945 forwards
.push_back(e
.forwardChunk
);
948 auto *nameTab
= make
<NamePointersChunk
>(names
);
949 auto *ordinalTab
= make
<ExportOrdinalChunk
>(ctx
, baseOrdinal
, names
.size());
951 make
<ExportDirectoryChunk
>(baseOrdinal
, maxOrdinal
, names
.size(), dllName
,
952 addressTab
, nameTab
, ordinalTab
);
953 chunks
.push_back(dir
);
954 chunks
.push_back(dllName
);
955 chunks
.push_back(addressTab
);
956 chunks
.push_back(nameTab
);
957 chunks
.push_back(ordinalTab
);
958 chunks
.insert(chunks
.end(), names
.begin(), names
.end());
959 chunks
.insert(chunks
.end(), forwards
.begin(), forwards
.end());
962 } // namespace lld::coff