Coverage Report

Created: 2017-09-19 22:28

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