/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/lld/COFF/Chunks.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- Chunks.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 | | #include "Chunks.h" |
11 | | #include "Error.h" |
12 | | #include "InputFiles.h" |
13 | | #include "Symbols.h" |
14 | | #include "Writer.h" |
15 | | #include "llvm/ADT/Twine.h" |
16 | | #include "llvm/BinaryFormat/COFF.h" |
17 | | #include "llvm/Object/COFF.h" |
18 | | #include "llvm/Support/Debug.h" |
19 | | #include "llvm/Support/Endian.h" |
20 | | #include "llvm/Support/raw_ostream.h" |
21 | | #include <algorithm> |
22 | | |
23 | | using namespace llvm; |
24 | | using namespace llvm::object; |
25 | | using namespace llvm::support::endian; |
26 | | using namespace llvm::COFF; |
27 | | using llvm::support::ulittle32_t; |
28 | | |
29 | | namespace lld { |
30 | | namespace coff { |
31 | | |
32 | | SectionChunk::SectionChunk(ObjFile *F, const coff_section *H) |
33 | | : Chunk(SectionKind), Repl(this), Header(H), File(F), |
34 | | Relocs(File->getCOFFObj()->getRelocations(Header)), |
35 | 821 | NumRelocs(std::distance(Relocs.begin(), Relocs.end())) { |
36 | 821 | // Initialize SectionName. |
37 | 821 | File->getCOFFObj()->getSectionName(Header, SectionName); |
38 | 821 | |
39 | 821 | Alignment = Header->getAlignment(); |
40 | 821 | |
41 | 821 | // Chunks may be discarded during comdat merging. |
42 | 821 | Discarded = false; |
43 | 821 | |
44 | 821 | // If linker GC is disabled, every chunk starts out alive. If linker GC is |
45 | 821 | // enabled, treat non-comdat sections as roots. Generally optimized object |
46 | 821 | // files will be built with -ffunction-sections or /Gy, so most things worth |
47 | 821 | // stripping will be in a comdat. |
48 | 796 | Live = !Config->DoGC || !isCOMDAT(); |
49 | 821 | } |
50 | | |
51 | 99 | static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } |
52 | 416 | static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } |
53 | 55 | static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } |
54 | 8 | static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); } |
55 | 3 | static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); } |
56 | | |
57 | | static void applySecRel(const SectionChunk *Sec, uint8_t *Off, |
58 | 110 | OutputSection *OS, uint64_t S) { |
59 | 110 | if (!OS110 ) { |
60 | 2 | if (Sec->isCodeView()) |
61 | 2 | return; |
62 | 0 | fatal("SECREL relocation cannot be applied to absolute symbols"); |
63 | 0 | } |
64 | 108 | uint64_t SecRel = S - OS->getRVA(); |
65 | 108 | if (SecRel > UINT32_MAX108 ) { |
66 | 0 | error("overflow in SECREL relocation in section: " + Sec->getSectionName()); |
67 | 0 | return; |
68 | 0 | } |
69 | 108 | add32(Off, SecRel); |
70 | 108 | } |
71 | | |
72 | 99 | static void applySecIdx(uint8_t *Off, OutputSection *OS) { |
73 | 99 | // If we have no output section, this must be an absolute symbol. Use the |
74 | 99 | // sentinel absolute symbol section index. |
75 | 99 | uint16_t SecIdx = OS ? OS->SectionIndex96 : DefinedAbsolute::OutputSectionIndex3 ; |
76 | 99 | add16(Off, SecIdx); |
77 | 99 | } |
78 | | |
79 | | void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, |
80 | 457 | uint64_t S, uint64_t P) const { |
81 | 457 | switch (Type) { |
82 | 8 | case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break; |
83 | 54 | case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break; |
84 | 130 | case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break; |
85 | 115 | case IMAGE_REL_AMD64_REL32: add32(Off, S - P - 4); break; |
86 | 1 | case IMAGE_REL_AMD64_REL32_1: add32(Off, S - P - 5); break; |
87 | 1 | case IMAGE_REL_AMD64_REL32_2: add32(Off, S - P - 6); break; |
88 | 1 | case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break; |
89 | 1 | case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break; |
90 | 1 | case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break; |
91 | 73 | case IMAGE_REL_AMD64_SECTION: applySecIdx(Off, OS); break; |
92 | 72 | case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, OS, S); break; |
93 | 0 | default: |
94 | 0 | fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); |
95 | 458 | } |
96 | 458 | } |
97 | | |
98 | | void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, |
99 | 112 | uint64_t S, uint64_t P) const { |
100 | 112 | switch (Type) { |
101 | 1 | case IMAGE_REL_I386_ABSOLUTE: break; |
102 | 26 | case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break; |
103 | 4 | case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; |
104 | 18 | case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; |
105 | 26 | case IMAGE_REL_I386_SECTION: applySecIdx(Off, OS); break; |
106 | 37 | case IMAGE_REL_I386_SECREL: applySecRel(this, Off, OS, S); break; |
107 | 0 | default: |
108 | 0 | fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); |
109 | 112 | } |
110 | 112 | } |
111 | | |
112 | 18 | static void applyMOV(uint8_t *Off, uint16_t V) { |
113 | 18 | write16le(Off, (read16le(Off) & 0xfbf0) | ((V & 0x800) >> 1) | ((V >> 12) & 0xf)); |
114 | 18 | write16le(Off + 2, (read16le(Off + 2) & 0x8f00) | ((V & 0x700) << 4) | (V & 0xff)); |
115 | 18 | } |
116 | | |
117 | 18 | static uint16_t readMOV(uint8_t *Off) { |
118 | 18 | uint16_t Opcode1 = read16le(Off); |
119 | 18 | uint16_t Opcode2 = read16le(Off + 2); |
120 | 18 | uint16_t Imm = (Opcode2 & 0x00ff) | ((Opcode2 >> 4) & 0x0700); |
121 | 18 | Imm |= ((Opcode1 << 1) & 0x0800) | ((Opcode1 & 0x000f) << 12); |
122 | 18 | return Imm; |
123 | 18 | } |
124 | | |
125 | 9 | void applyMOV32T(uint8_t *Off, uint32_t V) { |
126 | 9 | uint16_t ImmW = readMOV(Off); // read MOVW operand |
127 | 9 | uint16_t ImmT = readMOV(Off + 4); // read MOVT operand |
128 | 9 | uint32_t Imm = ImmW | (ImmT << 16); |
129 | 9 | V += Imm; // add the immediate offset |
130 | 9 | applyMOV(Off, V); // set MOVW operand |
131 | 9 | applyMOV(Off + 4, V >> 16); // set MOVT operand |
132 | 9 | } |
133 | | |
134 | 1 | static void applyBranch20T(uint8_t *Off, int32_t V) { |
135 | 1 | uint32_t S = V < 0 ? 11 : 00 ; |
136 | 1 | uint32_t J1 = (V >> 19) & 1; |
137 | 1 | uint32_t J2 = (V >> 18) & 1; |
138 | 1 | or16(Off, (S << 10) | ((V >> 12) & 0x3f)); |
139 | 1 | or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); |
140 | 1 | } |
141 | | |
142 | 6 | void applyBranch24T(uint8_t *Off, int32_t V) { |
143 | 6 | if (!isInt<25>(V)) |
144 | 0 | fatal("relocation out of range"); |
145 | 6 | uint32_t S = V < 0 ? 6 15 : 01 ; |
146 | 6 | uint32_t J1 = ((~V >> 23) & 1) ^ S; |
147 | 6 | uint32_t J2 = ((~V >> 22) & 1) ^ S; |
148 | 6 | or16(Off, (S << 10) | ((V >> 12) & 0x3ff)); |
149 | 6 | // Clear out the J1 and J2 bits which may be set. |
150 | 6 | write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); |
151 | 6 | } |
152 | | |
153 | | void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, |
154 | 14 | uint64_t S, uint64_t P) const { |
155 | 14 | // Pointer to thumb code must have the LSB set. |
156 | 14 | uint64_t SX = S; |
157 | 14 | if (OS && 14 (OS->getPermissions() & IMAGE_SCN_MEM_EXECUTE)14 ) |
158 | 11 | SX |= 1; |
159 | 14 | switch (Type) { |
160 | 1 | case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break; |
161 | 1 | case IMAGE_REL_ARM_ADDR32NB: add32(Off, SX); break; |
162 | 5 | case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, SX + Config->ImageBase); break; |
163 | 1 | case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, SX - P - 4); break; |
164 | 3 | case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, SX - P - 4); break; |
165 | 2 | case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, SX - P - 4); break; |
166 | 0 | case IMAGE_REL_ARM_SECTION: applySecIdx(Off, OS); break; |
167 | 1 | case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, OS, S); break; |
168 | 0 | default: |
169 | 0 | fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); |
170 | 14 | } |
171 | 14 | } |
172 | | |
173 | | // Interpret the existing immediate value as a byte offset to the |
174 | | // target symbol, then update the instruction with the immediate as |
175 | | // the page offset from the current instruction to the target. |
176 | 5 | static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P) { |
177 | 5 | uint32_t Orig = read32le(Off); |
178 | 5 | uint64_t Imm = ((Orig >> 29) & 0x3) | ((Orig >> 3) & 0x1FFFFC); |
179 | 5 | S += Imm; |
180 | 5 | Imm = (S >> 12) - (P >> 12); |
181 | 5 | uint32_t ImmLo = (Imm & 0x3) << 29; |
182 | 5 | uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; |
183 | 5 | uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); |
184 | 5 | write32le(Off, (Orig & ~Mask) | ImmLo | ImmHi); |
185 | 5 | } |
186 | | |
187 | | // Update the immediate field in a AARCH64 ldr, str, and add instruction. |
188 | | // Optionally limit the range of the written immediate by one or more bits |
189 | | // (RangeLimit). |
190 | 24 | static void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit) { |
191 | 24 | uint32_t Orig = read32le(Off); |
192 | 24 | Imm += (Orig >> 10) & 0xFFF; |
193 | 24 | Orig &= ~(0xFFF << 10); |
194 | 24 | write32le(Off, Orig | ((Imm & (0xFFF >> RangeLimit)) << 10)); |
195 | 24 | } |
196 | | |
197 | | // Add the 12 bit page offset to the existing immediate. |
198 | | // Ldr/str instructions store the opcode immediate scaled |
199 | | // by the load/store size (giving a larger range for larger |
200 | | // loads/stores). The immediate is always (both before and after |
201 | | // fixing up the relocation) stored scaled similarly. |
202 | | // Even if larger loads/stores have a larger range, limit the |
203 | | // effective offset to 12 bit, since it is intended to be a |
204 | | // page offset. |
205 | 23 | static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) { |
206 | 23 | uint32_t Orig = read32le(Off); |
207 | 23 | uint32_t Size = Orig >> 30; |
208 | 23 | // 0x04000000 indicates SIMD/FP registers |
209 | 23 | // 0x00800000 indicates 128 bit |
210 | 23 | if ((Orig & 0x4800000) == 0x4800000) |
211 | 2 | Size += 4; |
212 | 23 | if ((Imm & ((1 << Size) - 1)) != 0) |
213 | 0 | fatal("misaligned ldr/str offset"); |
214 | 23 | applyArm64Imm(Off, Imm >> Size, Size); |
215 | 23 | } |
216 | | |
217 | | void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, |
218 | 27 | uint64_t S, uint64_t P) const { |
219 | 27 | switch (Type) { |
220 | 2 | case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P); break; |
221 | 1 | case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff, 0); break; |
222 | 20 | case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break; |
223 | 3 | case IMAGE_REL_ARM64_BRANCH26: or32(Off, ((S - P) & 0x0FFFFFFC) >> 2); break; |
224 | 0 | case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break; |
225 | 1 | case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break; |
226 | 0 | default: |
227 | 0 | fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); |
228 | 27 | } |
229 | 27 | } |
230 | | |
231 | 505 | void SectionChunk::writeTo(uint8_t *Buf) const { |
232 | 505 | if (!hasData()) |
233 | 5 | return; |
234 | 500 | // Copy section contents from source object file to output file. |
235 | 500 | ArrayRef<uint8_t> A = getContents(); |
236 | 500 | memcpy(Buf + OutputSectionOff, A.data(), A.size()); |
237 | 500 | |
238 | 500 | // Apply relocations. |
239 | 500 | size_t InputSize = getSize(); |
240 | 615 | for (const coff_relocation &Rel : Relocs) { |
241 | 615 | // Check for an invalid relocation offset. This check isn't perfect, because |
242 | 615 | // we don't have the relocation size, which is only known after checking the |
243 | 615 | // machine and relocation type. As a result, a relocation may overwrite the |
244 | 615 | // beginning of the following input section. |
245 | 615 | if (Rel.VirtualAddress >= InputSize) |
246 | 0 | fatal("relocation points beyond the end of its parent section"); |
247 | 615 | |
248 | 615 | uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress; |
249 | 615 | |
250 | 615 | // Get the output section of the symbol for this relocation. The output |
251 | 615 | // section is needed to compute SECREL and SECTION relocations used in debug |
252 | 615 | // info. |
253 | 615 | SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex); |
254 | 615 | Defined *Sym = cast<Defined>(Body); |
255 | 615 | Chunk *C = Sym->getChunk(); |
256 | 615 | OutputSection *OS = C ? C->getOutputSection()576 : nullptr39 ; |
257 | 615 | |
258 | 615 | // Only absolute and __ImageBase symbols lack an output section. For any |
259 | 615 | // other symbol, this indicates that the chunk was discarded. Normally |
260 | 615 | // relocations against discarded sections are an error. However, debug info |
261 | 615 | // sections are not GC roots and can end up with these kinds of relocations. |
262 | 615 | // Skip these relocations. |
263 | 615 | if (!OS && 615 !isa<DefinedAbsolute>(Sym)42 && !isa<DefinedSynthetic>(Sym)20 ) { |
264 | 5 | if (isCodeView() || 5 isDWARF()1 ) |
265 | 5 | continue; |
266 | 0 | fatal("relocation against symbol in discarded section: " + |
267 | 0 | Sym->getName()); |
268 | 0 | } |
269 | 610 | uint64_t S = Sym->getRVA(); |
270 | 610 | |
271 | 610 | // Compute the RVA of the relocation for relative relocations. |
272 | 610 | uint64_t P = RVA + Rel.VirtualAddress; |
273 | 610 | switch (Config->Machine) { |
274 | 457 | case AMD64: |
275 | 457 | applyRelX64(Off, Rel.Type, OS, S, P); |
276 | 457 | break; |
277 | 112 | case I386: |
278 | 112 | applyRelX86(Off, Rel.Type, OS, S, P); |
279 | 112 | break; |
280 | 14 | case ARMNT: |
281 | 14 | applyRelARM(Off, Rel.Type, OS, S, P); |
282 | 14 | break; |
283 | 27 | case ARM64: |
284 | 27 | applyRelARM64(Off, Rel.Type, OS, S, P); |
285 | 27 | break; |
286 | 0 | default: |
287 | 0 | llvm_unreachable("unknown machine type"); |
288 | 501 | } |
289 | 501 | } |
290 | 505 | } |
291 | | |
292 | 14 | void SectionChunk::addAssociative(SectionChunk *Child) { |
293 | 14 | AssocChildren.push_back(Child); |
294 | 14 | } |
295 | | |
296 | 408 | static uint8_t getBaserelType(const coff_relocation &Rel) { |
297 | 408 | switch (Config->Machine) { |
298 | 307 | case AMD64: |
299 | 307 | if (Rel.Type == IMAGE_REL_AMD64_ADDR64) |
300 | 47 | return IMAGE_REL_BASED_DIR64; |
301 | 260 | return IMAGE_REL_BASED_ABSOLUTE; |
302 | 60 | case I386: |
303 | 60 | if (Rel.Type == IMAGE_REL_I386_DIR32) |
304 | 26 | return IMAGE_REL_BASED_HIGHLOW; |
305 | 34 | return IMAGE_REL_BASED_ABSOLUTE; |
306 | 14 | case ARMNT: |
307 | 14 | if (Rel.Type == IMAGE_REL_ARM_ADDR32) |
308 | 1 | return IMAGE_REL_BASED_HIGHLOW; |
309 | 13 | if (13 Rel.Type == IMAGE_REL_ARM_MOV32T13 ) |
310 | 5 | return IMAGE_REL_BASED_ARM_MOV32T; |
311 | 8 | return IMAGE_REL_BASED_ABSOLUTE; |
312 | 27 | case ARM64: |
313 | 27 | if (Rel.Type == IMAGE_REL_ARM64_ADDR64) |
314 | 1 | return IMAGE_REL_BASED_DIR64; |
315 | 26 | return IMAGE_REL_BASED_ABSOLUTE; |
316 | 0 | default: |
317 | 0 | llvm_unreachable("unknown machine type"); |
318 | 0 | } |
319 | 0 | } |
320 | | |
321 | | // Windows-specific. |
322 | | // Collect all locations that contain absolute addresses, which need to be |
323 | | // fixed by the loader if load-time relocation is needed. |
324 | | // Only called when base relocation is enabled. |
325 | 706 | void SectionChunk::getBaserels(std::vector<Baserel> *Res) { |
326 | 408 | for (const coff_relocation &Rel : Relocs) { |
327 | 408 | uint8_t Ty = getBaserelType(Rel); |
328 | 408 | if (Ty == IMAGE_REL_BASED_ABSOLUTE) |
329 | 328 | continue; |
330 | 80 | SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex); |
331 | 80 | if (isa<DefinedAbsolute>(Body)) |
332 | 14 | continue; |
333 | 66 | Res->emplace_back(RVA + Rel.VirtualAddress, Ty); |
334 | 66 | } |
335 | 706 | } |
336 | | |
337 | 1.22k | bool SectionChunk::hasData() const { |
338 | 1.22k | return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA); |
339 | 1.22k | } |
340 | | |
341 | 2.17k | uint32_t SectionChunk::getPermissions() const { |
342 | 2.17k | return Header->Characteristics & PermMask; |
343 | 2.17k | } |
344 | | |
345 | 4.38k | bool SectionChunk::isCOMDAT() const { |
346 | 4.38k | return Header->Characteristics & IMAGE_SCN_LNK_COMDAT; |
347 | 4.38k | } |
348 | | |
349 | 11 | void SectionChunk::printDiscardedMessage() const { |
350 | 11 | // Removed by dead-stripping. If it's removed by ICF, ICF already |
351 | 11 | // printed out the name, so don't repeat that here. |
352 | 11 | if (Sym && 11 this == Repl11 ) { |
353 | 4 | if (Discarded) |
354 | 0 | message("Discarded comdat symbol " + Sym->getName()); |
355 | 4 | else if (4 !Live4 ) |
356 | 4 | message("Discarded " + Sym->getName()); |
357 | 4 | } |
358 | 11 | } |
359 | | |
360 | 13 | StringRef SectionChunk::getDebugName() { |
361 | 13 | if (Sym) |
362 | 13 | return Sym->getName(); |
363 | 0 | return ""; |
364 | 0 | } |
365 | | |
366 | 664 | ArrayRef<uint8_t> SectionChunk::getContents() const { |
367 | 664 | ArrayRef<uint8_t> A; |
368 | 664 | File->getCOFFObj()->getSectionContents(Header, A); |
369 | 664 | return A; |
370 | 664 | } |
371 | | |
372 | 7 | void SectionChunk::replace(SectionChunk *Other) { |
373 | 7 | Other->Repl = Repl; |
374 | 7 | Other->Live = false; |
375 | 7 | } |
376 | | |
377 | 10 | CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) { |
378 | 10 | // Common symbols are aligned on natural boundaries up to 32 bytes. |
379 | 10 | // This is what MSVC link.exe does. |
380 | 10 | Alignment = std::min(uint64_t(32), PowerOf2Ceil(Sym.getValue())); |
381 | 10 | } |
382 | | |
383 | 10 | uint32_t CommonChunk::getPermissions() const { |
384 | 10 | return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | |
385 | 10 | IMAGE_SCN_MEM_WRITE; |
386 | 10 | } |
387 | | |
388 | 149 | void StringChunk::writeTo(uint8_t *Buf) const { |
389 | 149 | memcpy(Buf + OutputSectionOff, Str.data(), Str.size()); |
390 | 149 | } |
391 | | |
392 | 46 | ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImpSymbol(S) { |
393 | 46 | // Intel Optimization Manual says that all branch targets |
394 | 46 | // should be 16-byte aligned. MSVC linker does this too. |
395 | 46 | Alignment = 16; |
396 | 46 | } |
397 | | |
398 | 44 | void ImportThunkChunkX64::writeTo(uint8_t *Buf) const { |
399 | 44 | memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); |
400 | 44 | // The first two bytes is a JMP instruction. Fill its operand. |
401 | 44 | write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() - RVA - getSize()); |
402 | 44 | } |
403 | | |
404 | 12 | void ImportThunkChunkX86::getBaserels(std::vector<Baserel> *Res) { |
405 | 12 | Res->emplace_back(getRVA() + 2); |
406 | 12 | } |
407 | | |
408 | 12 | void ImportThunkChunkX86::writeTo(uint8_t *Buf) const { |
409 | 12 | memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); |
410 | 12 | // The first two bytes is a JMP instruction. Fill its operand. |
411 | 12 | write32le(Buf + OutputSectionOff + 2, |
412 | 12 | ImpSymbol->getRVA() + Config->ImageBase); |
413 | 12 | } |
414 | | |
415 | 2 | void ImportThunkChunkARM::getBaserels(std::vector<Baserel> *Res) { |
416 | 2 | Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T); |
417 | 2 | } |
418 | | |
419 | 2 | void ImportThunkChunkARM::writeTo(uint8_t *Buf) const { |
420 | 2 | memcpy(Buf + OutputSectionOff, ImportThunkARM, sizeof(ImportThunkARM)); |
421 | 2 | // Fix mov.w and mov.t operands. |
422 | 2 | applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase); |
423 | 2 | } |
424 | | |
425 | 3 | void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const { |
426 | 3 | int64_t Off = ImpSymbol->getRVA() & 0xfff; |
427 | 3 | memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64)); |
428 | 3 | applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA); |
429 | 3 | applyArm64Ldr(Buf + OutputSectionOff + 4, Off); |
430 | 3 | } |
431 | | |
432 | 2 | void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) { |
433 | 2 | Res->emplace_back(getRVA()); |
434 | 2 | } |
435 | | |
436 | 2 | size_t LocalImportChunk::getSize() const { |
437 | 2 | return Config->is64() ? 81 : 41 ; |
438 | 2 | } |
439 | | |
440 | 2 | void LocalImportChunk::writeTo(uint8_t *Buf) const { |
441 | 2 | if (Config->is64()2 ) { |
442 | 1 | write64le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); |
443 | 2 | } else { |
444 | 1 | write32le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); |
445 | 1 | } |
446 | 2 | } |
447 | | |
448 | 2 | void SEHTableChunk::writeTo(uint8_t *Buf) const { |
449 | 2 | ulittle32_t *Begin = reinterpret_cast<ulittle32_t *>(Buf + OutputSectionOff); |
450 | 2 | size_t Cnt = 0; |
451 | 2 | for (Defined *D : Syms) |
452 | 3 | Begin[Cnt++] = D->getRVA(); |
453 | 2 | std::sort(Begin, Begin + Cnt); |
454 | 2 | } |
455 | | |
456 | | // Windows-specific. This class represents a block in .reloc section. |
457 | | // The format is described here. |
458 | | // |
459 | | // On Windows, each DLL is linked against a fixed base address and |
460 | | // usually loaded to that address. However, if there's already another |
461 | | // DLL that overlaps, the loader has to relocate it. To do that, DLLs |
462 | | // contain .reloc sections which contain offsets that need to be fixed |
463 | | // up at runtime. If the loader finds that a DLL cannot be loaded to its |
464 | | // desired base address, it loads it to somewhere else, and add <actual |
465 | | // base address> - <desired base address> to each offset that is |
466 | | // specified by the .reloc section. In ELF terms, .reloc sections |
467 | | // contain relative relocations in REL format (as opposed to RELA.) |
468 | | // |
469 | | // This already significantly reduces the size of relocations compared |
470 | | // to ELF .rel.dyn, but Windows does more to reduce it (probably because |
471 | | // it was invented for PCs in the late '80s or early '90s.) Offsets in |
472 | | // .reloc are grouped by page where the page size is 12 bits, and |
473 | | // offsets sharing the same page address are stored consecutively to |
474 | | // represent them with less space. This is very similar to the page |
475 | | // table which is grouped by (multiple stages of) pages. |
476 | | // |
477 | | // For example, let's say we have 0x00030, 0x00500, 0x00700, 0x00A00, |
478 | | // 0x20004, and 0x20008 in a .reloc section for x64. The uppermost 4 |
479 | | // bits have a type IMAGE_REL_BASED_DIR64 or 0xA. In the section, they |
480 | | // are represented like this: |
481 | | // |
482 | | // 0x00000 -- page address (4 bytes) |
483 | | // 16 -- size of this block (4 bytes) |
484 | | // 0xA030 -- entries (2 bytes each) |
485 | | // 0xA500 |
486 | | // 0xA700 |
487 | | // 0xAA00 |
488 | | // 0x20000 -- page address (4 bytes) |
489 | | // 12 -- size of this block (4 bytes) |
490 | | // 0xA004 -- entries (2 bytes each) |
491 | | // 0xA008 |
492 | | // |
493 | | // Usually we have a lot of relocations for each page, so the number of |
494 | | // bytes for one .reloc entry is close to 2 bytes on average. |
495 | 41 | BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) { |
496 | 41 | // Block header consists of 4 byte page RVA and 4 byte block size. |
497 | 41 | // Each entry is 2 byte. Last entry may be padding. |
498 | 41 | Data.resize(alignTo((End - Begin) * 2 + 8, 4)); |
499 | 41 | uint8_t *P = Data.data(); |
500 | 41 | write32le(P, Page); |
501 | 41 | write32le(P + 4, Data.size()); |
502 | 41 | P += 8; |
503 | 135 | for (Baserel *I = Begin; I != End135 ; ++I94 ) { |
504 | 94 | write16le(P, (I->Type << 12) | (I->RVA - Page)); |
505 | 94 | P += 2; |
506 | 94 | } |
507 | 41 | } |
508 | | |
509 | 41 | void BaserelChunk::writeTo(uint8_t *Buf) const { |
510 | 41 | memcpy(Buf + OutputSectionOff, Data.data(), Data.size()); |
511 | 41 | } |
512 | | |
513 | 24 | uint8_t Baserel::getDefaultType() { |
514 | 24 | switch (Config->Machine) { |
515 | 4 | case AMD64: |
516 | 4 | return IMAGE_REL_BASED_DIR64; |
517 | 20 | case I386: |
518 | 20 | case ARMNT: |
519 | 20 | return IMAGE_REL_BASED_HIGHLOW; |
520 | 0 | default: |
521 | 0 | llvm_unreachable("unknown machine type"); |
522 | 0 | } |
523 | 0 | } |
524 | | |
525 | | } // namespace coff |
526 | | } // namespace lld |