1 //===-- ARMMachObjectWriter.cpp - ARM Mach Object Writer ------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "MCTargetDesc/ARMMCTargetDesc.h"
11 #include "MCTargetDesc/ARMBaseInfo.h"
12 #include "MCTargetDesc/ARMFixupKinds.h"
13 #include "llvm/ADT/Twine.h"
14 #include "llvm/MC/MCAsmLayout.h"
15 #include "llvm/MC/MCAssembler.h"
16 #include "llvm/MC/MCContext.h"
17 #include "llvm/MC/MCExpr.h"
18 #include "llvm/MC/MCFixup.h"
19 #include "llvm/MC/MCFixupKindInfo.h"
20 #include "llvm/MC/MCMachOSymbolFlags.h"
21 #include "llvm/MC/MCMachObjectWriter.h"
22 #include "llvm/MC/MCValue.h"
23 #include "llvm/Support/ErrorHandling.h"
24 #include "llvm/Support/MachO.h"
28 class ARMMachObjectWriter : public MCMachObjectTargetWriter {
29 void RecordARMScatteredRelocation(MachObjectWriter *Writer,
30 const MCAssembler &Asm,
31 const MCAsmLayout &Layout,
32 const MCFragment *Fragment,
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);
45 bool requiresExternRelocation(MachObjectWriter *Writer,
46 const MCAssembler &Asm,
47 const MCFragment &Fragment,
48 unsigned RelocType, const MCSymbolData *SD,
52 ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType,
54 : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype,
55 /*UseAggressiveSymbolFolding=*/true) {}
57 void RecordRelocation(MachObjectWriter *Writer,
58 const MCAssembler &Asm, const MCAsmLayout &Layout,
59 const MCFragment *Fragment, const MCFixup &Fixup,
60 MCValue Target, uint64_t &FixedValue) override;
64 static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
66 RelocType = unsigned(MachO::ARM_RELOC_VANILLA);
74 Log2Size = llvm::Log2_32(1);
77 Log2Size = llvm::Log2_32(2);
80 Log2Size = llvm::Log2_32(4);
83 Log2Size = llvm::Log2_32(8);
86 // These fixups are expected to always be resolvable at assembly time and
87 // have no relocations supported.
88 case ARM::fixup_arm_ldst_pcrel_12:
89 case ARM::fixup_arm_pcrel_10:
90 case ARM::fixup_arm_adr_pcrel_12:
93 // Handle 24-bit branch kinds.
94 case ARM::fixup_arm_condbranch:
95 case ARM::fixup_arm_uncondbranch:
96 case ARM::fixup_arm_uncondbl:
97 case ARM::fixup_arm_condbl:
98 case ARM::fixup_arm_blx:
99 RelocType = unsigned(MachO::ARM_RELOC_BR24);
100 // Report as 'long', even though that is not quite accurate.
101 Log2Size = llvm::Log2_32(4);
104 // Handle Thumb branches.
105 case ARM::fixup_arm_thumb_br:
106 RelocType = unsigned(MachO::ARM_THUMB_RELOC_BR22);
107 Log2Size = llvm::Log2_32(2);
110 case ARM::fixup_t2_uncondbranch:
111 case ARM::fixup_arm_thumb_bl:
112 case ARM::fixup_arm_thumb_blx:
113 RelocType = unsigned(MachO::ARM_THUMB_RELOC_BR22);
114 Log2Size = llvm::Log2_32(4);
117 // For movw/movt r_type relocations they always have a pair following them and
118 // the r_length bits are used differently. The encoding of the r_length is as
120 // low bit of r_length:
121 // 0 - :lower16: for movw instructions
122 // 1 - :upper16: for movt instructions
123 // high bit of r_length:
124 // 0 - arm instructions
125 // 1 - thumb instructions
126 case ARM::fixup_arm_movt_hi16:
127 RelocType = unsigned(MachO::ARM_RELOC_HALF);
130 case ARM::fixup_t2_movt_hi16:
131 RelocType = unsigned(MachO::ARM_RELOC_HALF);
135 case ARM::fixup_arm_movw_lo16:
136 RelocType = unsigned(MachO::ARM_RELOC_HALF);
139 case ARM::fixup_t2_movw_lo16:
140 RelocType = unsigned(MachO::ARM_RELOC_HALF);
146 void ARMMachObjectWriter::
147 RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
148 const MCAssembler &Asm,
149 const MCAsmLayout &Layout,
150 const MCFragment *Fragment,
151 const MCFixup &Fixup,
153 uint64_t &FixedValue) {
154 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
155 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
156 unsigned Type = MachO::ARM_RELOC_HALF;
159 const MCSymbol *A = &Target.getSymA()->getSymbol();
160 const MCSymbolData *A_SD = &Asm.getSymbolData(*A);
162 if (!A_SD->getFragment())
163 Asm.getContext().FatalError(Fixup.getLoc(),
164 "symbol '" + A->getName() +
165 "' can not be undefined in a subtraction expression");
167 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
170 Writer->getSectionAddress(A_SD->getFragment()->getParent());
171 FixedValue += SecAddr;
173 if (const MCSymbolRefExpr *B = Target.getSymB()) {
174 const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
176 if (!B_SD->getFragment())
177 Asm.getContext().FatalError(Fixup.getLoc(),
178 "symbol '" + B->getSymbol().getName() +
179 "' can not be undefined in a subtraction expression");
181 // Select the appropriate difference relocation type.
182 Type = MachO::ARM_RELOC_HALF_SECTDIFF;
183 Value2 = Writer->getSymbolAddress(B_SD, Layout);
184 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
187 // Relocations are written out in reverse order, so the PAIR comes first.
188 // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
190 // For these two r_type relocations they always have a pair following them and
191 // the r_length bits are used differently. The encoding of the r_length is as
193 // low bit of r_length:
194 // 0 - :lower16: for movw instructions
195 // 1 - :upper16: for movt instructions
196 // high bit of r_length:
197 // 0 - arm instructions
198 // 1 - thumb instructions
199 // the other half of the relocated expression is in the following pair
200 // relocation entry in the low 16 bits of r_address field.
201 unsigned ThumbBit = 0;
202 unsigned MovtBit = 0;
203 switch ((unsigned)Fixup.getKind()) {
205 case ARM::fixup_arm_movt_hi16:
207 // The thumb bit shouldn't be set in the 'other-half' bit of the
208 // relocation, but it will be set in FixedValue if the base symbol
209 // is a thumb function. Clear it out here.
210 if (Asm.isThumbFunc(A))
211 FixedValue &= 0xfffffffe;
213 case ARM::fixup_t2_movt_hi16:
214 if (Asm.isThumbFunc(A))
215 FixedValue &= 0xfffffffe;
218 case ARM::fixup_t2_movw_lo16:
223 if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
224 uint32_t OtherHalf = MovtBit
225 ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
227 MachO::any_relocation_info MRE;
228 MRE.r_word0 = ((OtherHalf << 0) |
229 (MachO::ARM_RELOC_PAIR << 24) |
234 MRE.r_word1 = Value2;
235 Writer->addRelocation(Fragment->getParent(), MRE);
238 MachO::any_relocation_info MRE;
239 MRE.r_word0 = ((FixupOffset << 0) |
246 Writer->addRelocation(Fragment->getParent(), MRE);
249 void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
250 const MCAssembler &Asm,
251 const MCAsmLayout &Layout,
252 const MCFragment *Fragment,
253 const MCFixup &Fixup,
257 uint64_t &FixedValue) {
258 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
259 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
262 const MCSymbol *A = &Target.getSymA()->getSymbol();
263 const MCSymbolData *A_SD = &Asm.getSymbolData(*A);
265 if (!A_SD->getFragment())
266 Asm.getContext().FatalError(Fixup.getLoc(),
267 "symbol '" + A->getName() +
268 "' can not be undefined in a subtraction expression");
270 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
271 uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent());
272 FixedValue += SecAddr;
275 if (const MCSymbolRefExpr *B = Target.getSymB()) {
276 assert(Type == MachO::ARM_RELOC_VANILLA && "invalid reloc for 2 symbols");
277 const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
279 if (!B_SD->getFragment())
280 Asm.getContext().FatalError(Fixup.getLoc(),
281 "symbol '" + B->getSymbol().getName() +
282 "' can not be undefined in a subtraction expression");
284 // Select the appropriate difference relocation type.
285 Type = MachO::ARM_RELOC_SECTDIFF;
286 Value2 = Writer->getSymbolAddress(B_SD, Layout);
287 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
290 // Relocations are written out in reverse order, so the PAIR comes first.
291 if (Type == MachO::ARM_RELOC_SECTDIFF ||
292 Type == MachO::ARM_RELOC_LOCAL_SECTDIFF) {
293 MachO::any_relocation_info MRE;
294 MRE.r_word0 = ((0 << 0) |
295 (MachO::ARM_RELOC_PAIR << 24) |
299 MRE.r_word1 = Value2;
300 Writer->addRelocation(Fragment->getParent(), MRE);
303 MachO::any_relocation_info MRE;
304 MRE.r_word0 = ((FixupOffset << 0) |
310 Writer->addRelocation(Fragment->getParent(), MRE);
313 bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer,
314 const MCAssembler &Asm,
315 const MCFragment &Fragment,
317 const MCSymbolData *SD,
318 uint64_t FixedValue) {
319 // Most cases can be identified purely from the symbol.
320 if (Writer->doesSymbolRequireExternRelocation(SD))
322 int64_t Value = (int64_t)FixedValue; // The displacement is signed.
327 case MachO::ARM_RELOC_BR24:
328 // PC pre-adjustment of 8 for these instructions.
330 // ARM BL/BLX has a 25-bit offset.
333 case MachO::ARM_THUMB_RELOC_BR22:
334 // PC pre-adjustment of 4 for these instructions.
336 // Thumb BL/BLX has a 24-bit offset.
339 // BL/BLX also use external relocations when an internal relocation
340 // would result in the target being out of range. This gives the linker
341 // enough information to generate a branch island.
342 const MCSectionData &SymSD = Asm.getSectionData(
343 SD->getSymbol().getSection());
344 Value += Writer->getSectionAddress(&SymSD);
345 Value -= Writer->getSectionAddress(Fragment.getParent());
346 // If the resultant value would be out of range for an internal relocation,
347 // use an external instead.
348 if (Value > Range || Value < -(Range + 1))
353 void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer,
354 const MCAssembler &Asm,
355 const MCAsmLayout &Layout,
356 const MCFragment *Fragment,
357 const MCFixup &Fixup,
359 uint64_t &FixedValue) {
360 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
362 unsigned RelocType = MachO::ARM_RELOC_VANILLA;
363 if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size))
364 // If we failed to get fixup kind info, it's because there's no legal
365 // relocation type for the fixup kind. This happens when it's a fixup that's
366 // expected to always be resolvable at assembly time and not have any
367 // relocations needed.
368 Asm.getContext().FatalError(Fixup.getLoc(),
369 "unsupported relocation on symbol");
371 // If this is a difference or a defined symbol plus an offset, then we need a
372 // scattered relocation entry. Differences always require scattered
374 if (Target.getSymB()) {
375 if (RelocType == MachO::ARM_RELOC_HALF)
376 return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment,
377 Fixup, Target, FixedValue);
378 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
379 Target, RelocType, Log2Size,
383 // Get the symbol data, if any.
384 const MCSymbolData *SD = nullptr;
385 if (Target.getSymA())
386 SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
388 // FIXME: For other platforms, we need to use scattered relocations for
389 // internal relocations with offsets. If this is an internal relocation with
390 // an offset, it also needs a scattered relocation entry.
392 // Is this right for ARM?
393 uint32_t Offset = Target.getConstant();
394 if (IsPCRel && RelocType == MachO::ARM_RELOC_VANILLA)
395 Offset += 1 << Log2Size;
396 if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD))
397 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
398 Target, RelocType, Log2Size,
402 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
404 unsigned IsExtern = 0;
407 if (Target.isAbsolute()) { // constant
409 report_fatal_error("FIXME: relocations to absolute targets "
410 "not yet implemented");
412 // Resolve constant variables.
413 if (SD->getSymbol().isVariable()) {
415 if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
416 Res, Layout, Writer->getSectionAddressMap())) {
422 // Check whether we need an external or internal relocation.
423 if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, SD,
426 Index = SD->getIndex();
428 // For external relocations, make sure to offset the fixup value to
429 // compensate for the addend of the symbol address, if it was
430 // undefined. This occurs with weak definitions, for example.
431 if (!SD->Symbol->isUndefined())
432 FixedValue -= Layout.getSymbolOffset(SD);
434 // The index is the section ordinal (1-based).
435 const MCSectionData &SymSD = Asm.getSectionData(
436 SD->getSymbol().getSection());
437 Index = SymSD.getOrdinal() + 1;
438 FixedValue += Writer->getSectionAddress(&SymSD);
441 FixedValue -= Writer->getSectionAddress(Fragment->getParent());
443 // The type is determined by the fixup kind.
447 // struct relocation_info (8 bytes)
448 MachO::any_relocation_info MRE;
449 MRE.r_word0 = FixupOffset;
450 MRE.r_word1 = ((Index << 0) |
456 // Even when it's not a scattered relocation, movw/movt always uses
457 // a PAIR relocation.
458 if (Type == MachO::ARM_RELOC_HALF) {
459 // The other-half value only gets populated for the movt and movw
460 // relocation entries.
462 switch ((unsigned)Fixup.getKind()) {
464 case ARM::fixup_arm_movw_lo16:
465 case ARM::fixup_t2_movw_lo16:
466 Value = (FixedValue >> 16) & 0xffff;
468 case ARM::fixup_arm_movt_hi16:
469 case ARM::fixup_t2_movt_hi16:
470 Value = FixedValue & 0xffff;
473 MachO::any_relocation_info MREPair;
474 MREPair.r_word0 = Value;
475 MREPair.r_word1 = ((0xffffff << 0) |
477 (MachO::ARM_RELOC_PAIR << 28));
479 Writer->addRelocation(Fragment->getParent(), MREPair);
482 Writer->addRelocation(Fragment->getParent(), MRE);
485 MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS,
488 uint32_t CPUSubtype) {
489 return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit,
492 OS, /*IsLittleEndian=*/true);