xref: /llvm-project-15.0.7/lld/COFF/DLL.cpp (revision e993a16d)
1 //===- DLL.cpp ------------------------------------------------------------===//
2 //
3 //                             The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines various types of chunks for the DLL import or export
11 // descriptor tables. They are inherently Windows-specific.
12 // You need to read Microsoft PE/COFF spec to understand details
13 // about the data structures.
14 //
15 // If you are not particularly interested in linking against Windows
16 // DLL, you can skip this file, and you should still be able to
17 // understand the rest of the linker.
18 //
19 //===----------------------------------------------------------------------===//
20 
21 #include "Chunks.h"
22 #include "DLL.h"
23 #include "llvm/ADT/STLExtras.h"
24 #include "llvm/Object/COFF.h"
25 #include "llvm/Support/Endian.h"
26 #include "llvm/Support/Path.h"
27 
28 using namespace llvm;
29 using namespace llvm::object;
30 using namespace llvm::support::endian;
31 using namespace llvm::COFF;
32 using llvm::RoundUpToAlignment;
33 
34 namespace lld {
35 namespace coff {
36 
37 // Import table
38 
39 static int ptrSize() { return Config->is64() ? 8 : 4; }
40 
41 // A chunk for the import descriptor table.
42 class HintNameChunk : public Chunk {
43 public:
44   HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {}
45 
46   size_t getSize() const override {
47     // Starts with 2 byte Hint field, followed by a null-terminated string,
48     // ends with 0 or 1 byte padding.
49     return RoundUpToAlignment(Name.size() + 3, 2);
50   }
51 
52   void writeTo(uint8_t *Buf) override {
53     write16le(Buf + FileOff, Hint);
54     memcpy(Buf + FileOff + 2, Name.data(), Name.size());
55   }
56 
57 private:
58   StringRef Name;
59   uint16_t Hint;
60 };
61 
62 // A chunk for the import descriptor table.
63 class LookupChunk : public Chunk {
64 public:
65   explicit LookupChunk(Chunk *C) : HintName(C) {}
66   size_t getSize() const override { return ptrSize(); }
67 
68   void writeTo(uint8_t *Buf) override {
69     write32le(Buf + FileOff, HintName->getRVA());
70   }
71 
72   Chunk *HintName;
73 };
74 
75 // A chunk for the import descriptor table.
76 // This chunk represent import-by-ordinal symbols.
77 // See Microsoft PE/COFF spec 7.1. Import Header for details.
78 class OrdinalOnlyChunk : public Chunk {
79 public:
80   explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {}
81   size_t getSize() const override { return ptrSize(); }
82 
83   void writeTo(uint8_t *Buf) override {
84     // An import-by-ordinal slot has MSB 1 to indicate that
85     // this is import-by-ordinal (and not import-by-name).
86     if (Config->is64()) {
87       write64le(Buf + FileOff, (1ULL << 63) | Ordinal);
88     } else {
89       write32le(Buf + FileOff, (1ULL << 31) | Ordinal);
90     }
91   }
92 
93   uint16_t Ordinal;
94 };
95 
96 // A chunk for the import descriptor table.
97 class ImportDirectoryChunk : public Chunk {
98 public:
99   explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {}
100   size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); }
101 
102   void writeTo(uint8_t *Buf) override {
103     auto *E = (coff_import_directory_table_entry *)(Buf + FileOff);
104     E->ImportLookupTableRVA = LookupTab->getRVA();
105     E->NameRVA = DLLName->getRVA();
106     E->ImportAddressTableRVA = AddressTab->getRVA();
107   }
108 
109   Chunk *DLLName;
110   Chunk *LookupTab;
111   Chunk *AddressTab;
112 };
113 
114 // A chunk representing null terminator in the import table.
115 // Contents of this chunk is always null bytes.
116 class NullChunk : public Chunk {
117 public:
118   explicit NullChunk(size_t N) : Size(N) {}
119   bool hasData() const override { return false; }
120   size_t getSize() const override { return Size; }
121   void setAlign(size_t N) { Align = N; }
122 
123 private:
124   size_t Size;
125 };
126 
127 uint64_t IdataContents::getDirSize() {
128   return Dirs.size() * sizeof(ImportDirectoryTableEntry);
129 }
130 
131 uint64_t IdataContents::getIATSize() {
132   return Addresses.size() * ptrSize();
133 }
134 
135 // Returns a list of .idata contents.
136 // See Microsoft PE/COFF spec 5.4 for details.
137 std::vector<Chunk *> IdataContents::getChunks() {
138   create();
139   std::vector<Chunk *> V;
140   // The loader assumes a specific order of data.
141   // Add each type in the correct order.
142   for (std::unique_ptr<Chunk> &C : Dirs)
143     V.push_back(C.get());
144   for (std::unique_ptr<Chunk> &C : Lookups)
145     V.push_back(C.get());
146   for (std::unique_ptr<Chunk> &C : Addresses)
147     V.push_back(C.get());
148   for (std::unique_ptr<Chunk> &C : Hints)
149     V.push_back(C.get());
150   for (auto &P : DLLNames) {
151     std::unique_ptr<Chunk> &C = P.second;
152     V.push_back(C.get());
153   }
154   return V;
155 }
156 
157 static std::map<StringRef, std::vector<DefinedImportData *>>
158 binImports(const std::vector<DefinedImportData *> &Imports) {
159   // Group DLL-imported symbols by DLL name because that's how
160   // symbols are layed out in the import descriptor table.
161   std::map<StringRef, std::vector<DefinedImportData *>> M;
162   for (DefinedImportData *Sym : Imports)
163     M[Sym->getDLLName()].push_back(Sym);
164 
165   for (auto &P : M) {
166     // Sort symbols by name for each group.
167     std::vector<DefinedImportData *> &Syms = P.second;
168     std::sort(Syms.begin(), Syms.end(),
169               [](DefinedImportData *A, DefinedImportData *B) {
170                 return A->getName() < B->getName();
171               });
172   }
173   return M;
174 }
175 
176 void IdataContents::create() {
177   std::map<StringRef, std::vector<DefinedImportData *>> Map =
178       binImports(Imports);
179 
180   // Create .idata contents for each DLL.
181   for (auto &P : Map) {
182     StringRef Name = P.first;
183     std::vector<DefinedImportData *> &Syms = P.second;
184 
185     // Create lookup and address tables. If they have external names,
186     // we need to create HintName chunks to store the names.
187     // If they don't (if they are import-by-ordinals), we store only
188     // ordinal values to the table.
189     size_t Base = Lookups.size();
190     for (DefinedImportData *S : Syms) {
191       uint16_t Ord = S->getOrdinal();
192       if (S->getExternalName().empty()) {
193         Lookups.push_back(make_unique<OrdinalOnlyChunk>(Ord));
194         Addresses.push_back(make_unique<OrdinalOnlyChunk>(Ord));
195         continue;
196       }
197       auto C = make_unique<HintNameChunk>(S->getExternalName(), Ord);
198       Lookups.push_back(make_unique<LookupChunk>(C.get()));
199       Addresses.push_back(make_unique<LookupChunk>(C.get()));
200       Hints.push_back(std::move(C));
201     }
202     // Terminate with null values.
203     Lookups.push_back(make_unique<NullChunk>(ptrSize()));
204     Addresses.push_back(make_unique<NullChunk>(ptrSize()));
205 
206     for (int I = 0, E = Syms.size(); I < E; ++I)
207       Syms[I]->setLocation(Addresses[Base + I].get());
208 
209     // Create the import table header.
210     if (!DLLNames.count(Name))
211       DLLNames[Name] = make_unique<StringChunk>(Name);
212     auto Dir = make_unique<ImportDirectoryChunk>(DLLNames[Name].get());
213     Dir->LookupTab = Lookups[Base].get();
214     Dir->AddressTab = Addresses[Base].get();
215     Dirs.push_back(std::move(Dir));
216   }
217   // Add null terminator.
218   Dirs.push_back(make_unique<NullChunk>(sizeof(ImportDirectoryTableEntry)));
219 }
220 
221 // Export table
222 // See Microsoft PE/COFF spec 4.3 for details.
223 
224 // A chunk for the delay import descriptor table etnry.
225 class DelayDirectoryChunk : public Chunk {
226 public:
227   explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {}
228 
229   size_t getSize() const override {
230     return sizeof(delay_import_directory_table_entry);
231   }
232 
233   void writeTo(uint8_t *Buf) override {
234     auto *E = (delay_import_directory_table_entry *)(Buf + FileOff);
235     E->Attributes = 1;
236     E->Name = DLLName->getRVA();
237     E->ModuleHandle = ModuleHandle->getRVA();
238     E->DelayImportAddressTable = AddressTab->getRVA();
239     E->DelayImportNameTable = NameTab->getRVA();
240   }
241 
242   Chunk *DLLName;
243   Chunk *ModuleHandle;
244   Chunk *AddressTab;
245   Chunk *NameTab;
246 };
247 
248 // Initial contents for delay-loaded functions.
249 // This code calls __delayLoadHelper2 function to resolve a symbol
250 // and then overwrites its jump table slot with the result
251 // for subsequent function calls.
252 static const uint8_t Thunk[] = {
253     0x51,                               // push    rcx
254     0x52,                               // push    rdx
255     0x41, 0x50,                         // push    r8
256     0x41, 0x51,                         // push    r9
257     0x48, 0x83, 0xEC, 0x48,             // sub     rsp, 48h
258     0x66, 0x0F, 0x7F, 0x04, 0x24,       // movdqa  xmmword ptr [rsp], xmm0
259     0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa  xmmword ptr [rsp+10h], xmm1
260     0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa  xmmword ptr [rsp+20h], xmm2
261     0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa  xmmword ptr [rsp+30h], xmm3
262     0x48, 0x8D, 0x15, 0, 0, 0, 0,       // lea     rdx, [__imp_<FUNCNAME>]
263     0x48, 0x8D, 0x0D, 0, 0, 0, 0,       // lea     rcx, [___DELAY_IMPORT_...]
264     0xE8, 0, 0, 0, 0,                   // call    __delayLoadHelper2
265     0x66, 0x0F, 0x6F, 0x04, 0x24,       // movdqa  xmm0, xmmword ptr [rsp]
266     0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa  xmm1, xmmword ptr [rsp+10h]
267     0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa  xmm2, xmmword ptr [rsp+20h]
268     0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa  xmm3, xmmword ptr [rsp+30h]
269     0x48, 0x83, 0xC4, 0x48,             // add     rsp, 48h
270     0x41, 0x59,                         // pop     r9
271     0x41, 0x58,                         // pop     r8
272     0x5A,                               // pop     rdx
273     0x59,                               // pop     rcx
274     0xFF, 0xE0,                         // jmp     rax
275 };
276 
277 // A chunk for the delay import thunk.
278 class ThunkChunk : public Chunk {
279 public:
280   ThunkChunk(Defined *I, Chunk *D, Defined *H) : Imp(I), Desc(D), Helper(H) {}
281   size_t getSize() const override { return sizeof(Thunk); }
282 
283   void writeTo(uint8_t *Buf) override {
284     memcpy(Buf + FileOff, Thunk, sizeof(Thunk));
285     write32le(Buf + FileOff + 36, Imp->getRVA() - RVA - 40);
286     write32le(Buf + FileOff + 43, Desc->getRVA() - RVA - 47);
287     write32le(Buf + FileOff + 48, Helper->getRVA() - RVA - 52);
288   }
289 
290   Defined *Imp = nullptr;
291   Chunk *Desc = nullptr;
292   Defined *Helper = nullptr;
293 };
294 
295 std::vector<Chunk *> DelayLoadContents::getChunks() {
296   std::vector<Chunk *> V;
297   for (std::unique_ptr<Chunk> &C : Dirs)
298     V.push_back(C.get());
299   for (std::unique_ptr<Chunk> &C : Names)
300     V.push_back(C.get());
301   for (std::unique_ptr<Chunk> &C : HintNames)
302     V.push_back(C.get());
303   for (auto &P : DLLNames) {
304     std::unique_ptr<Chunk> &C = P.second;
305     V.push_back(C.get());
306   }
307   return V;
308 }
309 
310 std::vector<Chunk *> DelayLoadContents::getDataChunks() {
311   std::vector<Chunk *> V;
312   for (std::unique_ptr<Chunk> &C : ModuleHandles)
313     V.push_back(C.get());
314   for (std::unique_ptr<Chunk> &C : Addresses)
315     V.push_back(C.get());
316   return V;
317 }
318 
319 uint64_t DelayLoadContents::getDirSize() {
320   return Dirs.size() * sizeof(delay_import_directory_table_entry);
321 }
322 
323 // A chunk for the import descriptor table.
324 class DelayAddressChunk : public Chunk {
325 public:
326   explicit DelayAddressChunk(Chunk *C) : Thunk(C) {}
327   size_t getSize() const override { return 8; }
328 
329   void writeTo(uint8_t *Buf) override {
330     write64le(Buf + FileOff, Thunk->getRVA() + Config->ImageBase);
331   }
332 
333   void getBaserels(std::vector<uint32_t> *Res, Defined *ImageBase) override {
334     Res->push_back(RVA);
335   }
336 
337   Chunk *Thunk;
338 };
339 
340 void DelayLoadContents::create(Defined *H) {
341   Helper = H;
342   std::map<StringRef, std::vector<DefinedImportData *>> Map =
343       binImports(Imports);
344 
345   // Create .didat contents for each DLL.
346   for (auto &P : Map) {
347     StringRef Name = P.first;
348     std::vector<DefinedImportData *> &Syms = P.second;
349 
350     // Create the delay import table header.
351     if (!DLLNames.count(Name))
352       DLLNames[Name] = make_unique<StringChunk>(Name);
353     auto Dir = make_unique<DelayDirectoryChunk>(DLLNames[Name].get());
354 
355     size_t Base = Addresses.size();
356     for (DefinedImportData *S : Syms) {
357       auto T = make_unique<ThunkChunk>(S, Dir.get(), Helper);
358       auto A = make_unique<DelayAddressChunk>(T.get());
359       Addresses.push_back(std::move(A));
360       Thunks.push_back(std::move(T));
361       StringRef ExtName = S->getExternalName();
362       if (ExtName.empty()) {
363         Names.push_back(make_unique<OrdinalOnlyChunk>(S->getOrdinal()));
364       } else {
365         auto C = make_unique<HintNameChunk>(ExtName, 0);
366         Names.push_back(make_unique<LookupChunk>(C.get()));
367         HintNames.push_back(std::move(C));
368       }
369     }
370     // Terminate with null values.
371     Addresses.push_back(make_unique<NullChunk>(8));
372     Names.push_back(make_unique<NullChunk>(8));
373 
374     for (int I = 0, E = Syms.size(); I < E; ++I)
375       Syms[I]->setLocation(Addresses[Base + I].get());
376     auto *MH = new NullChunk(8);
377     MH->setAlign(8);
378     ModuleHandles.push_back(std::unique_ptr<Chunk>(MH));
379 
380     // Fill the delay import table header fields.
381     Dir->ModuleHandle = MH;
382     Dir->AddressTab = Addresses[Base].get();
383     Dir->NameTab = Names[Base].get();
384     Dirs.push_back(std::move(Dir));
385   }
386   // Add null terminator.
387   Dirs.push_back(
388       make_unique<NullChunk>(sizeof(delay_import_directory_table_entry)));
389 }
390 
391 // Export table
392 // Read Microsoft PE/COFF spec 5.3 for details.
393 
394 // A chunk for the export descriptor table.
395 class ExportDirectoryChunk : public Chunk {
396 public:
397   ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O)
398       : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N),
399         OrdinalTab(O) {}
400 
401   size_t getSize() const override {
402     return sizeof(export_directory_table_entry);
403   }
404 
405   void writeTo(uint8_t *Buf) override {
406     auto *E = (export_directory_table_entry *)(Buf + FileOff);
407     E->NameRVA = DLLName->getRVA();
408     E->OrdinalBase = 0;
409     E->AddressTableEntries = MaxOrdinal + 1;
410     E->NumberOfNamePointers = NameTabSize;
411     E->ExportAddressTableRVA = AddressTab->getRVA();
412     E->NamePointerRVA = NameTab->getRVA();
413     E->OrdinalTableRVA = OrdinalTab->getRVA();
414   }
415 
416   uint16_t MaxOrdinal;
417   uint16_t NameTabSize;
418   Chunk *DLLName;
419   Chunk *AddressTab;
420   Chunk *NameTab;
421   Chunk *OrdinalTab;
422 };
423 
424 class AddressTableChunk : public Chunk {
425 public:
426   explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {}
427   size_t getSize() const override { return Size * 4; }
428 
429   void writeTo(uint8_t *Buf) override {
430     for (Export &E : Config->Exports) {
431       auto *D = cast<Defined>(E.Sym->repl());
432       write32le(Buf + FileOff + E.Ordinal * 4, D->getRVA());
433     }
434   }
435 
436 private:
437   size_t Size;
438 };
439 
440 class NamePointersChunk : public Chunk {
441 public:
442   explicit NamePointersChunk(std::vector<Chunk *> &V) : Chunks(V) {}
443   size_t getSize() const override { return Chunks.size() * 4; }
444 
445   void writeTo(uint8_t *Buf) override {
446     uint8_t *P = Buf + FileOff;
447     for (Chunk *C : Chunks) {
448       write32le(P, C->getRVA());
449       P += 4;
450     }
451   }
452 
453 private:
454   std::vector<Chunk *> Chunks;
455 };
456 
457 class ExportOrdinalChunk : public Chunk {
458 public:
459   explicit ExportOrdinalChunk(size_t I) : Size(I) {}
460   size_t getSize() const override { return Size * 2; }
461 
462   void writeTo(uint8_t *Buf) override {
463     uint8_t *P = Buf + FileOff;
464     for (Export &E : Config->Exports) {
465       if (E.Noname)
466         continue;
467       write16le(P, E.Ordinal);
468       P += 2;
469     }
470   }
471 
472 private:
473   size_t Size;
474 };
475 
476 EdataContents::EdataContents() {
477   uint16_t MaxOrdinal = 0;
478   for (Export &E : Config->Exports)
479     MaxOrdinal = std::max(MaxOrdinal, E.Ordinal);
480 
481   auto *DLLName = new StringChunk(sys::path::filename(Config->OutputFile));
482   auto *AddressTab = new AddressTableChunk(MaxOrdinal);
483   std::vector<Chunk *> Names;
484   for (Export &E : Config->Exports)
485     if (!E.Noname)
486       Names.push_back(new StringChunk(E.ExtName));
487   auto *NameTab = new NamePointersChunk(Names);
488   auto *OrdinalTab = new ExportOrdinalChunk(Names.size());
489   auto *Dir = new ExportDirectoryChunk(MaxOrdinal, Names.size(), DLLName,
490                                        AddressTab, NameTab, OrdinalTab);
491   Chunks.push_back(std::unique_ptr<Chunk>(Dir));
492   Chunks.push_back(std::unique_ptr<Chunk>(DLLName));
493   Chunks.push_back(std::unique_ptr<Chunk>(AddressTab));
494   Chunks.push_back(std::unique_ptr<Chunk>(NameTab));
495   Chunks.push_back(std::unique_ptr<Chunk>(OrdinalTab));
496   for (Chunk *C : Names)
497     Chunks.push_back(std::unique_ptr<Chunk>(C));
498 }
499 
500 } // namespace coff
501 } // namespace lld
502