/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/COFF/DLL.cpp
Line | Count | Source (jump to first uncovered line) |
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 "Chunks.h" |
22 | | #include "llvm/Object/COFF.h" |
23 | | #include "llvm/Support/Endian.h" |
24 | | #include "llvm/Support/Path.h" |
25 | | |
26 | | using namespace llvm; |
27 | | using namespace llvm::object; |
28 | | using namespace llvm::support::endian; |
29 | | using namespace llvm::COFF; |
30 | | |
31 | | namespace lld { |
32 | | namespace coff { |
33 | | namespace { |
34 | | |
35 | | // Import table |
36 | | |
37 | | // A chunk for the import descriptor table. |
38 | | class HintNameChunk : public NonSectionChunk { |
39 | | public: |
40 | 90 | HintNameChunk(StringRef n, uint16_t h) : name(n), hint(h) {} |
41 | | |
42 | 192 | size_t getSize() const override { |
43 | 192 | // Starts with 2 byte Hint field, followed by a null-terminated string, |
44 | 192 | // ends with 0 or 1 byte padding. |
45 | 192 | return alignTo(name.size() + 3, 2); |
46 | 192 | } |
47 | | |
48 | 90 | void writeTo(uint8_t *buf) const override { |
49 | 90 | memset(buf, 0, getSize()); |
50 | 90 | write16le(buf, hint); |
51 | 90 | memcpy(buf + 2, name.data(), name.size()); |
52 | 90 | } |
53 | | |
54 | | private: |
55 | | StringRef name; |
56 | | uint16_t hint; |
57 | | }; |
58 | | |
59 | | // A chunk for the import descriptor table. |
60 | | class LookupChunk : public NonSectionChunk { |
61 | | public: |
62 | 170 | explicit LookupChunk(Chunk *c) : hintName(c) { |
63 | 170 | setAlignment(config->wordsize); |
64 | 170 | } |
65 | 266 | size_t getSize() const override { return config->wordsize; } |
66 | | |
67 | 170 | void writeTo(uint8_t *buf) const override { |
68 | 170 | if (config->is64()) |
69 | 125 | write64le(buf, hintName->getRVA()); |
70 | 45 | else |
71 | 45 | write32le(buf, hintName->getRVA()); |
72 | 170 | } |
73 | | |
74 | | Chunk *hintName; |
75 | | }; |
76 | | |
77 | | // A chunk for the import descriptor table. |
78 | | // This chunk represent import-by-ordinal symbols. |
79 | | // See Microsoft PE/COFF spec 7.1. Import Header for details. |
80 | | class OrdinalOnlyChunk : public NonSectionChunk { |
81 | | public: |
82 | 25 | explicit OrdinalOnlyChunk(uint16_t v) : ordinal(v) { |
83 | 25 | setAlignment(config->wordsize); |
84 | 25 | } |
85 | 37 | size_t getSize() const override { return config->wordsize; } |
86 | | |
87 | 25 | void writeTo(uint8_t *buf) const override { |
88 | 25 | // An import-by-ordinal slot has MSB 1 to indicate that |
89 | 25 | // this is import-by-ordinal (and not import-by-name). |
90 | 25 | if (config->is64()) { |
91 | 25 | write64le(buf, (1ULL << 63) | ordinal); |
92 | 25 | } else { |
93 | 0 | write32le(buf, (1ULL << 31) | ordinal); |
94 | 0 | } |
95 | 25 | } |
96 | | |
97 | | uint16_t ordinal; |
98 | | }; |
99 | | |
100 | | // A chunk for the import descriptor table. |
101 | | class ImportDirectoryChunk : public NonSectionChunk { |
102 | | public: |
103 | 48 | explicit ImportDirectoryChunk(Chunk *n) : dllName(n) {} |
104 | 148 | size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); } |
105 | | |
106 | 48 | void writeTo(uint8_t *buf) const override { |
107 | 48 | memset(buf, 0, getSize()); |
108 | 48 | |
109 | 48 | auto *e = (coff_import_directory_table_entry *)(buf); |
110 | 48 | e->ImportLookupTableRVA = lookupTab->getRVA(); |
111 | 48 | e->NameRVA = dllName->getRVA(); |
112 | 48 | e->ImportAddressTableRVA = addressTab->getRVA(); |
113 | 48 | } |
114 | | |
115 | | Chunk *dllName; |
116 | | Chunk *lookupTab; |
117 | | Chunk *addressTab; |
118 | | }; |
119 | | |
120 | | // A chunk representing null terminator in the import table. |
121 | | // Contents of this chunk is always null bytes. |
122 | | class NullChunk : public NonSectionChunk { |
123 | | public: |
124 | 168 | explicit NullChunk(size_t n) : size(n) { hasData = false; } |
125 | 289 | size_t getSize() const override { return size; } |
126 | | |
127 | 168 | void writeTo(uint8_t *buf) const override { |
128 | 168 | memset(buf, 0, size); |
129 | 168 | } |
130 | | |
131 | | private: |
132 | | size_t size; |
133 | | }; |
134 | | |
135 | | static std::vector<std::vector<DefinedImportData *>> |
136 | 54 | binImports(const std::vector<DefinedImportData *> &imports) { |
137 | 54 | // Group DLL-imported symbols by DLL name because that's how |
138 | 54 | // symbols are layed out in the import descriptor table. |
139 | 104 | auto less = [](const std::string &a, const std::string &b) { |
140 | 104 | return config->dllOrder[a] < config->dllOrder[b]; |
141 | 104 | }; |
142 | 54 | std::map<std::string, std::vector<DefinedImportData *>, |
143 | 54 | bool(*)(const std::string &, const std::string &)> m(less); |
144 | 54 | for (DefinedImportData *sym : imports) |
145 | 103 | m[sym->getDLLName().lower()].push_back(sym); |
146 | 54 | |
147 | 54 | std::vector<std::vector<DefinedImportData *>> v; |
148 | 54 | for (auto &kv : m) { |
149 | 54 | // Sort symbols by name for each group. |
150 | 54 | std::vector<DefinedImportData *> &syms = kv.second; |
151 | 54 | std::sort(syms.begin(), syms.end(), |
152 | 54 | [](DefinedImportData *a, DefinedImportData *b) { |
153 | 52 | return a->getName() < b->getName(); |
154 | 52 | }); |
155 | 54 | v.push_back(std::move(syms)); |
156 | 54 | } |
157 | 54 | return v; |
158 | 54 | } |
159 | | |
160 | | // Export table |
161 | | // See Microsoft PE/COFF spec 4.3 for details. |
162 | | |
163 | | // A chunk for the delay import descriptor table etnry. |
164 | | class DelayDirectoryChunk : public NonSectionChunk { |
165 | | public: |
166 | 6 | explicit DelayDirectoryChunk(Chunk *n) : dllName(n) {} |
167 | | |
168 | 12 | size_t getSize() const override { |
169 | 12 | return sizeof(delay_import_directory_table_entry); |
170 | 12 | } |
171 | | |
172 | 6 | void writeTo(uint8_t *buf) const override { |
173 | 6 | memset(buf, 0, getSize()); |
174 | 6 | |
175 | 6 | auto *e = (delay_import_directory_table_entry *)(buf); |
176 | 6 | e->Attributes = 1; |
177 | 6 | e->Name = dllName->getRVA(); |
178 | 6 | e->ModuleHandle = moduleHandle->getRVA(); |
179 | 6 | e->DelayImportAddressTable = addressTab->getRVA(); |
180 | 6 | e->DelayImportNameTable = nameTab->getRVA(); |
181 | 6 | } |
182 | | |
183 | | Chunk *dllName; |
184 | | Chunk *moduleHandle; |
185 | | Chunk *addressTab; |
186 | | Chunk *nameTab; |
187 | | }; |
188 | | |
189 | | // Initial contents for delay-loaded functions. |
190 | | // This code calls __delayLoadHelper2 function to resolve a symbol |
191 | | // and then overwrites its jump table slot with the result |
192 | | // for subsequent function calls. |
193 | | static const uint8_t thunkX64[] = { |
194 | | 0x48, 0x8D, 0x05, 0, 0, 0, 0, // lea rax, [__imp_<FUNCNAME>] |
195 | | 0xE9, 0, 0, 0, 0, // jmp __tailMerge_<lib> |
196 | | }; |
197 | | |
198 | | static const uint8_t tailMergeX64[] = { |
199 | | 0x51, // push rcx |
200 | | 0x52, // push rdx |
201 | | 0x41, 0x50, // push r8 |
202 | | 0x41, 0x51, // push r9 |
203 | | 0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h |
204 | | 0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0 |
205 | | 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1 |
206 | | 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2 |
207 | | 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3 |
208 | | 0x48, 0x8B, 0xD0, // mov rdx, rax |
209 | | 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...] |
210 | | 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2 |
211 | | 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp] |
212 | | 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h] |
213 | | 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h] |
214 | | 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h] |
215 | | 0x48, 0x83, 0xC4, 0x48, // add rsp, 48h |
216 | | 0x41, 0x59, // pop r9 |
217 | | 0x41, 0x58, // pop r8 |
218 | | 0x5A, // pop rdx |
219 | | 0x59, // pop rcx |
220 | | 0xFF, 0xE0, // jmp rax |
221 | | }; |
222 | | |
223 | | static const uint8_t thunkX86[] = { |
224 | | 0xB8, 0, 0, 0, 0, // mov eax, offset ___imp__<FUNCNAME> |
225 | | 0xE9, 0, 0, 0, 0, // jmp __tailMerge_<lib> |
226 | | }; |
227 | | |
228 | | static const uint8_t tailMergeX86[] = { |
229 | | 0x51, // push ecx |
230 | | 0x52, // push edx |
231 | | 0x50, // push eax |
232 | | 0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR_<DLLNAME>_dll |
233 | | 0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8 |
234 | | 0x5A, // pop edx |
235 | | 0x59, // pop ecx |
236 | | 0xFF, 0xE0, // jmp eax |
237 | | }; |
238 | | |
239 | | static const uint8_t thunkARM[] = { |
240 | | 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 __imp_<FUNCNAME> |
241 | | 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 __imp_<FUNCNAME> |
242 | | 0x00, 0xf0, 0x00, 0xb8, // b.w __tailMerge_<lib> |
243 | | }; |
244 | | |
245 | | static const uint8_t tailMergeARM[] = { |
246 | | 0x2d, 0xe9, 0x0f, 0x48, // push.w {r0, r1, r2, r3, r11, lr} |
247 | | 0x0d, 0xf2, 0x10, 0x0b, // addw r11, sp, #16 |
248 | | 0x2d, 0xed, 0x10, 0x0b, // vpush {d0, d1, d2, d3, d4, d5, d6, d7} |
249 | | 0x61, 0x46, // mov r1, ip |
250 | | 0x40, 0xf2, 0x00, 0x00, // mov.w r0, #0 DELAY_IMPORT_DESCRIPTOR |
251 | | 0xc0, 0xf2, 0x00, 0x00, // mov.t r0, #0 DELAY_IMPORT_DESCRIPTOR |
252 | | 0x00, 0xf0, 0x00, 0xd0, // bl #0 __delayLoadHelper2 |
253 | | 0x84, 0x46, // mov ip, r0 |
254 | | 0xbd, 0xec, 0x10, 0x0b, // vpop {d0, d1, d2, d3, d4, d5, d6, d7} |
255 | | 0xbd, 0xe8, 0x0f, 0x48, // pop.w {r0, r1, r2, r3, r11, lr} |
256 | | 0x60, 0x47, // bx ip |
257 | | }; |
258 | | |
259 | | static const uint8_t thunkARM64[] = { |
260 | | 0x11, 0x00, 0x00, 0x90, // adrp x17, #0 __imp_<FUNCNAME> |
261 | | 0x31, 0x02, 0x00, 0x91, // add x17, x17, #0 :lo12:__imp_<FUNCNAME> |
262 | | 0x00, 0x00, 0x00, 0x14, // b __tailMerge_<lib> |
263 | | }; |
264 | | |
265 | | static const uint8_t tailMergeARM64[] = { |
266 | | 0xfd, 0x7b, 0xb3, 0xa9, // stp x29, x30, [sp, #-208]! |
267 | | 0xfd, 0x03, 0x00, 0x91, // mov x29, sp |
268 | | 0xe0, 0x07, 0x01, 0xa9, // stp x0, x1, [sp, #16] |
269 | | 0xe2, 0x0f, 0x02, 0xa9, // stp x2, x3, [sp, #32] |
270 | | 0xe4, 0x17, 0x03, 0xa9, // stp x4, x5, [sp, #48] |
271 | | 0xe6, 0x1f, 0x04, 0xa9, // stp x6, x7, [sp, #64] |
272 | | 0xe0, 0x87, 0x02, 0xad, // stp q0, q1, [sp, #80] |
273 | | 0xe2, 0x8f, 0x03, 0xad, // stp q2, q3, [sp, #112] |
274 | | 0xe4, 0x97, 0x04, 0xad, // stp q4, q5, [sp, #144] |
275 | | 0xe6, 0x9f, 0x05, 0xad, // stp q6, q7, [sp, #176] |
276 | | 0xe1, 0x03, 0x11, 0xaa, // mov x1, x17 |
277 | | 0x00, 0x00, 0x00, 0x90, // adrp x0, #0 DELAY_IMPORT_DESCRIPTOR |
278 | | 0x00, 0x00, 0x00, 0x91, // add x0, x0, #0 :lo12:DELAY_IMPORT_DESCRIPTOR |
279 | | 0x00, 0x00, 0x00, 0x94, // bl #0 __delayLoadHelper2 |
280 | | 0xf0, 0x03, 0x00, 0xaa, // mov x16, x0 |
281 | | 0xe6, 0x9f, 0x45, 0xad, // ldp q6, q7, [sp, #176] |
282 | | 0xe4, 0x97, 0x44, 0xad, // ldp q4, q5, [sp, #144] |
283 | | 0xe2, 0x8f, 0x43, 0xad, // ldp q2, q3, [sp, #112] |
284 | | 0xe0, 0x87, 0x42, 0xad, // ldp q0, q1, [sp, #80] |
285 | | 0xe6, 0x1f, 0x44, 0xa9, // ldp x6, x7, [sp, #64] |
286 | | 0xe4, 0x17, 0x43, 0xa9, // ldp x4, x5, [sp, #48] |
287 | | 0xe2, 0x0f, 0x42, 0xa9, // ldp x2, x3, [sp, #32] |
288 | | 0xe0, 0x07, 0x41, 0xa9, // ldp x0, x1, [sp, #16] |
289 | | 0xfd, 0x7b, 0xcd, 0xa8, // ldp x29, x30, [sp], #208 |
290 | | 0x00, 0x02, 0x1f, 0xd6, // br x16 |
291 | | }; |
292 | | |
293 | | // A chunk for the delay import thunk. |
294 | | class ThunkChunkX64 : public NonSectionChunk { |
295 | | public: |
296 | 7 | ThunkChunkX64(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {} |
297 | | |
298 | 7 | size_t getSize() const override { return sizeof(thunkX64); } |
299 | | |
300 | 7 | void writeTo(uint8_t *buf) const override { |
301 | 7 | memcpy(buf, thunkX64, sizeof(thunkX64)); |
302 | 7 | write32le(buf + 3, imp->getRVA() - rva - 7); |
303 | 7 | write32le(buf + 8, tailMerge->getRVA() - rva - 12); |
304 | 7 | } |
305 | | |
306 | | Defined *imp = nullptr; |
307 | | Chunk *tailMerge = nullptr; |
308 | | }; |
309 | | |
310 | | class TailMergeChunkX64 : public NonSectionChunk { |
311 | | public: |
312 | 3 | TailMergeChunkX64(Chunk *d, Defined *h) : desc(d), helper(h) {} |
313 | | |
314 | 3 | size_t getSize() const override { return sizeof(tailMergeX64); } |
315 | | |
316 | 3 | void writeTo(uint8_t *buf) const override { |
317 | 3 | memcpy(buf, tailMergeX64, sizeof(tailMergeX64)); |
318 | 3 | write32le(buf + 39, desc->getRVA() - rva - 43); |
319 | 3 | write32le(buf + 44, helper->getRVA() - rva - 48); |
320 | 3 | } |
321 | | |
322 | | Chunk *desc = nullptr; |
323 | | Defined *helper = nullptr; |
324 | | }; |
325 | | |
326 | | class ThunkChunkX86 : public NonSectionChunk { |
327 | | public: |
328 | 2 | ThunkChunkX86(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {} |
329 | | |
330 | 2 | size_t getSize() const override { return sizeof(thunkX86); } |
331 | | |
332 | 2 | void writeTo(uint8_t *buf) const override { |
333 | 2 | memcpy(buf, thunkX86, sizeof(thunkX86)); |
334 | 2 | write32le(buf + 1, imp->getRVA() + config->imageBase); |
335 | 2 | write32le(buf + 6, tailMerge->getRVA() - rva - 10); |
336 | 2 | } |
337 | | |
338 | 2 | void getBaserels(std::vector<Baserel> *res) override { |
339 | 2 | res->emplace_back(rva + 1); |
340 | 2 | } |
341 | | |
342 | | Defined *imp = nullptr; |
343 | | Chunk *tailMerge = nullptr; |
344 | | }; |
345 | | |
346 | | class TailMergeChunkX86 : public NonSectionChunk { |
347 | | public: |
348 | 1 | TailMergeChunkX86(Chunk *d, Defined *h) : desc(d), helper(h) {} |
349 | | |
350 | 1 | size_t getSize() const override { return sizeof(tailMergeX86); } |
351 | | |
352 | 1 | void writeTo(uint8_t *buf) const override { |
353 | 1 | memcpy(buf, tailMergeX86, sizeof(tailMergeX86)); |
354 | 1 | write32le(buf + 4, desc->getRVA() + config->imageBase); |
355 | 1 | write32le(buf + 9, helper->getRVA() - rva - 13); |
356 | 1 | } |
357 | | |
358 | 1 | void getBaserels(std::vector<Baserel> *res) override { |
359 | 1 | res->emplace_back(rva + 4); |
360 | 1 | } |
361 | | |
362 | | Chunk *desc = nullptr; |
363 | | Defined *helper = nullptr; |
364 | | }; |
365 | | |
366 | | class ThunkChunkARM : public NonSectionChunk { |
367 | | public: |
368 | 1 | ThunkChunkARM(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {} |
369 | | |
370 | 1 | size_t getSize() const override { return sizeof(thunkARM); } |
371 | | |
372 | 1 | void writeTo(uint8_t *buf) const override { |
373 | 1 | memcpy(buf, thunkARM, sizeof(thunkARM)); |
374 | 1 | applyMOV32T(buf + 0, imp->getRVA() + config->imageBase); |
375 | 1 | applyBranch24T(buf + 8, tailMerge->getRVA() - rva - 12); |
376 | 1 | } |
377 | | |
378 | 1 | void getBaserels(std::vector<Baserel> *res) override { |
379 | 1 | res->emplace_back(rva + 0, IMAGE_REL_BASED_ARM_MOV32T); |
380 | 1 | } |
381 | | |
382 | | Defined *imp = nullptr; |
383 | | Chunk *tailMerge = nullptr; |
384 | | }; |
385 | | |
386 | | class TailMergeChunkARM : public NonSectionChunk { |
387 | | public: |
388 | 1 | TailMergeChunkARM(Chunk *d, Defined *h) : desc(d), helper(h) {} |
389 | | |
390 | 1 | size_t getSize() const override { return sizeof(tailMergeARM); } |
391 | | |
392 | 1 | void writeTo(uint8_t *buf) const override { |
393 | 1 | memcpy(buf, tailMergeARM, sizeof(tailMergeARM)); |
394 | 1 | applyMOV32T(buf + 14, desc->getRVA() + config->imageBase); |
395 | 1 | applyBranch24T(buf + 22, helper->getRVA() - rva - 26); |
396 | 1 | } |
397 | | |
398 | 1 | void getBaserels(std::vector<Baserel> *res) override { |
399 | 1 | res->emplace_back(rva + 14, IMAGE_REL_BASED_ARM_MOV32T); |
400 | 1 | } |
401 | | |
402 | | Chunk *desc = nullptr; |
403 | | Defined *helper = nullptr; |
404 | | }; |
405 | | |
406 | | class ThunkChunkARM64 : public NonSectionChunk { |
407 | | public: |
408 | 1 | ThunkChunkARM64(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {} |
409 | | |
410 | 1 | size_t getSize() const override { return sizeof(thunkARM64); } |
411 | | |
412 | 1 | void writeTo(uint8_t *buf) const override { |
413 | 1 | memcpy(buf, thunkARM64, sizeof(thunkARM64)); |
414 | 1 | applyArm64Addr(buf + 0, imp->getRVA(), rva + 0, 12); |
415 | 1 | applyArm64Imm(buf + 4, imp->getRVA() & 0xfff, 0); |
416 | 1 | applyArm64Branch26(buf + 8, tailMerge->getRVA() - rva - 8); |
417 | 1 | } |
418 | | |
419 | | Defined *imp = nullptr; |
420 | | Chunk *tailMerge = nullptr; |
421 | | }; |
422 | | |
423 | | class TailMergeChunkARM64 : public NonSectionChunk { |
424 | | public: |
425 | 1 | TailMergeChunkARM64(Chunk *d, Defined *h) : desc(d), helper(h) {} |
426 | | |
427 | 1 | size_t getSize() const override { return sizeof(tailMergeARM64); } |
428 | | |
429 | 1 | void writeTo(uint8_t *buf) const override { |
430 | 1 | memcpy(buf, tailMergeARM64, sizeof(tailMergeARM64)); |
431 | 1 | applyArm64Addr(buf + 44, desc->getRVA(), rva + 44, 12); |
432 | 1 | applyArm64Imm(buf + 48, desc->getRVA() & 0xfff, 0); |
433 | 1 | applyArm64Branch26(buf + 52, helper->getRVA() - rva - 52); |
434 | 1 | } |
435 | | |
436 | | Chunk *desc = nullptr; |
437 | | Defined *helper = nullptr; |
438 | | }; |
439 | | |
440 | | // A chunk for the import descriptor table. |
441 | | class DelayAddressChunk : public NonSectionChunk { |
442 | | public: |
443 | 11 | explicit DelayAddressChunk(Chunk *c) : thunk(c) { |
444 | 11 | setAlignment(config->wordsize); |
445 | 11 | } |
446 | 11 | size_t getSize() const override { return config->wordsize; } |
447 | | |
448 | 11 | void writeTo(uint8_t *buf) const override { |
449 | 11 | if (config->is64()) { |
450 | 8 | write64le(buf, thunk->getRVA() + config->imageBase); |
451 | 8 | } else { |
452 | 3 | uint32_t bit = 0; |
453 | 3 | // Pointer to thumb code must have the LSB set, so adjust it. |
454 | 3 | if (config->machine == ARMNT) |
455 | 1 | bit = 1; |
456 | 3 | write32le(buf, (thunk->getRVA() + config->imageBase) | bit); |
457 | 3 | } |
458 | 11 | } |
459 | | |
460 | 11 | void getBaserels(std::vector<Baserel> *res) override { |
461 | 11 | res->emplace_back(rva); |
462 | 11 | } |
463 | | |
464 | | Chunk *thunk; |
465 | | }; |
466 | | |
467 | | // Export table |
468 | | // Read Microsoft PE/COFF spec 5.3 for details. |
469 | | |
470 | | // A chunk for the export descriptor table. |
471 | | class ExportDirectoryChunk : public NonSectionChunk { |
472 | | public: |
473 | | ExportDirectoryChunk(int i, int j, Chunk *d, Chunk *a, Chunk *n, Chunk *o) |
474 | | : maxOrdinal(i), nameTabSize(j), dllName(d), addressTab(a), nameTab(n), |
475 | 576 | ordinalTab(o) {} |
476 | | |
477 | 246 | size_t getSize() const override { |
478 | 246 | return sizeof(export_directory_table_entry); |
479 | 246 | } |
480 | | |
481 | 117 | void writeTo(uint8_t *buf) const override { |
482 | 117 | memset(buf, 0, getSize()); |
483 | 117 | |
484 | 117 | auto *e = (export_directory_table_entry *)(buf); |
485 | 117 | e->NameRVA = dllName->getRVA(); |
486 | 117 | e->OrdinalBase = 0; |
487 | 117 | e->AddressTableEntries = maxOrdinal + 1; |
488 | 117 | e->NumberOfNamePointers = nameTabSize; |
489 | 117 | e->ExportAddressTableRVA = addressTab->getRVA(); |
490 | 117 | e->NamePointerRVA = nameTab->getRVA(); |
491 | 117 | e->OrdinalTableRVA = ordinalTab->getRVA(); |
492 | 117 | } |
493 | | |
494 | | uint16_t maxOrdinal; |
495 | | uint16_t nameTabSize; |
496 | | Chunk *dllName; |
497 | | Chunk *addressTab; |
498 | | Chunk *nameTab; |
499 | | Chunk *ordinalTab; |
500 | | }; |
501 | | |
502 | | class AddressTableChunk : public NonSectionChunk { |
503 | | public: |
504 | 576 | explicit AddressTableChunk(size_t maxOrdinal) : size(maxOrdinal + 1) {} |
505 | 246 | size_t getSize() const override { return size * 4; } |
506 | | |
507 | 117 | void writeTo(uint8_t *buf) const override { |
508 | 117 | memset(buf, 0, getSize()); |
509 | 117 | |
510 | 209 | for (const Export &e : config->exports) { |
511 | 209 | uint8_t *p = buf + e.ordinal * 4; |
512 | 209 | uint32_t bit = 0; |
513 | 209 | // Pointer to thumb code must have the LSB set, so adjust it. |
514 | 209 | if (config->machine == ARMNT && !e.data6 ) |
515 | 3 | bit = 1; |
516 | 209 | if (e.forwardChunk) { |
517 | 2 | write32le(p, e.forwardChunk->getRVA() | bit); |
518 | 207 | } else { |
519 | 207 | write32le(p, cast<Defined>(e.sym)->getRVA() | bit); |
520 | 207 | } |
521 | 209 | } |
522 | 117 | } |
523 | | |
524 | | private: |
525 | | size_t size; |
526 | | }; |
527 | | |
528 | | class NamePointersChunk : public NonSectionChunk { |
529 | | public: |
530 | 576 | explicit NamePointersChunk(std::vector<Chunk *> &v) : chunks(v) {} |
531 | 129 | size_t getSize() const override { return chunks.size() * 4; } |
532 | | |
533 | 117 | void writeTo(uint8_t *buf) const override { |
534 | 207 | for (Chunk *c : chunks) { |
535 | 207 | write32le(buf, c->getRVA()); |
536 | 207 | buf += 4; |
537 | 207 | } |
538 | 117 | } |
539 | | |
540 | | private: |
541 | | std::vector<Chunk *> chunks; |
542 | | }; |
543 | | |
544 | | class ExportOrdinalChunk : public NonSectionChunk { |
545 | | public: |
546 | 576 | explicit ExportOrdinalChunk(size_t i) : size(i) {} |
547 | 129 | size_t getSize() const override { return size * 2; } |
548 | | |
549 | 117 | void writeTo(uint8_t *buf) const override { |
550 | 209 | for (Export &e : config->exports) { |
551 | 209 | if (e.noname) |
552 | 2 | continue; |
553 | 207 | write16le(buf, e.ordinal); |
554 | 207 | buf += 2; |
555 | 207 | } |
556 | 117 | } |
557 | | |
558 | | private: |
559 | | size_t size; |
560 | | }; |
561 | | |
562 | | } // anonymous namespace |
563 | | |
564 | 49 | void IdataContents::create() { |
565 | 49 | std::vector<std::vector<DefinedImportData *>> v = binImports(imports); |
566 | 49 | |
567 | 49 | // Create .idata contents for each DLL. |
568 | 49 | for (std::vector<DefinedImportData *> &syms : v) { |
569 | 48 | // Create lookup and address tables. If they have external names, |
570 | 48 | // we need to create hintName chunks to store the names. |
571 | 48 | // If they don't (if they are import-by-ordinals), we store only |
572 | 48 | // ordinal values to the table. |
573 | 48 | size_t base = lookups.size(); |
574 | 92 | for (DefinedImportData *s : syms) { |
575 | 92 | uint16_t ord = s->getOrdinal(); |
576 | 92 | if (s->getExternalName().empty()) { |
577 | 12 | lookups.push_back(make<OrdinalOnlyChunk>(ord)); |
578 | 12 | addresses.push_back(make<OrdinalOnlyChunk>(ord)); |
579 | 12 | continue; |
580 | 12 | } |
581 | 80 | auto *c = make<HintNameChunk>(s->getExternalName(), ord); |
582 | 80 | lookups.push_back(make<LookupChunk>(c)); |
583 | 80 | addresses.push_back(make<LookupChunk>(c)); |
584 | 80 | hints.push_back(c); |
585 | 80 | } |
586 | 48 | // Terminate with null values. |
587 | 48 | lookups.push_back(make<NullChunk>(config->wordsize)); |
588 | 48 | addresses.push_back(make<NullChunk>(config->wordsize)); |
589 | 48 | |
590 | 140 | for (int i = 0, e = syms.size(); i < e; ++i92 ) |
591 | 92 | syms[i]->setLocation(addresses[base + i]); |
592 | 48 | |
593 | 48 | // Create the import table header. |
594 | 48 | dllNames.push_back(make<StringChunk>(syms[0]->getDLLName())); |
595 | 48 | auto *dir = make<ImportDirectoryChunk>(dllNames.back()); |
596 | 48 | dir->lookupTab = lookups[base]; |
597 | 48 | dir->addressTab = addresses[base]; |
598 | 48 | dirs.push_back(dir); |
599 | 48 | } |
600 | 49 | // Add null terminator. |
601 | 49 | dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry))); |
602 | 49 | } |
603 | | |
604 | 5 | std::vector<Chunk *> DelayLoadContents::getChunks() { |
605 | 5 | std::vector<Chunk *> v; |
606 | 5 | v.insert(v.end(), dirs.begin(), dirs.end()); |
607 | 5 | v.insert(v.end(), names.begin(), names.end()); |
608 | 5 | v.insert(v.end(), hintNames.begin(), hintNames.end()); |
609 | 5 | v.insert(v.end(), dllNames.begin(), dllNames.end()); |
610 | 5 | return v; |
611 | 5 | } |
612 | | |
613 | 5 | std::vector<Chunk *> DelayLoadContents::getDataChunks() { |
614 | 5 | std::vector<Chunk *> v; |
615 | 5 | v.insert(v.end(), moduleHandles.begin(), moduleHandles.end()); |
616 | 5 | v.insert(v.end(), addresses.begin(), addresses.end()); |
617 | 5 | return v; |
618 | 5 | } |
619 | | |
620 | 5 | uint64_t DelayLoadContents::getDirSize() { |
621 | 5 | return dirs.size() * sizeof(delay_import_directory_table_entry); |
622 | 5 | } |
623 | | |
624 | 5 | void DelayLoadContents::create(Defined *h) { |
625 | 5 | helper = h; |
626 | 5 | std::vector<std::vector<DefinedImportData *>> v = binImports(imports); |
627 | 5 | |
628 | 5 | // Create .didat contents for each DLL. |
629 | 6 | for (std::vector<DefinedImportData *> &syms : v) { |
630 | 6 | // Create the delay import table header. |
631 | 6 | dllNames.push_back(make<StringChunk>(syms[0]->getDLLName())); |
632 | 6 | auto *dir = make<DelayDirectoryChunk>(dllNames.back()); |
633 | 6 | |
634 | 6 | size_t base = addresses.size(); |
635 | 6 | Chunk *tm = newTailMergeChunk(dir); |
636 | 11 | for (DefinedImportData *s : syms) { |
637 | 11 | Chunk *t = newThunkChunk(s, tm); |
638 | 11 | auto *a = make<DelayAddressChunk>(t); |
639 | 11 | addresses.push_back(a); |
640 | 11 | thunks.push_back(t); |
641 | 11 | StringRef extName = s->getExternalName(); |
642 | 11 | if (extName.empty()) { |
643 | 1 | names.push_back(make<OrdinalOnlyChunk>(s->getOrdinal())); |
644 | 10 | } else { |
645 | 10 | auto *c = make<HintNameChunk>(extName, 0); |
646 | 10 | names.push_back(make<LookupChunk>(c)); |
647 | 10 | hintNames.push_back(c); |
648 | 10 | } |
649 | 11 | } |
650 | 6 | thunks.push_back(tm); |
651 | 6 | // Terminate with null values. |
652 | 6 | addresses.push_back(make<NullChunk>(8)); |
653 | 6 | names.push_back(make<NullChunk>(8)); |
654 | 6 | |
655 | 17 | for (int i = 0, e = syms.size(); i < e; ++i11 ) |
656 | 11 | syms[i]->setLocation(addresses[base + i]); |
657 | 6 | auto *mh = make<NullChunk>(8); |
658 | 6 | mh->setAlignment(8); |
659 | 6 | moduleHandles.push_back(mh); |
660 | 6 | |
661 | 6 | // Fill the delay import table header fields. |
662 | 6 | dir->moduleHandle = mh; |
663 | 6 | dir->addressTab = addresses[base]; |
664 | 6 | dir->nameTab = names[base]; |
665 | 6 | dirs.push_back(dir); |
666 | 6 | } |
667 | 5 | // Add null terminator. |
668 | 5 | dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry))); |
669 | 5 | } |
670 | | |
671 | 6 | Chunk *DelayLoadContents::newTailMergeChunk(Chunk *dir) { |
672 | 6 | switch (config->machine) { |
673 | 6 | case AMD64: |
674 | 3 | return make<TailMergeChunkX64>(dir, helper); |
675 | 6 | case I386: |
676 | 1 | return make<TailMergeChunkX86>(dir, helper); |
677 | 6 | case ARMNT: |
678 | 1 | return make<TailMergeChunkARM>(dir, helper); |
679 | 6 | case ARM64: |
680 | 1 | return make<TailMergeChunkARM64>(dir, helper); |
681 | 6 | default: |
682 | 0 | llvm_unreachable("unsupported machine type"); |
683 | 6 | } |
684 | 6 | } |
685 | | |
686 | | Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *s, |
687 | 11 | Chunk *tailMerge) { |
688 | 11 | switch (config->machine) { |
689 | 11 | case AMD64: |
690 | 7 | return make<ThunkChunkX64>(s, tailMerge); |
691 | 11 | case I386: |
692 | 2 | return make<ThunkChunkX86>(s, tailMerge); |
693 | 11 | case ARMNT: |
694 | 1 | return make<ThunkChunkARM>(s, tailMerge); |
695 | 11 | case ARM64: |
696 | 1 | return make<ThunkChunkARM64>(s, tailMerge); |
697 | 11 | default: |
698 | 0 | llvm_unreachable("unsupported machine type"); |
699 | 11 | } |
700 | 11 | } |
701 | | |
702 | 576 | EdataContents::EdataContents() { |
703 | 576 | uint16_t maxOrdinal = 0; |
704 | 576 | for (Export &e : config->exports) |
705 | 209 | maxOrdinal = std::max(maxOrdinal, e.ordinal); |
706 | 576 | |
707 | 576 | auto *dllName = make<StringChunk>(sys::path::filename(config->outputFile)); |
708 | 576 | auto *addressTab = make<AddressTableChunk>(maxOrdinal); |
709 | 576 | std::vector<Chunk *> names; |
710 | 576 | for (Export &e : config->exports) |
711 | 209 | if (!e.noname) |
712 | 207 | names.push_back(make<StringChunk>(e.exportName)); |
713 | 576 | |
714 | 576 | std::vector<Chunk *> forwards; |
715 | 576 | for (Export &e : config->exports) { |
716 | 209 | if (e.forwardTo.empty()) |
717 | 207 | continue; |
718 | 2 | e.forwardChunk = make<StringChunk>(e.forwardTo); |
719 | 2 | forwards.push_back(e.forwardChunk); |
720 | 2 | } |
721 | 576 | |
722 | 576 | auto *nameTab = make<NamePointersChunk>(names); |
723 | 576 | auto *ordinalTab = make<ExportOrdinalChunk>(names.size()); |
724 | 576 | auto *dir = make<ExportDirectoryChunk>(maxOrdinal, names.size(), dllName, |
725 | 576 | addressTab, nameTab, ordinalTab); |
726 | 576 | chunks.push_back(dir); |
727 | 576 | chunks.push_back(dllName); |
728 | 576 | chunks.push_back(addressTab); |
729 | 576 | chunks.push_back(nameTab); |
730 | 576 | chunks.push_back(ordinalTab); |
731 | 576 | chunks.insert(chunks.end(), names.begin(), names.end()); |
732 | 576 | chunks.insert(chunks.end(), forwards.begin(), forwards.end()); |
733 | 576 | } |
734 | | |
735 | | } // namespace coff |
736 | | } // namespace lld |