/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- X86MachObjectWriter.cpp - X86 Mach-O Writer -----------------------===// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
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 "MCTargetDesc/X86FixupKinds.h" |
11 | | #include "MCTargetDesc/X86MCTargetDesc.h" |
12 | | #include "llvm/ADT/Twine.h" |
13 | | #include "llvm/BinaryFormat/MachO.h" |
14 | | #include "llvm/MC/MCAsmInfo.h" |
15 | | #include "llvm/MC/MCAsmLayout.h" |
16 | | #include "llvm/MC/MCAssembler.h" |
17 | | #include "llvm/MC/MCContext.h" |
18 | | #include "llvm/MC/MCMachObjectWriter.h" |
19 | | #include "llvm/MC/MCSectionMachO.h" |
20 | | #include "llvm/MC/MCValue.h" |
21 | | #include "llvm/Support/ErrorHandling.h" |
22 | | #include "llvm/Support/Format.h" |
23 | | |
24 | | using namespace llvm; |
25 | | |
26 | | namespace { |
27 | | class X86MachObjectWriter : public MCMachObjectTargetWriter { |
28 | | bool recordScatteredRelocation(MachObjectWriter *Writer, |
29 | | const MCAssembler &Asm, |
30 | | const MCAsmLayout &Layout, |
31 | | const MCFragment *Fragment, |
32 | | const MCFixup &Fixup, |
33 | | MCValue Target, |
34 | | unsigned Log2Size, |
35 | | uint64_t &FixedValue); |
36 | | void recordTLVPRelocation(MachObjectWriter *Writer, |
37 | | const MCAssembler &Asm, |
38 | | const MCAsmLayout &Layout, |
39 | | const MCFragment *Fragment, |
40 | | const MCFixup &Fixup, |
41 | | MCValue Target, |
42 | | uint64_t &FixedValue); |
43 | | |
44 | | void RecordX86Relocation(MachObjectWriter *Writer, |
45 | | const MCAssembler &Asm, |
46 | | const MCAsmLayout &Layout, |
47 | | const MCFragment *Fragment, |
48 | | const MCFixup &Fixup, |
49 | | MCValue Target, |
50 | | uint64_t &FixedValue); |
51 | | void RecordX86_64Relocation(MachObjectWriter *Writer, MCAssembler &Asm, |
52 | | const MCAsmLayout &Layout, |
53 | | const MCFragment *Fragment, const MCFixup &Fixup, |
54 | | MCValue Target, uint64_t &FixedValue); |
55 | | |
56 | | public: |
57 | | X86MachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype) |
58 | 2.83k | : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {} |
59 | | |
60 | | void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm, |
61 | | const MCAsmLayout &Layout, const MCFragment *Fragment, |
62 | | const MCFixup &Fixup, MCValue Target, |
63 | 96.4k | uint64_t &FixedValue) override { |
64 | 96.4k | if (Writer->is64Bit()) |
65 | 59.4k | RecordX86_64Relocation(Writer, Asm, Layout, Fragment, Fixup, Target, |
66 | 59.4k | FixedValue); |
67 | 96.4k | else |
68 | 37.0k | RecordX86Relocation(Writer, Asm, Layout, Fragment, Fixup, Target, |
69 | 37.0k | FixedValue); |
70 | 96.4k | } |
71 | | }; |
72 | | } |
73 | | |
74 | 59.4k | static bool isFixupKindRIPRel(unsigned Kind) { |
75 | 59.4k | return Kind == X86::reloc_riprel_4byte || |
76 | 49.3k | Kind == X86::reloc_riprel_4byte_movq_load || |
77 | 47.4k | Kind == X86::reloc_riprel_4byte_relax || |
78 | 47.4k | Kind == X86::reloc_riprel_4byte_relax_rex; |
79 | 59.4k | } |
80 | | |
81 | 96.4k | static unsigned getFixupKindLog2Size(unsigned Kind) { |
82 | 96.4k | switch (Kind) { |
83 | 0 | default: |
84 | 0 | llvm_unreachable("invalid fixup kind!"); |
85 | 1 | case FK_PCRel_1: |
86 | 1 | case FK_Data_1: return 0; |
87 | 1 | case FK_PCRel_2: |
88 | 1 | case FK_Data_2: return 1; |
89 | 61.1k | case FK_PCRel_4: |
90 | 61.1k | // FIXME: Remove these!!! |
91 | 61.1k | case X86::reloc_riprel_4byte: |
92 | 61.1k | case X86::reloc_riprel_4byte_relax: |
93 | 61.1k | case X86::reloc_riprel_4byte_relax_rex: |
94 | 61.1k | case X86::reloc_riprel_4byte_movq_load: |
95 | 61.1k | case X86::reloc_signed_4byte: |
96 | 61.1k | case X86::reloc_signed_4byte_relax: |
97 | 61.1k | case FK_Data_4: return 2; |
98 | 35.3k | case FK_Data_8: return 3; |
99 | 0 | } |
100 | 0 | } |
101 | | |
102 | | void X86MachObjectWriter::RecordX86_64Relocation( |
103 | | MachObjectWriter *Writer, MCAssembler &Asm, const MCAsmLayout &Layout, |
104 | | const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, |
105 | 59.4k | uint64_t &FixedValue) { |
106 | 59.4k | unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); |
107 | 59.4k | unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind()); |
108 | 59.4k | unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); |
109 | 59.4k | |
110 | 59.4k | // See <reloc.h>. |
111 | 59.4k | uint32_t FixupOffset = |
112 | 59.4k | Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); |
113 | 59.4k | uint32_t FixupAddress = |
114 | 59.4k | Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); |
115 | 59.4k | int64_t Value = 0; |
116 | 59.4k | unsigned Index = 0; |
117 | 59.4k | unsigned IsExtern = 0; |
118 | 59.4k | unsigned Type = 0; |
119 | 59.4k | const MCSymbol *RelSymbol = nullptr; |
120 | 59.4k | |
121 | 59.4k | Value = Target.getConstant(); |
122 | 59.4k | |
123 | 59.4k | if (IsPCRel59.4k ) { |
124 | 24.0k | // Compensate for the relocation offset, Darwin x86_64 relocations only have |
125 | 24.0k | // the addend and appear to have attempted to define it to be the actual |
126 | 24.0k | // expression addend without the PCrel bias. However, instructions with data |
127 | 24.0k | // following the relocation are not accommodated for (see comment below |
128 | 24.0k | // regarding SIGNED{1,2,4}), so it isn't exactly that either. |
129 | 24.0k | Value += 1LL << Log2Size; |
130 | 24.0k | } |
131 | 59.4k | |
132 | 59.4k | if (Target.isAbsolute()59.4k ) { // constant |
133 | 1 | // SymbolNum of 0 indicates the absolute section. |
134 | 1 | Type = MachO::X86_64_RELOC_UNSIGNED; |
135 | 1 | |
136 | 1 | // FIXME: I believe this is broken, I don't think the linker can understand |
137 | 1 | // it. I think it would require a local relocation, but I'm not sure if that |
138 | 1 | // would work either. The official way to get an absolute PCrel relocation |
139 | 1 | // is to use an absolute symbol (which we don't support yet). |
140 | 1 | if (IsPCRel1 ) { |
141 | 1 | IsExtern = 1; |
142 | 1 | Type = MachO::X86_64_RELOC_BRANCH; |
143 | 1 | } |
144 | 59.4k | } else if (59.4k Target.getSymB()59.4k ) { // A - B + constant |
145 | 26 | const MCSymbol *A = &Target.getSymA()->getSymbol(); |
146 | 26 | if (A->isTemporary()) |
147 | 6 | A = &Writer->findAliasedSymbol(*A); |
148 | 26 | const MCSymbol *A_Base = Asm.getAtom(*A); |
149 | 26 | |
150 | 26 | const MCSymbol *B = &Target.getSymB()->getSymbol(); |
151 | 26 | if (B->isTemporary()) |
152 | 6 | B = &Writer->findAliasedSymbol(*B); |
153 | 26 | const MCSymbol *B_Base = Asm.getAtom(*B); |
154 | 26 | |
155 | 26 | // Neither symbol can be modified. |
156 | 26 | if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None26 ) { |
157 | 0 | Asm.getContext().reportError(Fixup.getLoc(), |
158 | 0 | "unsupported relocation of modified symbol"); |
159 | 0 | return; |
160 | 0 | } |
161 | 26 | |
162 | 26 | // We don't support PCrel relocations of differences. Darwin 'as' doesn't |
163 | 26 | // implement most of these correctly. |
164 | 26 | if (26 IsPCRel26 ) { |
165 | 1 | Asm.getContext().reportError( |
166 | 1 | Fixup.getLoc(), "unsupported pc-relative relocation of difference"); |
167 | 1 | return; |
168 | 1 | } |
169 | 25 | |
170 | 25 | // The support for the situation where one or both of the symbols would |
171 | 25 | // require a local relocation is handled just like if the symbols were |
172 | 25 | // external. This is certainly used in the case of debug sections where the |
173 | 25 | // section has only temporary symbols and thus the symbols don't have base |
174 | 25 | // symbols. This is encoded using the section ordinal and non-extern |
175 | 25 | // relocation entries. |
176 | 25 | |
177 | 25 | // Darwin 'as' doesn't emit correct relocations for this (it ends up with a |
178 | 25 | // single SIGNED relocation); reject it for now. Except the case where both |
179 | 25 | // symbols don't have a base, equal but both NULL. |
180 | 25 | if (25 A_Base == B_Base && 25 A_Base3 ) { |
181 | 1 | Asm.getContext().reportError( |
182 | 1 | Fixup.getLoc(), "unsupported relocation with identical base"); |
183 | 1 | return; |
184 | 1 | } |
185 | 24 | |
186 | 24 | // A subtraction expression where either symbol is undefined is a |
187 | 24 | // non-relocatable expression. |
188 | 24 | if (24 A->isUndefined() || 24 B->isUndefined()21 ) { |
189 | 4 | StringRef Name = A->isUndefined() ? A->getName()3 : B->getName()1 ; |
190 | 4 | Asm.getContext().reportError(Fixup.getLoc(), |
191 | 4 | "unsupported relocation with subtraction expression, symbol '" + |
192 | 4 | Name + "' can not be undefined in a subtraction expression"); |
193 | 4 | return; |
194 | 4 | } |
195 | 20 | |
196 | 20 | Value += Writer->getSymbolAddress(*A, Layout) - |
197 | 20 | (!A_Base ? 03 : Writer->getSymbolAddress(*A_Base, Layout)17 ); |
198 | 20 | Value -= Writer->getSymbolAddress(*B, Layout) - |
199 | 20 | (!B_Base ? 03 : Writer->getSymbolAddress(*B_Base, Layout)17 ); |
200 | 20 | |
201 | 20 | if (!A_Base) |
202 | 3 | Index = A->getFragment()->getParent()->getOrdinal() + 1; |
203 | 20 | Type = MachO::X86_64_RELOC_UNSIGNED; |
204 | 20 | |
205 | 20 | MachO::any_relocation_info MRE; |
206 | 20 | MRE.r_word0 = FixupOffset; |
207 | 20 | MRE.r_word1 = |
208 | 20 | (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); |
209 | 20 | Writer->addRelocation(A_Base, Fragment->getParent(), MRE); |
210 | 20 | |
211 | 20 | if (B_Base) |
212 | 17 | RelSymbol = B_Base; |
213 | 20 | else |
214 | 3 | Index = B->getFragment()->getParent()->getOrdinal() + 1; |
215 | 26 | Type = MachO::X86_64_RELOC_SUBTRACTOR; |
216 | 59.4k | } else { |
217 | 59.3k | const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); |
218 | 59.3k | if (Symbol->isTemporary() && 59.3k Value41.6k ) { |
219 | 34 | const MCSection &Sec = Symbol->getSection(); |
220 | 34 | if (!Asm.getContext().getAsmInfo()->isSectionAtomizableBySymbols(Sec)) |
221 | 11 | Symbol->setUsedInReloc(); |
222 | 34 | } |
223 | 59.3k | RelSymbol = Asm.getAtom(*Symbol); |
224 | 59.3k | |
225 | 59.3k | // Relocations inside debug sections always use local relocations when |
226 | 59.3k | // possible. This seems to be done because the debugger doesn't fully |
227 | 59.3k | // understand x86_64 relocation entries, and expects to find values that |
228 | 59.3k | // have already been fixed up. |
229 | 59.3k | if (Symbol->isInSection()59.3k ) { |
230 | 42.6k | const MCSectionMachO &Section = |
231 | 42.6k | static_cast<const MCSectionMachO &>(*Fragment->getParent()); |
232 | 42.6k | if (Section.hasAttribute(MachO::S_ATTR_DEBUG)) |
233 | 29.3k | RelSymbol = nullptr; |
234 | 42.6k | } |
235 | 59.3k | |
236 | 59.3k | // x86_64 almost always uses external relocations, except when there is no |
237 | 59.3k | // symbol to use as a base address (a local symbol with no preceding |
238 | 59.3k | // non-local symbol). |
239 | 59.3k | if (RelSymbol59.3k ) { |
240 | 17.6k | // Add the local offset, if needed. |
241 | 17.6k | if (RelSymbol != Symbol) |
242 | 30 | Value += Layout.getSymbolOffset(*Symbol) - |
243 | 30 | Layout.getSymbolOffset(*RelSymbol); |
244 | 59.3k | } else if (41.7k Symbol->isInSection() && 41.7k !Symbol->isVariable()37.0k ) { |
245 | 37.0k | // The index is the section ordinal (1-based). |
246 | 37.0k | Index = Symbol->getFragment()->getParent()->getOrdinal() + 1; |
247 | 37.0k | Value += Writer->getSymbolAddress(*Symbol, Layout); |
248 | 37.0k | |
249 | 37.0k | if (IsPCRel) |
250 | 7.46k | Value -= FixupAddress + (1 << Log2Size); |
251 | 41.7k | } else if (4.63k Symbol->isVariable()4.63k ) { |
252 | 4.63k | const MCExpr *Value = Symbol->getVariableValue(); |
253 | 4.63k | int64_t Res; |
254 | 4.63k | bool isAbs = Value->evaluateAsAbsolute(Res, Layout, |
255 | 4.63k | Writer->getSectionAddressMap()); |
256 | 4.63k | if (isAbs4.63k ) { |
257 | 4.63k | FixedValue = Res; |
258 | 4.63k | return; |
259 | 0 | } else { |
260 | 0 | Asm.getContext().reportError(Fixup.getLoc(), |
261 | 0 | "unsupported relocation of variable '" + |
262 | 0 | Symbol->getName() + "'"); |
263 | 0 | return; |
264 | 0 | } |
265 | 0 | } else { |
266 | 0 | Asm.getContext().reportError( |
267 | 0 | Fixup.getLoc(), "unsupported relocation of undefined symbol '" + |
268 | 0 | Symbol->getName() + "'"); |
269 | 0 | return; |
270 | 0 | } |
271 | 54.7k | |
272 | 54.7k | MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind(); |
273 | 54.7k | if (IsPCRel54.7k ) { |
274 | 24.0k | if (IsRIPRel24.0k ) { |
275 | 12.0k | if (Modifier == MCSymbolRefExpr::VK_GOTPCREL12.0k ) { |
276 | 1.07k | // x86_64 distinguishes movq foo@GOTPCREL so that the linker can |
277 | 1.07k | // rewrite the movq to an leaq at link time if the symbol ends up in |
278 | 1.07k | // the same linkage unit. |
279 | 1.07k | if (unsigned(Fixup.getKind()) == X86::reloc_riprel_4byte_movq_load) |
280 | 1.00k | Type = MachO::X86_64_RELOC_GOT_LOAD; |
281 | 1.07k | else |
282 | 67 | Type = MachO::X86_64_RELOC_GOT; |
283 | 12.0k | } else if (11.0k Modifier == MCSymbolRefExpr::VK_TLVP11.0k ) { |
284 | 6 | Type = MachO::X86_64_RELOC_TLV; |
285 | 11.0k | } else if (11.0k Modifier != MCSymbolRefExpr::VK_None11.0k ) { |
286 | 0 | Asm.getContext().reportError( |
287 | 0 | Fixup.getLoc(), "unsupported symbol modifier in relocation"); |
288 | 0 | return; |
289 | 0 | } else { |
290 | 11.0k | Type = MachO::X86_64_RELOC_SIGNED; |
291 | 11.0k | |
292 | 11.0k | // The Darwin x86_64 relocation format has a problem where it cannot |
293 | 11.0k | // encode an address (L<foo> + <constant>) which is outside the atom |
294 | 11.0k | // containing L<foo>. Generally, this shouldn't occur but it does |
295 | 11.0k | // happen when we have a RIPrel instruction with data following the |
296 | 11.0k | // relocation entry (e.g., movb $012, L0(%rip)). Even with the PCrel |
297 | 11.0k | // adjustment Darwin x86_64 uses, the offset is still negative and the |
298 | 11.0k | // linker has no way to recognize this. |
299 | 11.0k | // |
300 | 11.0k | // To work around this, Darwin uses several special relocation types |
301 | 11.0k | // to indicate the offsets. However, the specification or |
302 | 11.0k | // implementation of these seems to also be incomplete; they should |
303 | 11.0k | // adjust the addend as well based on the actual encoded instruction |
304 | 11.0k | // (the additional bias), but instead appear to just look at the final |
305 | 11.0k | // offset. |
306 | 11.0k | switch (-(Target.getConstant() + (1LL << Log2Size))) { |
307 | 308 | case 1: Type = MachO::X86_64_RELOC_SIGNED_1; break; |
308 | 7 | case 2: Type = MachO::X86_64_RELOC_SIGNED_2; break; |
309 | 87 | case 4: Type = MachO::X86_64_RELOC_SIGNED_4; break; |
310 | 24.0k | } |
311 | 24.0k | } |
312 | 0 | } else { |
313 | 11.9k | if (Modifier != MCSymbolRefExpr::VK_None11.9k ) { |
314 | 1 | Asm.getContext().reportError( |
315 | 1 | Fixup.getLoc(), |
316 | 1 | "unsupported symbol modifier in branch relocation"); |
317 | 1 | return; |
318 | 1 | } |
319 | 11.9k | |
320 | 11.9k | Type = MachO::X86_64_RELOC_BRANCH; |
321 | 11.9k | } |
322 | 54.7k | } else { |
323 | 30.7k | if (Modifier == MCSymbolRefExpr::VK_GOT30.7k ) { |
324 | 0 | Type = MachO::X86_64_RELOC_GOT; |
325 | 30.7k | } else if (30.7k Modifier == MCSymbolRefExpr::VK_GOTPCREL30.7k ) { |
326 | 28 | // GOTPCREL is allowed as a modifier on non-PCrel instructions, in which |
327 | 28 | // case all we do is set the PCrel bit in the relocation entry; this is |
328 | 28 | // used with exception handling, for example. The source is required to |
329 | 28 | // include any necessary offset directly. |
330 | 28 | Type = MachO::X86_64_RELOC_GOT; |
331 | 28 | IsPCRel = 1; |
332 | 30.7k | } else if (30.6k Modifier == MCSymbolRefExpr::VK_TLVP30.6k ) { |
333 | 1 | Asm.getContext().reportError( |
334 | 1 | Fixup.getLoc(), "TLVP symbol modifier should have been rip-rel"); |
335 | 1 | return; |
336 | 30.6k | } else if (30.6k Modifier != MCSymbolRefExpr::VK_None30.6k ) { |
337 | 1 | Asm.getContext().reportError( |
338 | 1 | Fixup.getLoc(), "unsupported symbol modifier in relocation"); |
339 | 1 | return; |
340 | 0 | } else { |
341 | 30.6k | Type = MachO::X86_64_RELOC_UNSIGNED; |
342 | 30.6k | unsigned Kind = Fixup.getKind(); |
343 | 30.6k | if (Kind == X86::reloc_signed_4byte30.6k ) { |
344 | 2 | Asm.getContext().reportError( |
345 | 2 | Fixup.getLoc(), |
346 | 2 | "32-bit absolute addressing is not supported in 64-bit mode"); |
347 | 2 | return; |
348 | 2 | } |
349 | 54.7k | } |
350 | 30.7k | } |
351 | 59.4k | } |
352 | 54.7k | |
353 | 54.7k | // x86_64 always writes custom values into the fixups. |
354 | 54.7k | FixedValue = Value; |
355 | 54.7k | |
356 | 54.7k | // struct relocation_info (8 bytes) |
357 | 54.7k | MachO::any_relocation_info MRE; |
358 | 54.7k | MRE.r_word0 = FixupOffset; |
359 | 54.7k | MRE.r_word1 = (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | |
360 | 54.7k | (IsExtern << 27) | (Type << 28); |
361 | 54.7k | Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); |
362 | 54.7k | } |
363 | | |
364 | | bool X86MachObjectWriter::recordScatteredRelocation(MachObjectWriter *Writer, |
365 | | const MCAssembler &Asm, |
366 | | const MCAsmLayout &Layout, |
367 | | const MCFragment *Fragment, |
368 | | const MCFixup &Fixup, |
369 | | MCValue Target, |
370 | | unsigned Log2Size, |
371 | 7.80k | uint64_t &FixedValue) { |
372 | 7.80k | uint64_t OriginalFixedValue = FixedValue; |
373 | 7.80k | uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); |
374 | 7.80k | unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); |
375 | 7.80k | unsigned Type = MachO::GENERIC_RELOC_VANILLA; |
376 | 7.80k | |
377 | 7.80k | // See <reloc.h>. |
378 | 7.80k | const MCSymbol *A = &Target.getSymA()->getSymbol(); |
379 | 7.80k | |
380 | 7.80k | if (!A->getFragment()7.80k ) { |
381 | 1 | Asm.getContext().reportError( |
382 | 1 | Fixup.getLoc(), |
383 | 1 | "symbol '" + A->getName() + |
384 | 1 | "' can not be undefined in a subtraction expression"); |
385 | 1 | return false; |
386 | 1 | } |
387 | 7.80k | |
388 | 7.80k | uint32_t Value = Writer->getSymbolAddress(*A, Layout); |
389 | 7.80k | uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent()); |
390 | 7.80k | FixedValue += SecAddr; |
391 | 7.80k | uint32_t Value2 = 0; |
392 | 7.80k | |
393 | 7.80k | if (const MCSymbolRefExpr *B7.80k = Target.getSymB()) { |
394 | 7.74k | const MCSymbol *SB = &B->getSymbol(); |
395 | 7.74k | |
396 | 7.74k | if (!SB->getFragment()7.74k ) { |
397 | 1 | Asm.getContext().reportError( |
398 | 1 | Fixup.getLoc(), |
399 | 1 | "symbol '" + SB->getName() + |
400 | 1 | "' can not be undefined in a subtraction expression"); |
401 | 1 | return false; |
402 | 1 | } |
403 | 7.74k | |
404 | 7.74k | // Select the appropriate difference relocation type. |
405 | 7.74k | // |
406 | 7.74k | // Note that there is no longer any semantic difference between these two |
407 | 7.74k | // relocation types from the linkers point of view, this is done solely for |
408 | 7.74k | // pedantic compatibility with 'as'. |
409 | 7.74k | Type = A->isExternal() ? 7.74k (unsigned)MachO::GENERIC_RELOC_SECTDIFF686 |
410 | 7.05k | : (unsigned)MachO::GENERIC_RELOC_LOCAL_SECTDIFF; |
411 | 7.74k | Value2 = Writer->getSymbolAddress(*SB, Layout); |
412 | 7.74k | FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent()); |
413 | 7.74k | } |
414 | 7.80k | |
415 | 7.80k | // Relocations are written out in reverse order, so the PAIR comes first. |
416 | 7.80k | if (7.80k Type == MachO::GENERIC_RELOC_SECTDIFF || |
417 | 7.80k | Type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF7.12k ) { |
418 | 7.74k | // If the offset is too large to fit in a scattered relocation, |
419 | 7.74k | // we're hosed. It's an unfortunate limitation of the MachO format. |
420 | 7.74k | if (FixupOffset > 0xffffff7.74k ) { |
421 | 1 | char Buffer[32]; |
422 | 1 | format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer)); |
423 | 1 | Asm.getContext().reportError(Fixup.getLoc(), |
424 | 1 | Twine("Section too large, can't encode " |
425 | 1 | "r_address (") + Buffer + |
426 | 1 | ") into 24 bits of scattered " |
427 | 1 | "relocation entry."); |
428 | 1 | return false; |
429 | 1 | } |
430 | 7.74k | |
431 | 7.74k | MachO::any_relocation_info MRE; |
432 | 7.74k | MRE.r_word0 = ((0 << 0) | // r_address |
433 | 7.74k | (MachO::GENERIC_RELOC_PAIR << 24) | // r_type |
434 | 7.74k | (Log2Size << 28) | |
435 | 7.74k | (IsPCRel << 30) | |
436 | 7.74k | MachO::R_SCATTERED); |
437 | 7.74k | MRE.r_word1 = Value2; |
438 | 7.74k | Writer->addRelocation(nullptr, Fragment->getParent(), MRE); |
439 | 7.80k | } else { |
440 | 62 | // If the offset is more than 24-bits, it won't fit in a scattered |
441 | 62 | // relocation offset field, so we fall back to using a non-scattered |
442 | 62 | // relocation. This is a bit risky, as if the offset reaches out of |
443 | 62 | // the block and the linker is doing scattered loading on this |
444 | 62 | // symbol, things can go badly. |
445 | 62 | // |
446 | 62 | // Required for 'as' compatibility. |
447 | 62 | if (FixupOffset > 0xffffff62 ) { |
448 | 4 | FixedValue = OriginalFixedValue; |
449 | 4 | return false; |
450 | 4 | } |
451 | 7.80k | } |
452 | 7.80k | |
453 | 7.80k | MachO::any_relocation_info MRE; |
454 | 7.80k | MRE.r_word0 = ((FixupOffset << 0) | |
455 | 7.80k | (Type << 24) | |
456 | 7.80k | (Log2Size << 28) | |
457 | 7.80k | (IsPCRel << 30) | |
458 | 7.80k | MachO::R_SCATTERED); |
459 | 7.80k | MRE.r_word1 = Value; |
460 | 7.80k | Writer->addRelocation(nullptr, Fragment->getParent(), MRE); |
461 | 7.80k | return true; |
462 | 7.80k | } |
463 | | |
464 | | void X86MachObjectWriter::recordTLVPRelocation(MachObjectWriter *Writer, |
465 | | const MCAssembler &Asm, |
466 | | const MCAsmLayout &Layout, |
467 | | const MCFragment *Fragment, |
468 | | const MCFixup &Fixup, |
469 | | MCValue Target, |
470 | 0 | uint64_t &FixedValue) { |
471 | 0 | const MCSymbolRefExpr *SymA = Target.getSymA(); |
472 | 0 | assert(SymA->getKind() == MCSymbolRefExpr::VK_TLVP && !is64Bit() && |
473 | 0 | "Should only be called with a 32-bit TLVP relocation!"); |
474 | 0 |
|
475 | 0 | unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); |
476 | 0 | uint32_t Value = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); |
477 | 0 | unsigned IsPCRel = 0; |
478 | 0 |
|
479 | 0 | // We're only going to have a second symbol in pic mode and it'll be a |
480 | 0 | // subtraction from the picbase. For 32-bit pic the addend is the difference |
481 | 0 | // between the picbase and the next address. For 32-bit static the addend is |
482 | 0 | // zero. |
483 | 0 | if (auto *SymB0 = Target.getSymB()) { |
484 | 0 | // If this is a subtraction then we're pcrel. |
485 | 0 | uint32_t FixupAddress = |
486 | 0 | Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); |
487 | 0 | IsPCRel = 1; |
488 | 0 | FixedValue = FixupAddress - |
489 | 0 | Writer->getSymbolAddress(SymB->getSymbol(), Layout) + |
490 | 0 | Target.getConstant(); |
491 | 0 | FixedValue += 1ULL << Log2Size; |
492 | 0 | } else { |
493 | 0 | FixedValue = 0; |
494 | 0 | } |
495 | 0 |
|
496 | 0 | // struct relocation_info (8 bytes) |
497 | 0 | MachO::any_relocation_info MRE; |
498 | 0 | MRE.r_word0 = Value; |
499 | 0 | MRE.r_word1 = |
500 | 0 | (IsPCRel << 24) | (Log2Size << 25) | (MachO::GENERIC_RELOC_TLV << 28); |
501 | 0 | Writer->addRelocation(&SymA->getSymbol(), Fragment->getParent(), MRE); |
502 | 0 | } |
503 | | |
504 | | void X86MachObjectWriter::RecordX86Relocation(MachObjectWriter *Writer, |
505 | | const MCAssembler &Asm, |
506 | | const MCAsmLayout &Layout, |
507 | | const MCFragment *Fragment, |
508 | | const MCFixup &Fixup, |
509 | | MCValue Target, |
510 | 37.0k | uint64_t &FixedValue) { |
511 | 37.0k | unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); |
512 | 37.0k | unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); |
513 | 37.0k | |
514 | 37.0k | // If this is a 32-bit TLVP reloc it's handled a bit differently. |
515 | 37.0k | if (Target.getSymA() && |
516 | 37.0k | Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP37.0k ) { |
517 | 0 | recordTLVPRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, |
518 | 0 | FixedValue); |
519 | 0 | return; |
520 | 0 | } |
521 | 37.0k | |
522 | 37.0k | // If this is a difference or a defined symbol plus an offset, then we need a |
523 | 37.0k | // scattered relocation entry. Differences always require scattered |
524 | 37.0k | // relocations. |
525 | 37.0k | if (37.0k Target.getSymB()37.0k ) { |
526 | 7.74k | recordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, |
527 | 7.74k | Target, Log2Size, FixedValue); |
528 | 7.74k | return; |
529 | 7.74k | } |
530 | 29.3k | |
531 | 29.3k | // Get the symbol data, if any. |
532 | 29.3k | const MCSymbol *A = nullptr; |
533 | 29.3k | if (Target.getSymA()) |
534 | 29.3k | A = &Target.getSymA()->getSymbol(); |
535 | 29.3k | |
536 | 29.3k | // If this is an internal relocation with an offset, it also needs a scattered |
537 | 29.3k | // relocation entry. |
538 | 29.3k | uint32_t Offset = Target.getConstant(); |
539 | 29.3k | if (IsPCRel) |
540 | 7.49k | Offset += 1 << Log2Size; |
541 | 29.3k | // Try to record the scattered relocation if needed. Fall back to non |
542 | 29.3k | // scattered if necessary (see comments in recordScatteredRelocation() |
543 | 29.3k | // for details). |
544 | 29.3k | if (Offset && 29.3k A100 && !Writer->doesSymbolRequireExternRelocation(*A)99 && |
545 | 62 | recordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, |
546 | 62 | Log2Size, FixedValue)) |
547 | 58 | return; |
548 | 29.2k | |
549 | 29.2k | // See <reloc.h>. |
550 | 29.2k | uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); |
551 | 29.2k | unsigned Index = 0; |
552 | 29.2k | unsigned Type = 0; |
553 | 29.2k | const MCSymbol *RelSymbol = nullptr; |
554 | 29.2k | |
555 | 29.2k | if (Target.isAbsolute()29.2k ) { // constant |
556 | 1 | // SymbolNum of 0 indicates the absolute section. |
557 | 1 | // |
558 | 1 | // FIXME: Currently, these are never generated (see code below). I cannot |
559 | 1 | // find a case where they are actually emitted. |
560 | 1 | Type = MachO::GENERIC_RELOC_VANILLA; |
561 | 29.2k | } else { |
562 | 29.2k | // Resolve constant variables. |
563 | 29.2k | if (A->isVariable()29.2k ) { |
564 | 2.48k | int64_t Res; |
565 | 2.48k | if (A->getVariableValue()->evaluateAsAbsolute( |
566 | 2.48k | Res, Layout, Writer->getSectionAddressMap())) { |
567 | 2.47k | FixedValue = Res; |
568 | 2.47k | return; |
569 | 2.47k | } |
570 | 26.7k | } |
571 | 26.7k | |
572 | 26.7k | // Check whether we need an external or internal relocation. |
573 | 26.7k | if (26.7k Writer->doesSymbolRequireExternRelocation(*A)26.7k ) { |
574 | 7.19k | RelSymbol = A; |
575 | 7.19k | // For external relocations, make sure to offset the fixup value to |
576 | 7.19k | // compensate for the addend of the symbol address, if it was |
577 | 7.19k | // undefined. This occurs with weak definitions, for example. |
578 | 7.19k | if (!A->isUndefined()) |
579 | 435 | FixedValue -= Layout.getSymbolOffset(*A); |
580 | 26.7k | } else { |
581 | 19.5k | // The index is the section ordinal (1-based). |
582 | 19.5k | const MCSection &Sec = A->getSection(); |
583 | 19.5k | Index = Sec.getOrdinal() + 1; |
584 | 19.5k | FixedValue += Writer->getSectionAddress(&Sec); |
585 | 19.5k | } |
586 | 26.7k | if (IsPCRel) |
587 | 7.48k | FixedValue -= Writer->getSectionAddress(Fragment->getParent()); |
588 | 29.2k | |
589 | 29.2k | Type = MachO::GENERIC_RELOC_VANILLA; |
590 | 29.2k | } |
591 | 29.2k | |
592 | 29.2k | // struct relocation_info (8 bytes) |
593 | 26.7k | MachO::any_relocation_info MRE; |
594 | 26.7k | MRE.r_word0 = FixupOffset; |
595 | 26.7k | MRE.r_word1 = |
596 | 26.7k | (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); |
597 | 26.7k | Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); |
598 | 26.7k | } |
599 | | |
600 | | MCObjectWriter *llvm::createX86MachObjectWriter(raw_pwrite_stream &OS, |
601 | | bool Is64Bit, uint32_t CPUType, |
602 | 2.83k | uint32_t CPUSubtype) { |
603 | 2.83k | return createMachObjectWriter(new X86MachObjectWriter(Is64Bit, |
604 | 2.83k | CPUType, |
605 | 2.83k | CPUSubtype), |
606 | 2.83k | OS, /*IsLittleEndian=*/true); |
607 | 2.83k | } |