Line data Source code
1 : //===-- ARMMachObjectWriter.cpp - ARM Mach Object 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/ARMBaseInfo.h"
11 : #include "MCTargetDesc/ARMFixupKinds.h"
12 : #include "MCTargetDesc/ARMMCTargetDesc.h"
13 : #include "llvm/ADT/Twine.h"
14 : #include "llvm/BinaryFormat/MachO.h"
15 : #include "llvm/MC/MCAsmLayout.h"
16 : #include "llvm/MC/MCAssembler.h"
17 : #include "llvm/MC/MCContext.h"
18 : #include "llvm/MC/MCExpr.h"
19 : #include "llvm/MC/MCFixup.h"
20 : #include "llvm/MC/MCFixupKindInfo.h"
21 : #include "llvm/MC/MCMachObjectWriter.h"
22 : #include "llvm/MC/MCSection.h"
23 : #include "llvm/MC/MCValue.h"
24 : #include "llvm/Support/ErrorHandling.h"
25 : using namespace llvm;
26 :
27 : namespace {
28 0 : class ARMMachObjectWriter : public MCMachObjectTargetWriter {
29 : void RecordARMScatteredRelocation(MachObjectWriter *Writer,
30 : const MCAssembler &Asm,
31 : const MCAsmLayout &Layout,
32 : const MCFragment *Fragment,
33 : const MCFixup &Fixup,
34 : MCValue Target,
35 : unsigned Type,
36 : unsigned Log2Size,
37 : uint64_t &FixedValue);
38 : void RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
39 : const MCAssembler &Asm,
40 : const MCAsmLayout &Layout,
41 : const MCFragment *Fragment,
42 : const MCFixup &Fixup, MCValue Target,
43 : uint64_t &FixedValue);
44 :
45 : bool requiresExternRelocation(MachObjectWriter *Writer,
46 : const MCAssembler &Asm,
47 : const MCFragment &Fragment, unsigned RelocType,
48 : const MCSymbol &S, uint64_t FixedValue);
49 :
50 : public:
51 : ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
52 0 : : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {}
53 :
54 : void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
55 : const MCAsmLayout &Layout, const MCFragment *Fragment,
56 : const MCFixup &Fixup, MCValue Target,
57 : uint64_t &FixedValue) override;
58 : };
59 : }
60 :
61 1370 : static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
62 : unsigned &Log2Size) {
63 1370 : RelocType = unsigned(MachO::ARM_RELOC_VANILLA);
64 1370 : Log2Size = ~0U;
65 :
66 1370 : switch (Kind) {
67 : default:
68 : return false;
69 :
70 : case FK_Data_1:
71 0 : Log2Size = llvm::Log2_32(1);
72 0 : return true;
73 : case FK_Data_2:
74 0 : Log2Size = llvm::Log2_32(2);
75 0 : return true;
76 : case FK_Data_4:
77 119 : Log2Size = llvm::Log2_32(4);
78 119 : return true;
79 : case FK_Data_8:
80 0 : Log2Size = llvm::Log2_32(8);
81 0 : return true;
82 :
83 : // These fixups are expected to always be resolvable at assembly time and
84 : // have no relocations supported.
85 : case ARM::fixup_arm_ldst_pcrel_12:
86 : case ARM::fixup_arm_pcrel_10:
87 : case ARM::fixup_arm_adr_pcrel_12:
88 : case ARM::fixup_arm_thumb_br:
89 : return false;
90 :
91 : // Handle 24-bit branch kinds.
92 567 : case ARM::fixup_arm_condbranch:
93 : case ARM::fixup_arm_uncondbranch:
94 : case ARM::fixup_arm_uncondbl:
95 : case ARM::fixup_arm_condbl:
96 : case ARM::fixup_arm_blx:
97 567 : RelocType = unsigned(MachO::ARM_RELOC_BR24);
98 : // Report as 'long', even though that is not quite accurate.
99 567 : Log2Size = llvm::Log2_32(4);
100 567 : return true;
101 :
102 599 : case ARM::fixup_t2_uncondbranch:
103 : case ARM::fixup_arm_thumb_bl:
104 : case ARM::fixup_arm_thumb_blx:
105 599 : RelocType = unsigned(MachO::ARM_THUMB_RELOC_BR22);
106 599 : Log2Size = llvm::Log2_32(4);
107 599 : return true;
108 :
109 : // For movw/movt r_type relocations they always have a pair following them and
110 : // the r_length bits are used differently. The encoding of the r_length is as
111 : // follows:
112 : // low bit of r_length:
113 : // 0 - :lower16: for movw instructions
114 : // 1 - :upper16: for movt instructions
115 : // high bit of r_length:
116 : // 0 - arm instructions
117 : // 1 - thumb instructions
118 8 : case ARM::fixup_arm_movt_hi16:
119 8 : RelocType = unsigned(MachO::ARM_RELOC_HALF);
120 8 : Log2Size = 1;
121 8 : return true;
122 31 : case ARM::fixup_t2_movt_hi16:
123 31 : RelocType = unsigned(MachO::ARM_RELOC_HALF);
124 31 : Log2Size = 3;
125 31 : return true;
126 :
127 8 : case ARM::fixup_arm_movw_lo16:
128 8 : RelocType = unsigned(MachO::ARM_RELOC_HALF);
129 8 : Log2Size = 0;
130 8 : return true;
131 30 : case ARM::fixup_t2_movw_lo16:
132 30 : RelocType = unsigned(MachO::ARM_RELOC_HALF);
133 30 : Log2Size = 2;
134 30 : return true;
135 : }
136 : }
137 :
138 0 : void ARMMachObjectWriter::
139 : RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
140 : const MCAssembler &Asm,
141 : const MCAsmLayout &Layout,
142 : const MCFragment *Fragment,
143 : const MCFixup &Fixup,
144 : MCValue Target,
145 : uint64_t &FixedValue) {
146 0 : uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
147 0 : unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
148 : unsigned Type = MachO::ARM_RELOC_HALF;
149 :
150 : // See <reloc.h>.
151 0 : const MCSymbol *A = &Target.getSymA()->getSymbol();
152 :
153 0 : if (!A->getFragment()) {
154 0 : Asm.getContext().reportError(Fixup.getLoc(),
155 0 : "symbol '" + A->getName() +
156 0 : "' can not be undefined in a subtraction expression");
157 0 : return;
158 : }
159 :
160 0 : uint32_t Value = Writer->getSymbolAddress(*A, Layout);
161 : uint32_t Value2 = 0;
162 0 : uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent());
163 0 : FixedValue += SecAddr;
164 :
165 0 : if (const MCSymbolRefExpr *B = Target.getSymB()) {
166 0 : const MCSymbol *SB = &B->getSymbol();
167 :
168 0 : if (!SB->getFragment()) {
169 0 : Asm.getContext().reportError(Fixup.getLoc(),
170 0 : "symbol '" + B->getSymbol().getName() +
171 0 : "' can not be undefined in a subtraction expression");
172 0 : return;
173 : }
174 :
175 : // Select the appropriate difference relocation type.
176 : Type = MachO::ARM_RELOC_HALF_SECTDIFF;
177 0 : Value2 = Writer->getSymbolAddress(B->getSymbol(), Layout);
178 0 : FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent());
179 : }
180 :
181 : // Relocations are written out in reverse order, so the PAIR comes first.
182 : // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
183 : //
184 : // For these two r_type relocations they always have a pair following them and
185 : // the r_length bits are used differently. The encoding of the r_length is as
186 : // follows:
187 : // low bit of r_length:
188 : // 0 - :lower16: for movw instructions
189 : // 1 - :upper16: for movt instructions
190 : // high bit of r_length:
191 : // 0 - arm instructions
192 : // 1 - thumb instructions
193 : // the other half of the relocated expression is in the following pair
194 : // relocation entry in the low 16 bits of r_address field.
195 : unsigned ThumbBit = 0;
196 : unsigned MovtBit = 0;
197 0 : switch ((unsigned)Fixup.getKind()) {
198 : default: break;
199 0 : case ARM::fixup_arm_movt_hi16:
200 : MovtBit = 1;
201 : // The thumb bit shouldn't be set in the 'other-half' bit of the
202 : // relocation, but it will be set in FixedValue if the base symbol
203 : // is a thumb function. Clear it out here.
204 0 : if (Asm.isThumbFunc(A))
205 0 : FixedValue &= 0xfffffffe;
206 : break;
207 0 : case ARM::fixup_t2_movt_hi16:
208 0 : if (Asm.isThumbFunc(A))
209 0 : FixedValue &= 0xfffffffe;
210 : MovtBit = 1;
211 : LLVM_FALLTHROUGH;
212 : case ARM::fixup_t2_movw_lo16:
213 : ThumbBit = 1;
214 : break;
215 : }
216 :
217 0 : if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
218 0 : uint32_t OtherHalf = MovtBit
219 0 : ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
220 :
221 : MachO::any_relocation_info MRE;
222 0 : MRE.r_word0 = ((OtherHalf << 0) |
223 0 : (MachO::ARM_RELOC_PAIR << 24) |
224 0 : (MovtBit << 28) |
225 0 : (ThumbBit << 29) |
226 0 : (IsPCRel << 30) |
227 : MachO::R_SCATTERED);
228 0 : MRE.r_word1 = Value2;
229 0 : Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
230 : }
231 :
232 : MachO::any_relocation_info MRE;
233 0 : MRE.r_word0 = ((FixupOffset << 0) |
234 0 : (Type << 24) |
235 0 : (MovtBit << 28) |
236 0 : (ThumbBit << 29) |
237 0 : (IsPCRel << 30) |
238 : MachO::R_SCATTERED);
239 0 : MRE.r_word1 = Value;
240 0 : Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
241 : }
242 :
243 0 : void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
244 : const MCAssembler &Asm,
245 : const MCAsmLayout &Layout,
246 : const MCFragment *Fragment,
247 : const MCFixup &Fixup,
248 : MCValue Target,
249 : unsigned Type,
250 : unsigned Log2Size,
251 : uint64_t &FixedValue) {
252 0 : uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
253 0 : unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
254 :
255 : // See <reloc.h>.
256 0 : const MCSymbol *A = &Target.getSymA()->getSymbol();
257 :
258 0 : if (!A->getFragment()) {
259 0 : Asm.getContext().reportError(Fixup.getLoc(),
260 0 : "symbol '" + A->getName() +
261 0 : "' can not be undefined in a subtraction expression");
262 0 : return;
263 : }
264 :
265 0 : uint32_t Value = Writer->getSymbolAddress(*A, Layout);
266 0 : uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent());
267 0 : FixedValue += SecAddr;
268 : uint32_t Value2 = 0;
269 :
270 0 : if (const MCSymbolRefExpr *B = Target.getSymB()) {
271 : assert(Type == MachO::ARM_RELOC_VANILLA && "invalid reloc for 2 symbols");
272 0 : const MCSymbol *SB = &B->getSymbol();
273 :
274 0 : if (!SB->getFragment()) {
275 0 : Asm.getContext().reportError(Fixup.getLoc(),
276 0 : "symbol '" + B->getSymbol().getName() +
277 0 : "' can not be undefined in a subtraction expression");
278 0 : return;
279 : }
280 :
281 : // Select the appropriate difference relocation type.
282 : Type = MachO::ARM_RELOC_SECTDIFF;
283 0 : Value2 = Writer->getSymbolAddress(B->getSymbol(), Layout);
284 0 : FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent());
285 : }
286 :
287 : // Relocations are written out in reverse order, so the PAIR comes first.
288 0 : if (Type == MachO::ARM_RELOC_SECTDIFF ||
289 : Type == MachO::ARM_RELOC_LOCAL_SECTDIFF) {
290 : MachO::any_relocation_info MRE;
291 0 : MRE.r_word0 = ((0 << 0) |
292 : (MachO::ARM_RELOC_PAIR << 24) |
293 0 : (Log2Size << 28) |
294 0 : (IsPCRel << 30) |
295 : MachO::R_SCATTERED);
296 0 : MRE.r_word1 = Value2;
297 0 : Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
298 : }
299 :
300 : MachO::any_relocation_info MRE;
301 0 : MRE.r_word0 = ((FixupOffset << 0) |
302 0 : (Type << 24) |
303 0 : (Log2Size << 28) |
304 0 : (IsPCRel << 30) |
305 : MachO::R_SCATTERED);
306 0 : MRE.r_word1 = Value;
307 0 : Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
308 : }
309 :
310 0 : bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer,
311 : const MCAssembler &Asm,
312 : const MCFragment &Fragment,
313 : unsigned RelocType,
314 : const MCSymbol &S,
315 : uint64_t FixedValue) {
316 : // Most cases can be identified purely from the symbol.
317 0 : if (Writer->doesSymbolRequireExternRelocation(S))
318 0 : return true;
319 0 : int64_t Value = (int64_t)FixedValue; // The displacement is signed.
320 : int64_t Range;
321 0 : switch (RelocType) {
322 : default:
323 : return false;
324 : case MachO::ARM_RELOC_BR24:
325 : // An ARM call might be to a Thumb function, in which case the offset may
326 : // not be encodable in the instruction and we must use an external
327 : // relocation that explicitly mentions the function. Not a problem if it's
328 : // to a temporary "Lwhatever" symbol though, and in fact trying to use an
329 : // external relocation there causes more issues.
330 0 : if (!S.isTemporary())
331 0 : return true;
332 :
333 : // PC pre-adjustment of 8 for these instructions.
334 0 : Value -= 8;
335 : // ARM BL/BLX has a 25-bit offset.
336 : Range = 0x1ffffff;
337 0 : break;
338 0 : case MachO::ARM_THUMB_RELOC_BR22:
339 : // PC pre-adjustment of 4 for these instructions.
340 0 : Value -= 4;
341 : // Thumb BL/BLX has a 24-bit offset.
342 : Range = 0xffffff;
343 : }
344 : // BL/BLX also use external relocations when an internal relocation
345 : // would result in the target being out of range. This gives the linker
346 : // enough information to generate a branch island.
347 0 : Value += Writer->getSectionAddress(&S.getSection());
348 0 : Value -= Writer->getSectionAddress(Fragment.getParent());
349 : // If the resultant value would be out of range for an internal relocation,
350 : // use an external instead.
351 0 : if (Value > Range || Value < -(Range + 1))
352 0 : return true;
353 : return false;
354 : }
355 :
356 1370 : void ARMMachObjectWriter::recordRelocation(MachObjectWriter *Writer,
357 : MCAssembler &Asm,
358 : const MCAsmLayout &Layout,
359 : const MCFragment *Fragment,
360 : const MCFixup &Fixup, MCValue Target,
361 : uint64_t &FixedValue) {
362 1370 : unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
363 : unsigned Log2Size;
364 1370 : unsigned RelocType = MachO::ARM_RELOC_VANILLA;
365 1370 : if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) {
366 : // If we failed to get fixup kind info, it's because there's no legal
367 : // relocation type for the fixup kind. This happens when it's a fixup that's
368 : // expected to always be resolvable at assembly time and not have any
369 : // relocations needed.
370 16 : Asm.getContext().reportError(Fixup.getLoc(),
371 : "unsupported relocation on symbol");
372 96 : return;
373 : }
374 :
375 : // If this is a difference or a defined symbol plus an offset, then we need a
376 : // scattered relocation entry. Differences always require scattered
377 : // relocations.
378 1362 : if (Target.getSymB()) {
379 81 : if (RelocType == MachO::ARM_RELOC_HALF)
380 59 : return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment,
381 59 : Fixup, Target, FixedValue);
382 22 : return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
383 : Target, RelocType, Log2Size,
384 22 : FixedValue);
385 : }
386 :
387 : // Get the symbol data, if any.
388 : const MCSymbol *A = nullptr;
389 1281 : if (Target.getSymA())
390 1281 : A = &Target.getSymA()->getSymbol();
391 :
392 : // FIXME: For other platforms, we need to use scattered relocations for
393 : // internal relocations with offsets. If this is an internal relocation with
394 : // an offset, it also needs a scattered relocation entry.
395 : //
396 : // Is this right for ARM?
397 1281 : uint32_t Offset = Target.getConstant();
398 1281 : if (IsPCRel && RelocType == MachO::ARM_RELOC_VANILLA)
399 0 : Offset += 1 << Log2Size;
400 1281 : if (Offset && A && !Writer->doesSymbolRequireExternRelocation(*A) &&
401 7 : RelocType != MachO::ARM_RELOC_HALF)
402 7 : return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
403 : Target, RelocType, Log2Size,
404 7 : FixedValue);
405 :
406 : // See <reloc.h>.
407 1274 : uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
408 : unsigned Index = 0;
409 : unsigned Type = 0;
410 : const MCSymbol *RelSymbol = nullptr;
411 :
412 : if (Target.isAbsolute()) { // constant
413 : // FIXME!
414 0 : report_fatal_error("FIXME: relocations to absolute targets "
415 : "not yet implemented");
416 : } else {
417 : // Resolve constant variables.
418 1274 : if (A->isVariable()) {
419 : int64_t Res;
420 0 : if (A->getVariableValue()->evaluateAsAbsolute(
421 : Res, Layout, Writer->getSectionAddressMap())) {
422 0 : FixedValue = Res;
423 0 : return;
424 : }
425 : }
426 :
427 : // Check whether we need an external or internal relocation.
428 1274 : if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, *A,
429 : FixedValue)) {
430 : RelSymbol = A;
431 :
432 : // For external relocations, make sure to offset the fixup value to
433 : // compensate for the addend of the symbol address, if it was
434 : // undefined. This occurs with weak definitions, for example.
435 1161 : if (!A->isUndefined())
436 11 : FixedValue -= Layout.getSymbolOffset(*A);
437 : } else {
438 : // The index is the section ordinal (1-based).
439 : const MCSection &Sec = A->getSection();
440 113 : Index = Sec.getOrdinal() + 1;
441 113 : FixedValue += Writer->getSectionAddress(&Sec);
442 : }
443 1274 : if (IsPCRel)
444 2320 : FixedValue -= Writer->getSectionAddress(Fragment->getParent());
445 :
446 : // The type is determined by the fixup kind.
447 1274 : Type = RelocType;
448 : }
449 :
450 : // struct relocation_info (8 bytes)
451 : MachO::any_relocation_info MRE;
452 1274 : MRE.r_word0 = FixupOffset;
453 1274 : MRE.r_word1 =
454 1274 : (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
455 :
456 : // Even when it's not a scattered relocation, movw/movt always uses
457 : // a PAIR relocation.
458 1274 : if (Type == MachO::ARM_RELOC_HALF) {
459 : // The entire addend is needed to correctly apply a relocation. One half is
460 : // extracted from the instruction itself, the other comes from this
461 : // PAIR. I.e. it's correct that we insert the high bits of the addend in the
462 : // MOVW case here. relocation entries.
463 : uint32_t Value = 0;
464 18 : switch ((unsigned)Fixup.getKind()) {
465 : default: break;
466 9 : case ARM::fixup_arm_movw_lo16:
467 : case ARM::fixup_t2_movw_lo16:
468 9 : Value = (FixedValue >> 16) & 0xffff;
469 9 : break;
470 9 : case ARM::fixup_arm_movt_hi16:
471 : case ARM::fixup_t2_movt_hi16:
472 9 : Value = FixedValue & 0xffff;
473 9 : break;
474 : }
475 : MachO::any_relocation_info MREPair;
476 18 : MREPair.r_word0 = Value;
477 18 : MREPair.r_word1 = ((0xffffff << 0) |
478 18 : (Log2Size << 25) |
479 : (MachO::ARM_RELOC_PAIR << 28));
480 :
481 18 : Writer->addRelocation(nullptr, Fragment->getParent(), MREPair);
482 : }
483 :
484 1274 : Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
485 : }
486 :
487 : std::unique_ptr<MCObjectTargetWriter>
488 927 : llvm::createARMMachObjectWriter(bool Is64Bit, uint32_t CPUType,
489 : uint32_t CPUSubtype) {
490 927 : return llvm::make_unique<ARMMachObjectWriter>(Is64Bit, CPUType, CPUSubtype);
491 : }
|