]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lld/COFF/Chunks.cpp
Update to tcsh 6.20.00
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lld / COFF / Chunks.cpp
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 "llvm/Object/COFF.h"
15 #include "llvm/Support/COFF.h"
16 #include "llvm/Support/Debug.h"
17 #include "llvm/Support/Endian.h"
18 #include "llvm/Support/raw_ostream.h"
19 #include <algorithm>
20
21 using namespace llvm;
22 using namespace llvm::object;
23 using namespace llvm::support::endian;
24 using namespace llvm::COFF;
25 using llvm::support::ulittle32_t;
26
27 namespace lld {
28 namespace coff {
29
30 SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H)
31     : Chunk(SectionKind), Repl(this), Header(H), File(F),
32       Relocs(File->getCOFFObj()->getRelocations(Header)),
33       NumRelocs(std::distance(Relocs.begin(), Relocs.end())) {
34   // Initialize SectionName.
35   File->getCOFFObj()->getSectionName(Header, SectionName);
36
37   Align = Header->getAlignment();
38
39   // Only COMDAT sections are subject of dead-stripping.
40   Live = !isCOMDAT();
41 }
42
43 static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
44 static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
45 static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); }
46 static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); }
47
48 void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym,
49                                uint64_t P) const {
50   uint64_t S = Sym->getRVA();
51   switch (Type) {
52   case IMAGE_REL_AMD64_ADDR32:   add32(Off, S + Config->ImageBase); break;
53   case IMAGE_REL_AMD64_ADDR64:   add64(Off, S + Config->ImageBase); break;
54   case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break;
55   case IMAGE_REL_AMD64_REL32:    add32(Off, S - P - 4); break;
56   case IMAGE_REL_AMD64_REL32_1:  add32(Off, S - P - 5); break;
57   case IMAGE_REL_AMD64_REL32_2:  add32(Off, S - P - 6); break;
58   case IMAGE_REL_AMD64_REL32_3:  add32(Off, S - P - 7); break;
59   case IMAGE_REL_AMD64_REL32_4:  add32(Off, S - P - 8); break;
60   case IMAGE_REL_AMD64_REL32_5:  add32(Off, S - P - 9); break;
61   case IMAGE_REL_AMD64_SECTION:  add16(Off, Sym->getSectionIndex()); break;
62   case IMAGE_REL_AMD64_SECREL:   add32(Off, Sym->getSecrel()); break;
63   default:
64     fatal("unsupported relocation type");
65   }
66 }
67
68 void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym,
69                                uint64_t P) const {
70   uint64_t S = Sym->getRVA();
71   switch (Type) {
72   case IMAGE_REL_I386_ABSOLUTE: break;
73   case IMAGE_REL_I386_DIR32:    add32(Off, S + Config->ImageBase); break;
74   case IMAGE_REL_I386_DIR32NB:  add32(Off, S); break;
75   case IMAGE_REL_I386_REL32:    add32(Off, S - P - 4); break;
76   case IMAGE_REL_I386_SECTION:  add16(Off, Sym->getSectionIndex()); break;
77   case IMAGE_REL_I386_SECREL:   add32(Off, Sym->getSecrel()); break;
78   default:
79     fatal("unsupported relocation type");
80   }
81 }
82
83 static void applyMOV(uint8_t *Off, uint16_t V) {
84   write16le(Off, (read16le(Off) & 0xfbf0) | ((V & 0x800) >> 1) | ((V >> 12) & 0xf));
85   write16le(Off + 2, (read16le(Off + 2) & 0x8f00) | ((V & 0x700) << 4) | (V & 0xff));
86 }
87
88 static uint16_t readMOV(uint8_t *Off) {
89   uint16_t Opcode1 = read16le(Off);
90   uint16_t Opcode2 = read16le(Off + 2);
91   uint16_t Imm = (Opcode2 & 0x00ff) | ((Opcode2 >> 4) & 0x0700);
92   Imm |= ((Opcode1 << 1) & 0x0800) | ((Opcode1 & 0x000f) << 12);
93   return Imm;
94 }
95
96 static void applyMOV32T(uint8_t *Off, uint32_t V) {
97   uint16_t ImmW = readMOV(Off);     // read MOVW operand
98   uint16_t ImmT = readMOV(Off + 4); // read MOVT operand
99   uint32_t Imm = ImmW | (ImmT << 16);
100   V += Imm;                         // add the immediate offset
101   applyMOV(Off, V);           // set MOVW operand
102   applyMOV(Off + 4, V >> 16); // set MOVT operand
103 }
104
105 static void applyBranch20T(uint8_t *Off, int32_t V) {
106   uint32_t S = V < 0 ? 1 : 0;
107   uint32_t J1 = (V >> 19) & 1;
108   uint32_t J2 = (V >> 18) & 1;
109   or16(Off, (S << 10) | ((V >> 12) & 0x3f));
110   or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff));
111 }
112
113 static void applyBranch24T(uint8_t *Off, int32_t V) {
114   if (!isInt<25>(V))
115     fatal("relocation out of range");
116   uint32_t S = V < 0 ? 1 : 0;
117   uint32_t J1 = ((~V >> 23) & 1) ^ S;
118   uint32_t J2 = ((~V >> 22) & 1) ^ S;
119   or16(Off, (S << 10) | ((V >> 12) & 0x3ff));
120   // Clear out the J1 and J2 bits which may be set.
121   write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff));
122 }
123
124 void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym,
125                                uint64_t P) const {
126   uint64_t S = Sym->getRVA();
127   // Pointer to thumb code must have the LSB set.
128   if (Sym->isExecutable())
129     S |= 1;
130   switch (Type) {
131   case IMAGE_REL_ARM_ADDR32:    add32(Off, S + Config->ImageBase); break;
132   case IMAGE_REL_ARM_ADDR32NB:  add32(Off, S); break;
133   case IMAGE_REL_ARM_MOV32T:    applyMOV32T(Off, S + Config->ImageBase); break;
134   case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, S - P - 4); break;
135   case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, S - P - 4); break;
136   case IMAGE_REL_ARM_BLX23T:    applyBranch24T(Off, S - P - 4); break;
137   case IMAGE_REL_ARM_SECREL:    add32(Off, Sym->getSecrel()); break;
138   default:
139     fatal("unsupported relocation type");
140   }
141 }
142
143 void SectionChunk::writeTo(uint8_t *Buf) const {
144   if (!hasData())
145     return;
146   // Copy section contents from source object file to output file.
147   ArrayRef<uint8_t> A = getContents();
148   memcpy(Buf + OutputSectionOff, A.data(), A.size());
149
150   // Apply relocations.
151   for (const coff_relocation &Rel : Relocs) {
152     uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress;
153     SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex);
154     Defined *Sym = cast<Defined>(Body);
155     uint64_t P = RVA + Rel.VirtualAddress;
156     switch (Config->Machine) {
157     case AMD64:
158       applyRelX64(Off, Rel.Type, Sym, P);
159       break;
160     case I386:
161       applyRelX86(Off, Rel.Type, Sym, P);
162       break;
163     case ARMNT:
164       applyRelARM(Off, Rel.Type, Sym, P);
165       break;
166     default:
167       llvm_unreachable("unknown machine type");
168     }
169   }
170 }
171
172 void SectionChunk::addAssociative(SectionChunk *Child) {
173   AssocChildren.push_back(Child);
174 }
175
176 static uint8_t getBaserelType(const coff_relocation &Rel) {
177   switch (Config->Machine) {
178   case AMD64:
179     if (Rel.Type == IMAGE_REL_AMD64_ADDR64)
180       return IMAGE_REL_BASED_DIR64;
181     return IMAGE_REL_BASED_ABSOLUTE;
182   case I386:
183     if (Rel.Type == IMAGE_REL_I386_DIR32)
184       return IMAGE_REL_BASED_HIGHLOW;
185     return IMAGE_REL_BASED_ABSOLUTE;
186   case ARMNT:
187     if (Rel.Type == IMAGE_REL_ARM_ADDR32)
188       return IMAGE_REL_BASED_HIGHLOW;
189     if (Rel.Type == IMAGE_REL_ARM_MOV32T)
190       return IMAGE_REL_BASED_ARM_MOV32T;
191     return IMAGE_REL_BASED_ABSOLUTE;
192   default:
193     llvm_unreachable("unknown machine type");
194   }
195 }
196
197 // Windows-specific.
198 // Collect all locations that contain absolute addresses, which need to be
199 // fixed by the loader if load-time relocation is needed.
200 // Only called when base relocation is enabled.
201 void SectionChunk::getBaserels(std::vector<Baserel> *Res) {
202   for (const coff_relocation &Rel : Relocs) {
203     uint8_t Ty = getBaserelType(Rel);
204     if (Ty == IMAGE_REL_BASED_ABSOLUTE)
205       continue;
206     SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex);
207     if (isa<DefinedAbsolute>(Body))
208       continue;
209     Res->emplace_back(RVA + Rel.VirtualAddress, Ty);
210   }
211 }
212
213 bool SectionChunk::hasData() const {
214   return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA);
215 }
216
217 uint32_t SectionChunk::getPermissions() const {
218   return Header->Characteristics & PermMask;
219 }
220
221 bool SectionChunk::isCOMDAT() const {
222   return Header->Characteristics & IMAGE_SCN_LNK_COMDAT;
223 }
224
225 void SectionChunk::printDiscardedMessage() const {
226   // Removed by dead-stripping. If it's removed by ICF, ICF already
227   // printed out the name, so don't repeat that here.
228   if (Sym && this == Repl)
229     outs() << "Discarded " << Sym->getName() << "\n";
230 }
231
232 StringRef SectionChunk::getDebugName() {
233   if (Sym)
234     return Sym->getName();
235   return "";
236 }
237
238 ArrayRef<uint8_t> SectionChunk::getContents() const {
239   ArrayRef<uint8_t> A;
240   File->getCOFFObj()->getSectionContents(Header, A);
241   return A;
242 }
243
244 void SectionChunk::replace(SectionChunk *Other) {
245   Other->Repl = Repl;
246   Other->Live = false;
247 }
248
249 CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) {
250   // Common symbols are aligned on natural boundaries up to 32 bytes.
251   // This is what MSVC link.exe does.
252   Align = std::min(uint64_t(32), PowerOf2Ceil(Sym.getValue()));
253 }
254
255 uint32_t CommonChunk::getPermissions() const {
256   return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ |
257          IMAGE_SCN_MEM_WRITE;
258 }
259
260 void StringChunk::writeTo(uint8_t *Buf) const {
261   memcpy(Buf + OutputSectionOff, Str.data(), Str.size());
262 }
263
264 ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImpSymbol(S) {
265   // Intel Optimization Manual says that all branch targets
266   // should be 16-byte aligned. MSVC linker does this too.
267   Align = 16;
268 }
269
270 void ImportThunkChunkX64::writeTo(uint8_t *Buf) const {
271   memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86));
272   // The first two bytes is a JMP instruction. Fill its operand.
273   write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() - RVA - getSize());
274 }
275
276 void ImportThunkChunkX86::getBaserels(std::vector<Baserel> *Res) {
277   Res->emplace_back(getRVA() + 2);
278 }
279
280 void ImportThunkChunkX86::writeTo(uint8_t *Buf) const {
281   memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86));
282   // The first two bytes is a JMP instruction. Fill its operand.
283   write32le(Buf + OutputSectionOff + 2,
284             ImpSymbol->getRVA() + Config->ImageBase);
285 }
286
287 void ImportThunkChunkARM::getBaserels(std::vector<Baserel> *Res) {
288   Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T);
289 }
290
291 void ImportThunkChunkARM::writeTo(uint8_t *Buf) const {
292   memcpy(Buf + OutputSectionOff, ImportThunkARM, sizeof(ImportThunkARM));
293   // Fix mov.w and mov.t operands.
294   applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase);
295 }
296
297 void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) {
298   Res->emplace_back(getRVA());
299 }
300
301 size_t LocalImportChunk::getSize() const {
302   return Config->is64() ? 8 : 4;
303 }
304
305 void LocalImportChunk::writeTo(uint8_t *Buf) const {
306   if (Config->is64()) {
307     write64le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase);
308   } else {
309     write32le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase);
310   }
311 }
312
313 void SEHTableChunk::writeTo(uint8_t *Buf) const {
314   ulittle32_t *Begin = reinterpret_cast<ulittle32_t *>(Buf + OutputSectionOff);
315   size_t Cnt = 0;
316   for (Defined *D : Syms)
317     Begin[Cnt++] = D->getRVA();
318   std::sort(Begin, Begin + Cnt);
319 }
320
321 // Windows-specific.
322 // This class represents a block in .reloc section.
323 BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) {
324   // Block header consists of 4 byte page RVA and 4 byte block size.
325   // Each entry is 2 byte. Last entry may be padding.
326   Data.resize(alignTo((End - Begin) * 2 + 8, 4));
327   uint8_t *P = Data.data();
328   write32le(P, Page);
329   write32le(P + 4, Data.size());
330   P += 8;
331   for (Baserel *I = Begin; I != End; ++I) {
332     write16le(P, (I->Type << 12) | (I->RVA - Page));
333     P += 2;
334   }
335 }
336
337 void BaserelChunk::writeTo(uint8_t *Buf) const {
338   memcpy(Buf + OutputSectionOff, Data.data(), Data.size());
339 }
340
341 uint8_t Baserel::getDefaultType() {
342   switch (Config->Machine) {
343   case AMD64:
344     return IMAGE_REL_BASED_DIR64;
345   case I386:
346     return IMAGE_REL_BASED_HIGHLOW;
347   default:
348     llvm_unreachable("unknown machine type");
349   }
350 }
351
352 } // namespace coff
353 } // namespace lld