xref: /freebsd/contrib/llvm-project/lld/COFF/DLL.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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:
HintNameChunk(StringRef n,uint16_t h)42   HintNameChunk(StringRef n, uint16_t h) : name(n), hint(h) {}
43 
getSize() const44   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 
writeTo(uint8_t * buf) const50   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:
LookupChunk(COFFLinkerContext & ctx,Chunk * c)64   explicit LookupChunk(COFFLinkerContext &ctx, Chunk *c)
65       : hintName(c), ctx(ctx) {
66     setAlignment(ctx.config.wordsize);
67   }
getSize() const68   size_t getSize() const override { return ctx.config.wordsize; }
69 
writeTo(uint8_t * buf) const70   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:
OrdinalOnlyChunk(COFFLinkerContext & c,uint16_t v)88   explicit OrdinalOnlyChunk(COFFLinkerContext &c, uint16_t v)
89       : ordinal(v), ctx(c) {
90     setAlignment(ctx.config.wordsize);
91   }
getSize() const92   size_t getSize() const override { return ctx.config.wordsize; }
93 
writeTo(uint8_t * buf) const94   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:
ImportDirectoryChunk(Chunk * n)113   explicit ImportDirectoryChunk(Chunk *n) : dllName(n) { setAlignment(4); }
getSize() const114   size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); }
115 
writeTo(uint8_t * buf) const116   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:
NullChunk(size_t n)134   explicit NullChunk(size_t n) : size(n) { hasData = false; }
getSize() const135   size_t getSize() const override { return size; }
136 
writeTo(uint8_t * buf) const137   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 *>>
binImports(COFFLinkerContext & ctx,const std::vector<DefinedImportData * > & imports)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:
DelayDirectoryChunk(Chunk * n)175   explicit DelayDirectoryChunk(Chunk *n) : dllName(n) { setAlignment(4); }
176 
getSize() const177   size_t getSize() const override {
178     return sizeof(delay_import_directory_table_entry);
179   }
180 
writeTo(uint8_t * buf) const181   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:
ThunkChunkX64(Defined * i,Chunk * tm)318   ThunkChunkX64(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {}
319 
getSize() const320   size_t getSize() const override { return sizeof(thunkX64); }
getMachine() const321   MachineTypes getMachine() const override { return AMD64; }
322 
writeTo(uint8_t * buf) const323   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:
TailMergeChunkX64(Chunk * d,Defined * h)335   TailMergeChunkX64(Chunk *d, Defined *h) : desc(d), helper(h) {}
336 
getSize() const337   size_t getSize() const override { return sizeof(tailMergeX64); }
getMachine() const338   MachineTypes getMachine() const override { return AMD64; }
339 
writeTo(uint8_t * buf) const340   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:
TailMergePDataChunkX64(Chunk * tm,Chunk * unwind)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 
getSize() const358   size_t getSize() const override { return 3 * sizeof(uint32_t); }
359 
writeTo(uint8_t * buf) const360   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:
TailMergeUnwindInfoX64()372   TailMergeUnwindInfoX64() {
373     // See
374     // https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_info
375     setAlignment(4);
376   }
377 
getSize() const378   size_t getSize() const override { return sizeof(tailMergeUnwindInfoX64); }
379 
writeTo(uint8_t * buf) const380   void writeTo(uint8_t *buf) const override {
381     memcpy(buf, tailMergeUnwindInfoX64, sizeof(tailMergeUnwindInfoX64));
382   }
383 };
384 
385 class ThunkChunkX86 : public NonSectionCodeChunk {
386 public:
ThunkChunkX86(COFFLinkerContext & ctx,Defined * i,Chunk * tm)387   ThunkChunkX86(COFFLinkerContext &ctx, Defined *i, Chunk *tm)
388       : imp(i), tailMerge(tm), ctx(ctx) {}
389 
getSize() const390   size_t getSize() const override { return sizeof(thunkX86); }
getMachine() const391   MachineTypes getMachine() const override { return I386; }
392 
writeTo(uint8_t * buf) const393   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 
getBaserels(std::vector<Baserel> * res)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:
TailMergeChunkX86(COFFLinkerContext & ctx,Chunk * d,Defined * h)412   TailMergeChunkX86(COFFLinkerContext &ctx, Chunk *d, Defined *h)
413       : desc(d), helper(h), ctx(ctx) {}
414 
getSize() const415   size_t getSize() const override { return sizeof(tailMergeX86); }
getMachine() const416   MachineTypes getMachine() const override { return I386; }
417 
writeTo(uint8_t * buf) const418   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 
getBaserels(std::vector<Baserel> * res)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:
ThunkChunkARM(COFFLinkerContext & ctx,Defined * i,Chunk * tm)437   ThunkChunkARM(COFFLinkerContext &ctx, Defined *i, Chunk *tm)
438       : imp(i), tailMerge(tm), ctx(ctx) {
439     setAlignment(2);
440   }
441 
getSize() const442   size_t getSize() const override { return sizeof(thunkARM); }
getMachine() const443   MachineTypes getMachine() const override { return ARMNT; }
444 
writeTo(uint8_t * buf) const445   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 
getBaserels(std::vector<Baserel> * res)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:
TailMergeChunkARM(COFFLinkerContext & ctx,Chunk * d,Defined * h)464   TailMergeChunkARM(COFFLinkerContext &ctx, Chunk *d, Defined *h)
465       : desc(d), helper(h), ctx(ctx) {
466     setAlignment(2);
467   }
468 
getSize() const469   size_t getSize() const override { return sizeof(tailMergeARM); }
getMachine() const470   MachineTypes getMachine() const override { return ARMNT; }
471 
writeTo(uint8_t * buf) const472   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 
getBaserels(std::vector<Baserel> * res)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:
ThunkChunkARM64(Defined * i,Chunk * tm)491   ThunkChunkARM64(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {
492     setAlignment(4);
493   }
494 
getSize() const495   size_t getSize() const override { return sizeof(thunkARM64); }
getMachine() const496   MachineTypes getMachine() const override { return ARM64; }
497 
writeTo(uint8_t * buf) const498   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:
TailMergeChunkARM64(Chunk * d,Defined * h)511   TailMergeChunkARM64(Chunk *d, Defined *h) : desc(d), helper(h) {
512     setAlignment(4);
513   }
514 
getSize() const515   size_t getSize() const override { return sizeof(tailMergeARM64); }
getMachine() const516   MachineTypes getMachine() const override { return ARM64; }
517 
writeTo(uint8_t * buf) const518   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:
DelayAddressChunk(COFFLinkerContext & ctx,Chunk * c)532   explicit DelayAddressChunk(COFFLinkerContext &ctx, Chunk *c)
533       : thunk(c), ctx(ctx) {
534     setAlignment(ctx.config.wordsize);
535   }
getSize() const536   size_t getSize() const override { return ctx.config.wordsize; }
537 
writeTo(uint8_t * buf) const538   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 
getBaserels(std::vector<Baserel> * res)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:
ExportDirectoryChunk(int baseOrdinal,int maxOrdinal,int nameTabSize,Chunk * d,Chunk * a,Chunk * n,Chunk * o)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 
getSize() const572   size_t getSize() const override {
573     return sizeof(export_directory_table_entry);
574   }
575 
writeTo(uint8_t * buf) const576   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:
AddressTableChunk(COFFLinkerContext & ctx,size_t baseOrdinal,size_t maxOrdinal)600   explicit AddressTableChunk(COFFLinkerContext &ctx, size_t baseOrdinal,
601                              size_t maxOrdinal)
602       : baseOrdinal(baseOrdinal), size((maxOrdinal - baseOrdinal) + 1),
603         ctx(ctx) {}
getSize() const604   size_t getSize() const override { return size * 4; }
605 
writeTo(uint8_t * buf) const606   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:
NamePointersChunk(std::vector<Chunk * > & v)635   explicit NamePointersChunk(std::vector<Chunk *> &v) : chunks(v) {}
getSize() const636   size_t getSize() const override { return chunks.size() * 4; }
637 
writeTo(uint8_t * buf) const638   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:
ExportOrdinalChunk(const COFFLinkerContext & ctx,size_t baseOrdinal,size_t tableSize)651   explicit ExportOrdinalChunk(const COFFLinkerContext &ctx, size_t baseOrdinal,
652                               size_t tableSize)
653       : baseOrdinal(baseOrdinal), size(tableSize), ctx(ctx) {}
getSize() const654   size_t getSize() const override { return size * 2; }
655 
writeTo(uint8_t * buf) const656   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 
create(COFFLinkerContext & ctx)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 
getChunks()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 
getDataChunks()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 
getDirSize()731 uint64_t DelayLoadContents::getDirSize() {
732   return dirs.size() * sizeof(delay_import_directory_table_entry);
733 }
734 
create(Defined * h)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 
newTailMergeChunk(Chunk * dir)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 
newTailMergeUnwindInfoChunk()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 }
newTailMergePDataChunk(Chunk * tm,Chunk * unwind)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 
newThunkChunk(DefinedImportData * s,Chunk * tailMerge)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 
EdataContents(COFFLinkerContext & ctx)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