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