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/ARMBaseInfo.h"
11 #include "MCTargetDesc/ARMFixupKinds.h"
12 #include "llvm/ADT/Twine.h"
13 #include "llvm/MC/MCAssembler.h"
14 #include "llvm/MC/MCAsmLayout.h"
15 #include "llvm/MC/MCMachObjectWriter.h"
16 #include "llvm/MC/MCExpr.h"
17 #include "llvm/MC/MCFixup.h"
18 #include "llvm/MC/MCFixupKindInfo.h"
19 #include "llvm/MC/MCMachOSymbolFlags.h"
20 #include "llvm/MC/MCValue.h"
21 #include "llvm/Object/MachOFormat.h"
22 #include "llvm/Support/ErrorHandling.h"
24 using namespace llvm::object;
27 class ARMMachObjectWriter : public MCMachObjectTargetWriter {
28 void RecordARMScatteredRelocation(MachObjectWriter *Writer,
29 const MCAssembler &Asm,
30 const MCAsmLayout &Layout,
31 const MCFragment *Fragment,
35 uint64_t &FixedValue);
36 void RecordARMMovwMovtRelocation(MachObjectWriter *Writer,
37 const MCAssembler &Asm,
38 const MCAsmLayout &Layout,
39 const MCFragment *Fragment,
40 const MCFixup &Fixup, MCValue Target,
41 uint64_t &FixedValue);
44 ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType,
46 : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype,
47 /*UseAggressiveSymbolFolding=*/true) {}
49 void RecordRelocation(MachObjectWriter *Writer,
50 const MCAssembler &Asm, const MCAsmLayout &Layout,
51 const MCFragment *Fragment, const MCFixup &Fixup,
52 MCValue Target, uint64_t &FixedValue);
56 static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
58 RelocType = unsigned(macho::RIT_Vanilla);
65 case ARM::fixup_t2_condbranch:
69 Log2Size = llvm::Log2_32(1);
72 Log2Size = llvm::Log2_32(2);
75 Log2Size = llvm::Log2_32(4);
78 Log2Size = llvm::Log2_32(8);
81 // Handle 24-bit branch kinds.
82 case ARM::fixup_arm_ldst_pcrel_12:
83 case ARM::fixup_arm_pcrel_10:
84 case ARM::fixup_arm_adr_pcrel_12:
85 case ARM::fixup_arm_condbranch:
86 case ARM::fixup_arm_uncondbranch:
87 RelocType = unsigned(macho::RIT_ARM_Branch24Bit);
88 // Report as 'long', even though that is not quite accurate.
89 Log2Size = llvm::Log2_32(4);
92 // Handle Thumb branches.
93 case ARM::fixup_arm_thumb_br:
94 RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit);
95 Log2Size = llvm::Log2_32(2);
98 case ARM::fixup_t2_uncondbranch:
99 case ARM::fixup_arm_thumb_bl:
100 case ARM::fixup_arm_thumb_blx:
101 RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit);
102 Log2Size = llvm::Log2_32(4);
105 case ARM::fixup_arm_movt_hi16:
106 case ARM::fixup_arm_movt_hi16_pcrel:
107 case ARM::fixup_t2_movt_hi16:
108 case ARM::fixup_t2_movt_hi16_pcrel:
109 RelocType = unsigned(macho::RIT_ARM_HalfDifference);
110 // Report as 'long', even though that is not quite accurate.
111 Log2Size = llvm::Log2_32(4);
114 case ARM::fixup_arm_movw_lo16:
115 case ARM::fixup_arm_movw_lo16_pcrel:
116 case ARM::fixup_t2_movw_lo16:
117 case ARM::fixup_t2_movw_lo16_pcrel:
118 RelocType = unsigned(macho::RIT_ARM_Half);
119 // Report as 'long', even though that is not quite accurate.
120 Log2Size = llvm::Log2_32(4);
125 void ARMMachObjectWriter::
126 RecordARMMovwMovtRelocation(MachObjectWriter *Writer,
127 const MCAssembler &Asm,
128 const MCAsmLayout &Layout,
129 const MCFragment *Fragment,
130 const MCFixup &Fixup,
132 uint64_t &FixedValue) {
133 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
134 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
135 unsigned Type = macho::RIT_ARM_Half;
138 const MCSymbol *A = &Target.getSymA()->getSymbol();
139 MCSymbolData *A_SD = &Asm.getSymbolData(*A);
141 if (!A_SD->getFragment())
142 report_fatal_error("symbol '" + A->getName() +
143 "' can not be undefined in a subtraction expression");
145 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
148 Writer->getSectionAddress(A_SD->getFragment()->getParent());
149 FixedValue += SecAddr;
151 if (const MCSymbolRefExpr *B = Target.getSymB()) {
152 MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
154 if (!B_SD->getFragment())
155 report_fatal_error("symbol '" + B->getSymbol().getName() +
156 "' can not be undefined in a subtraction expression");
158 // Select the appropriate difference relocation type.
159 Type = macho::RIT_ARM_HalfDifference;
160 Value2 = Writer->getSymbolAddress(B_SD, Layout);
161 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
164 // Relocations are written out in reverse order, so the PAIR comes first.
165 // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
167 // For these two r_type relocations they always have a pair following them and
168 // the r_length bits are used differently. The encoding of the r_length is as
170 // low bit of r_length:
171 // 0 - :lower16: for movw instructions
172 // 1 - :upper16: for movt instructions
173 // high bit of r_length:
174 // 0 - arm instructions
175 // 1 - thumb instructions
176 // the other half of the relocated expression is in the following pair
177 // relocation entry in the the low 16 bits of r_address field.
178 unsigned ThumbBit = 0;
179 unsigned MovtBit = 0;
180 switch ((unsigned)Fixup.getKind()) {
182 case ARM::fixup_arm_movt_hi16:
183 case ARM::fixup_arm_movt_hi16_pcrel:
185 // The thumb bit shouldn't be set in the 'other-half' bit of the
186 // relocation, but it will be set in FixedValue if the base symbol
187 // is a thumb function. Clear it out here.
188 if (A_SD->getFlags() & SF_ThumbFunc)
189 FixedValue &= 0xfffffffe;
191 case ARM::fixup_t2_movt_hi16:
192 case ARM::fixup_t2_movt_hi16_pcrel:
193 if (A_SD->getFlags() & SF_ThumbFunc)
194 FixedValue &= 0xfffffffe;
197 case ARM::fixup_t2_movw_lo16:
198 case ARM::fixup_t2_movw_lo16_pcrel:
203 if (Type == macho::RIT_ARM_HalfDifference) {
204 uint32_t OtherHalf = MovtBit
205 ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
207 macho::RelocationEntry MRE;
208 MRE.Word0 = ((OtherHalf << 0) |
209 (macho::RIT_Pair << 24) |
213 macho::RF_Scattered);
215 Writer->addRelocation(Fragment->getParent(), MRE);
218 macho::RelocationEntry MRE;
219 MRE.Word0 = ((FixupOffset << 0) |
224 macho::RF_Scattered);
226 Writer->addRelocation(Fragment->getParent(), MRE);
229 void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
230 const MCAssembler &Asm,
231 const MCAsmLayout &Layout,
232 const MCFragment *Fragment,
233 const MCFixup &Fixup,
236 uint64_t &FixedValue) {
237 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
238 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
239 unsigned Type = macho::RIT_Vanilla;
242 const MCSymbol *A = &Target.getSymA()->getSymbol();
243 MCSymbolData *A_SD = &Asm.getSymbolData(*A);
245 if (!A_SD->getFragment())
246 report_fatal_error("symbol '" + A->getName() +
247 "' can not be undefined in a subtraction expression");
249 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
250 uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent());
251 FixedValue += SecAddr;
254 if (const MCSymbolRefExpr *B = Target.getSymB()) {
255 MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
257 if (!B_SD->getFragment())
258 report_fatal_error("symbol '" + B->getSymbol().getName() +
259 "' can not be undefined in a subtraction expression");
261 // Select the appropriate difference relocation type.
262 Type = macho::RIT_Difference;
263 Value2 = Writer->getSymbolAddress(B_SD, Layout);
264 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
267 // Relocations are written out in reverse order, so the PAIR comes first.
268 if (Type == macho::RIT_Difference ||
269 Type == macho::RIT_Generic_LocalDifference) {
270 macho::RelocationEntry MRE;
271 MRE.Word0 = ((0 << 0) |
272 (macho::RIT_Pair << 24) |
275 macho::RF_Scattered);
277 Writer->addRelocation(Fragment->getParent(), MRE);
280 macho::RelocationEntry MRE;
281 MRE.Word0 = ((FixupOffset << 0) |
285 macho::RF_Scattered);
287 Writer->addRelocation(Fragment->getParent(), MRE);
290 void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer,
291 const MCAssembler &Asm,
292 const MCAsmLayout &Layout,
293 const MCFragment *Fragment,
294 const MCFixup &Fixup,
296 uint64_t &FixedValue) {
297 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
299 unsigned RelocType = macho::RIT_Vanilla;
300 if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) {
301 report_fatal_error("unknown ARM fixup kind!");
305 // If this is a difference or a defined symbol plus an offset, then we need a
306 // scattered relocation entry. Differences always require scattered
308 if (Target.getSymB()) {
309 if (RelocType == macho::RIT_ARM_Half ||
310 RelocType == macho::RIT_ARM_HalfDifference)
311 return RecordARMMovwMovtRelocation(Writer, Asm, Layout, Fragment, Fixup,
313 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
314 Target, Log2Size, FixedValue);
317 // Get the symbol data, if any.
318 MCSymbolData *SD = 0;
319 if (Target.getSymA())
320 SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
322 // FIXME: For other platforms, we need to use scattered relocations for
323 // internal relocations with offsets. If this is an internal relocation with
324 // an offset, it also needs a scattered relocation entry.
326 // Is this right for ARM?
327 uint32_t Offset = Target.getConstant();
328 if (IsPCRel && RelocType == macho::RIT_Vanilla)
329 Offset += 1 << Log2Size;
330 if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD))
331 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
332 Target, Log2Size, FixedValue);
335 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
337 unsigned IsExtern = 0;
340 if (Target.isAbsolute()) { // constant
342 report_fatal_error("FIXME: relocations to absolute targets "
343 "not yet implemented");
345 // Resolve constant variables.
346 if (SD->getSymbol().isVariable()) {
348 if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
349 Res, Layout, Writer->getSectionAddressMap())) {
355 // Check whether we need an external or internal relocation.
356 if (Writer->doesSymbolRequireExternRelocation(SD)) {
358 Index = SD->getIndex();
360 // For external relocations, make sure to offset the fixup value to
361 // compensate for the addend of the symbol address, if it was
362 // undefined. This occurs with weak definitions, for example.
363 if (!SD->Symbol->isUndefined())
364 FixedValue -= Layout.getSymbolOffset(SD);
366 // The index is the section ordinal (1-based).
367 const MCSectionData &SymSD = Asm.getSectionData(
368 SD->getSymbol().getSection());
369 Index = SymSD.getOrdinal() + 1;
370 FixedValue += Writer->getSectionAddress(&SymSD);
373 FixedValue -= Writer->getSectionAddress(Fragment->getParent());
375 // The type is determined by the fixup kind.
379 // struct relocation_info (8 bytes)
380 macho::RelocationEntry MRE;
381 MRE.Word0 = FixupOffset;
382 MRE.Word1 = ((Index << 0) |
387 Writer->addRelocation(Fragment->getParent(), MRE);
390 MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS,
393 uint32_t CPUSubtype) {
394 return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit,
397 OS, /*IsLittleEndian=*/true);