blob: 086ecc43b6b226ba4e36f63f42b71993071bef83 [file] [log] [blame]
Jim Grosbach2fc68982011-06-22 20:14:52 +00001//===-- 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
Evan Chengbe740292011-07-23 00:00:19 +000010#include "MCTargetDesc/ARMBaseInfo.h"
11#include "MCTargetDesc/ARMFixupKinds.h"
Jim Grosbachba8297e2011-06-24 23:44:37 +000012#include "llvm/ADT/Twine.h"
13#include "llvm/MC/MCAssembler.h"
14#include "llvm/MC/MCAsmLayout.h"
Jim Grosbach2fc68982011-06-22 20:14:52 +000015#include "llvm/MC/MCMachObjectWriter.h"
Jim Grosbach42e6bd32012-01-26 23:20:15 +000016#include "llvm/MC/MCContext.h"
Jim Grosbachba8297e2011-06-24 23:44:37 +000017#include "llvm/MC/MCExpr.h"
18#include "llvm/MC/MCFixup.h"
19#include "llvm/MC/MCFixupKindInfo.h"
Jim Grosbach62006112011-11-29 01:15:25 +000020#include "llvm/MC/MCMachOSymbolFlags.h"
Jim Grosbachba8297e2011-06-24 23:44:37 +000021#include "llvm/MC/MCValue.h"
22#include "llvm/Object/MachOFormat.h"
23#include "llvm/Support/ErrorHandling.h"
Jim Grosbach2fc68982011-06-22 20:14:52 +000024using namespace llvm;
Jim Grosbachba8297e2011-06-24 23:44:37 +000025using namespace llvm::object;
Jim Grosbach2fc68982011-06-22 20:14:52 +000026
27namespace {
28class ARMMachObjectWriter : public MCMachObjectTargetWriter {
Jim Grosbachba8297e2011-06-24 23:44:37 +000029 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 Log2Size,
36 uint64_t &FixedValue);
37 void RecordARMMovwMovtRelocation(MachObjectWriter *Writer,
38 const MCAssembler &Asm,
39 const MCAsmLayout &Layout,
40 const MCFragment *Fragment,
41 const MCFixup &Fixup, MCValue Target,
42 uint64_t &FixedValue);
43
Jim Grosbach2fc68982011-06-22 20:14:52 +000044public:
45 ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType,
46 uint32_t CPUSubtype)
47 : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype,
48 /*UseAggressiveSymbolFolding=*/true) {}
Jim Grosbachba8297e2011-06-24 23:44:37 +000049
50 void RecordRelocation(MachObjectWriter *Writer,
51 const MCAssembler &Asm, const MCAsmLayout &Layout,
52 const MCFragment *Fragment, const MCFixup &Fixup,
53 MCValue Target, uint64_t &FixedValue);
Jim Grosbach2fc68982011-06-22 20:14:52 +000054};
55}
56
Jim Grosbachba8297e2011-06-24 23:44:37 +000057static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
58 unsigned &Log2Size) {
59 RelocType = unsigned(macho::RIT_Vanilla);
60 Log2Size = ~0U;
61
62 switch (Kind) {
63 default:
64 return false;
65
66 case FK_Data_1:
67 Log2Size = llvm::Log2_32(1);
68 return true;
69 case FK_Data_2:
70 Log2Size = llvm::Log2_32(2);
71 return true;
72 case FK_Data_4:
73 Log2Size = llvm::Log2_32(4);
74 return true;
75 case FK_Data_8:
76 Log2Size = llvm::Log2_32(8);
77 return true;
78
79 // Handle 24-bit branch kinds.
80 case ARM::fixup_arm_ldst_pcrel_12:
81 case ARM::fixup_arm_pcrel_10:
82 case ARM::fixup_arm_adr_pcrel_12:
83 case ARM::fixup_arm_condbranch:
84 case ARM::fixup_arm_uncondbranch:
85 RelocType = unsigned(macho::RIT_ARM_Branch24Bit);
86 // Report as 'long', even though that is not quite accurate.
87 Log2Size = llvm::Log2_32(4);
88 return true;
89
90 // Handle Thumb branches.
91 case ARM::fixup_arm_thumb_br:
92 RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit);
93 Log2Size = llvm::Log2_32(2);
94 return true;
95
96 case ARM::fixup_t2_uncondbranch:
97 case ARM::fixup_arm_thumb_bl:
98 case ARM::fixup_arm_thumb_blx:
99 RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit);
100 Log2Size = llvm::Log2_32(4);
101 return true;
102
103 case ARM::fixup_arm_movt_hi16:
104 case ARM::fixup_arm_movt_hi16_pcrel:
105 case ARM::fixup_t2_movt_hi16:
106 case ARM::fixup_t2_movt_hi16_pcrel:
107 RelocType = unsigned(macho::RIT_ARM_HalfDifference);
108 // Report as 'long', even though that is not quite accurate.
109 Log2Size = llvm::Log2_32(4);
110 return true;
111
112 case ARM::fixup_arm_movw_lo16:
113 case ARM::fixup_arm_movw_lo16_pcrel:
114 case ARM::fixup_t2_movw_lo16:
115 case ARM::fixup_t2_movw_lo16_pcrel:
116 RelocType = unsigned(macho::RIT_ARM_Half);
117 // Report as 'long', even though that is not quite accurate.
118 Log2Size = llvm::Log2_32(4);
119 return true;
120 }
121}
122
123void ARMMachObjectWriter::
124RecordARMMovwMovtRelocation(MachObjectWriter *Writer,
125 const MCAssembler &Asm,
126 const MCAsmLayout &Layout,
127 const MCFragment *Fragment,
128 const MCFixup &Fixup,
129 MCValue Target,
130 uint64_t &FixedValue) {
131 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
132 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
133 unsigned Type = macho::RIT_ARM_Half;
134
135 // See <reloc.h>.
136 const MCSymbol *A = &Target.getSymA()->getSymbol();
137 MCSymbolData *A_SD = &Asm.getSymbolData(*A);
138
139 if (!A_SD->getFragment())
140 report_fatal_error("symbol '" + A->getName() +
141 "' can not be undefined in a subtraction expression");
142
143 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
144 uint32_t Value2 = 0;
145 uint64_t SecAddr =
146 Writer->getSectionAddress(A_SD->getFragment()->getParent());
147 FixedValue += SecAddr;
148
149 if (const MCSymbolRefExpr *B = Target.getSymB()) {
150 MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
151
152 if (!B_SD->getFragment())
153 report_fatal_error("symbol '" + B->getSymbol().getName() +
154 "' can not be undefined in a subtraction expression");
155
156 // Select the appropriate difference relocation type.
157 Type = macho::RIT_ARM_HalfDifference;
158 Value2 = Writer->getSymbolAddress(B_SD, Layout);
159 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
160 }
161
162 // Relocations are written out in reverse order, so the PAIR comes first.
163 // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
164 //
165 // For these two r_type relocations they always have a pair following them and
166 // the r_length bits are used differently. The encoding of the r_length is as
167 // follows:
168 // low bit of r_length:
169 // 0 - :lower16: for movw instructions
170 // 1 - :upper16: for movt instructions
171 // high bit of r_length:
172 // 0 - arm instructions
173 // 1 - thumb instructions
174 // the other half of the relocated expression is in the following pair
175 // relocation entry in the the low 16 bits of r_address field.
176 unsigned ThumbBit = 0;
177 unsigned MovtBit = 0;
178 switch ((unsigned)Fixup.getKind()) {
179 default: break;
180 case ARM::fixup_arm_movt_hi16:
181 case ARM::fixup_arm_movt_hi16_pcrel:
182 MovtBit = 1;
Jim Grosbach62006112011-11-29 01:15:25 +0000183 // The thumb bit shouldn't be set in the 'other-half' bit of the
184 // relocation, but it will be set in FixedValue if the base symbol
185 // is a thumb function. Clear it out here.
186 if (A_SD->getFlags() & SF_ThumbFunc)
187 FixedValue &= 0xfffffffe;
Jim Grosbachba8297e2011-06-24 23:44:37 +0000188 break;
189 case ARM::fixup_t2_movt_hi16:
190 case ARM::fixup_t2_movt_hi16_pcrel:
Jim Grosbach62006112011-11-29 01:15:25 +0000191 if (A_SD->getFlags() & SF_ThumbFunc)
192 FixedValue &= 0xfffffffe;
Jim Grosbachba8297e2011-06-24 23:44:37 +0000193 MovtBit = 1;
194 // Fallthrough
195 case ARM::fixup_t2_movw_lo16:
196 case ARM::fixup_t2_movw_lo16_pcrel:
197 ThumbBit = 1;
198 break;
199 }
200
Jim Grosbachba8297e2011-06-24 23:44:37 +0000201 if (Type == macho::RIT_ARM_HalfDifference) {
202 uint32_t OtherHalf = MovtBit
203 ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
204
205 macho::RelocationEntry MRE;
206 MRE.Word0 = ((OtherHalf << 0) |
207 (macho::RIT_Pair << 24) |
208 (MovtBit << 28) |
209 (ThumbBit << 29) |
210 (IsPCRel << 30) |
211 macho::RF_Scattered);
212 MRE.Word1 = Value2;
213 Writer->addRelocation(Fragment->getParent(), MRE);
214 }
215
216 macho::RelocationEntry MRE;
217 MRE.Word0 = ((FixupOffset << 0) |
218 (Type << 24) |
219 (MovtBit << 28) |
220 (ThumbBit << 29) |
221 (IsPCRel << 30) |
222 macho::RF_Scattered);
223 MRE.Word1 = Value;
224 Writer->addRelocation(Fragment->getParent(), MRE);
225}
226
227void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
228 const MCAssembler &Asm,
229 const MCAsmLayout &Layout,
230 const MCFragment *Fragment,
231 const MCFixup &Fixup,
232 MCValue Target,
233 unsigned Log2Size,
234 uint64_t &FixedValue) {
235 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
236 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
237 unsigned Type = macho::RIT_Vanilla;
238
239 // See <reloc.h>.
240 const MCSymbol *A = &Target.getSymA()->getSymbol();
241 MCSymbolData *A_SD = &Asm.getSymbolData(*A);
242
243 if (!A_SD->getFragment())
244 report_fatal_error("symbol '" + A->getName() +
245 "' can not be undefined in a subtraction expression");
246
247 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
248 uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent());
249 FixedValue += SecAddr;
250 uint32_t Value2 = 0;
251
252 if (const MCSymbolRefExpr *B = Target.getSymB()) {
253 MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
254
255 if (!B_SD->getFragment())
256 report_fatal_error("symbol '" + B->getSymbol().getName() +
257 "' can not be undefined in a subtraction expression");
258
259 // Select the appropriate difference relocation type.
260 Type = macho::RIT_Difference;
261 Value2 = Writer->getSymbolAddress(B_SD, Layout);
262 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
263 }
264
265 // Relocations are written out in reverse order, so the PAIR comes first.
266 if (Type == macho::RIT_Difference ||
267 Type == macho::RIT_Generic_LocalDifference) {
268 macho::RelocationEntry MRE;
269 MRE.Word0 = ((0 << 0) |
270 (macho::RIT_Pair << 24) |
271 (Log2Size << 28) |
272 (IsPCRel << 30) |
273 macho::RF_Scattered);
274 MRE.Word1 = Value2;
275 Writer->addRelocation(Fragment->getParent(), MRE);
276 }
277
278 macho::RelocationEntry MRE;
279 MRE.Word0 = ((FixupOffset << 0) |
280 (Type << 24) |
281 (Log2Size << 28) |
282 (IsPCRel << 30) |
283 macho::RF_Scattered);
284 MRE.Word1 = Value;
285 Writer->addRelocation(Fragment->getParent(), MRE);
286}
287
288void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer,
289 const MCAssembler &Asm,
290 const MCAsmLayout &Layout,
291 const MCFragment *Fragment,
292 const MCFixup &Fixup,
293 MCValue Target,
294 uint64_t &FixedValue) {
295 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
296 unsigned Log2Size;
297 unsigned RelocType = macho::RIT_Vanilla;
Jim Grosbach42e6bd32012-01-26 23:20:15 +0000298 if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size))
299 // If we failed to get fixup kind info, it's because there's no legal
300 // relocation type for the fixup kind. This happens when it's a fixup that's
301 // expected to always be resolvable at assembly time and not have any
302 // relocations needed.
303 Asm.getContext().FatalError(Fixup.getLoc(),
304 "unsupported relocation on symbol");
Jim Grosbachba8297e2011-06-24 23:44:37 +0000305
306 // If this is a difference or a defined symbol plus an offset, then we need a
307 // scattered relocation entry. Differences always require scattered
308 // relocations.
309 if (Target.getSymB()) {
310 if (RelocType == macho::RIT_ARM_Half ||
311 RelocType == macho::RIT_ARM_HalfDifference)
312 return RecordARMMovwMovtRelocation(Writer, Asm, Layout, Fragment, Fixup,
313 Target, FixedValue);
314 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
315 Target, Log2Size, FixedValue);
316 }
317
318 // Get the symbol data, if any.
319 MCSymbolData *SD = 0;
320 if (Target.getSymA())
321 SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
322
323 // FIXME: For other platforms, we need to use scattered relocations for
324 // internal relocations with offsets. If this is an internal relocation with
325 // an offset, it also needs a scattered relocation entry.
326 //
327 // Is this right for ARM?
328 uint32_t Offset = Target.getConstant();
329 if (IsPCRel && RelocType == macho::RIT_Vanilla)
330 Offset += 1 << Log2Size;
331 if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD))
332 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
333 Target, Log2Size, FixedValue);
334
335 // See <reloc.h>.
336 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
337 unsigned Index = 0;
338 unsigned IsExtern = 0;
339 unsigned Type = 0;
340
341 if (Target.isAbsolute()) { // constant
342 // FIXME!
343 report_fatal_error("FIXME: relocations to absolute targets "
344 "not yet implemented");
345 } else {
346 // Resolve constant variables.
347 if (SD->getSymbol().isVariable()) {
348 int64_t Res;
349 if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
350 Res, Layout, Writer->getSectionAddressMap())) {
351 FixedValue = Res;
352 return;
353 }
354 }
355
356 // Check whether we need an external or internal relocation.
357 if (Writer->doesSymbolRequireExternRelocation(SD)) {
358 IsExtern = 1;
359 Index = SD->getIndex();
360
361 // For external relocations, make sure to offset the fixup value to
362 // compensate for the addend of the symbol address, if it was
363 // undefined. This occurs with weak definitions, for example.
364 if (!SD->Symbol->isUndefined())
365 FixedValue -= Layout.getSymbolOffset(SD);
366 } else {
367 // The index is the section ordinal (1-based).
368 const MCSectionData &SymSD = Asm.getSectionData(
369 SD->getSymbol().getSection());
370 Index = SymSD.getOrdinal() + 1;
371 FixedValue += Writer->getSectionAddress(&SymSD);
372 }
373 if (IsPCRel)
374 FixedValue -= Writer->getSectionAddress(Fragment->getParent());
375
376 // The type is determined by the fixup kind.
377 Type = RelocType;
378 }
379
380 // struct relocation_info (8 bytes)
381 macho::RelocationEntry MRE;
382 MRE.Word0 = FixupOffset;
383 MRE.Word1 = ((Index << 0) |
384 (IsPCRel << 24) |
385 (Log2Size << 25) |
386 (IsExtern << 27) |
387 (Type << 28));
388 Writer->addRelocation(Fragment->getParent(), MRE);
389}
390
Jim Grosbach2fc68982011-06-22 20:14:52 +0000391MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS,
392 bool Is64Bit,
393 uint32_t CPUType,
394 uint32_t CPUSubtype) {
395 return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit,
396 CPUType,
397 CPUSubtype),
398 OS, /*IsLittleEndian=*/true);
399}