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 //===----------------------------------------------------------------------===//
11 #include "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/MCValue.h"
20 #include "llvm/Object/MachOFormat.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Target/TargetAsmBackend.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);
66 Log2Size = llvm::Log2_32(1);
69 Log2Size = llvm::Log2_32(2);
72 Log2Size = llvm::Log2_32(4);
75 Log2Size = llvm::Log2_32(8);
78 // Handle 24-bit branch kinds.
79 case ARM::fixup_arm_ldst_pcrel_12:
80 case ARM::fixup_arm_pcrel_10:
81 case ARM::fixup_arm_adr_pcrel_12:
82 case ARM::fixup_arm_condbranch:
83 case ARM::fixup_arm_uncondbranch:
84 RelocType = unsigned(macho::RIT_ARM_Branch24Bit);
85 // Report as 'long', even though that is not quite accurate.
86 Log2Size = llvm::Log2_32(4);
89 // Handle Thumb branches.
90 case ARM::fixup_arm_thumb_br:
91 RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit);
92 Log2Size = llvm::Log2_32(2);
95 case ARM::fixup_t2_uncondbranch:
96 case ARM::fixup_arm_thumb_bl:
97 case ARM::fixup_arm_thumb_blx:
98 RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit);
99 Log2Size = llvm::Log2_32(4);
102 case ARM::fixup_arm_movt_hi16:
103 case ARM::fixup_arm_movt_hi16_pcrel:
104 case ARM::fixup_t2_movt_hi16:
105 case ARM::fixup_t2_movt_hi16_pcrel:
106 RelocType = unsigned(macho::RIT_ARM_HalfDifference);
107 // Report as 'long', even though that is not quite accurate.
108 Log2Size = llvm::Log2_32(4);
111 case ARM::fixup_arm_movw_lo16:
112 case ARM::fixup_arm_movw_lo16_pcrel:
113 case ARM::fixup_t2_movw_lo16:
114 case ARM::fixup_t2_movw_lo16_pcrel:
115 RelocType = unsigned(macho::RIT_ARM_Half);
116 // Report as 'long', even though that is not quite accurate.
117 Log2Size = llvm::Log2_32(4);
122 void ARMMachObjectWriter::
123 RecordARMMovwMovtRelocation(MachObjectWriter *Writer,
124 const MCAssembler &Asm,
125 const MCAsmLayout &Layout,
126 const MCFragment *Fragment,
127 const MCFixup &Fixup,
129 uint64_t &FixedValue) {
130 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
131 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
132 unsigned Type = macho::RIT_ARM_Half;
135 const MCSymbol *A = &Target.getSymA()->getSymbol();
136 MCSymbolData *A_SD = &Asm.getSymbolData(*A);
138 if (!A_SD->getFragment())
139 report_fatal_error("symbol '" + A->getName() +
140 "' can not be undefined in a subtraction expression");
142 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
145 Writer->getSectionAddress(A_SD->getFragment()->getParent());
146 FixedValue += SecAddr;
148 if (const MCSymbolRefExpr *B = Target.getSymB()) {
149 MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
151 if (!B_SD->getFragment())
152 report_fatal_error("symbol '" + B->getSymbol().getName() +
153 "' can not be undefined in a subtraction expression");
155 // Select the appropriate difference relocation type.
156 Type = macho::RIT_ARM_HalfDifference;
157 Value2 = Writer->getSymbolAddress(B_SD, Layout);
158 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
161 // Relocations are written out in reverse order, so the PAIR comes first.
162 // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
164 // For these two r_type relocations they always have a pair following them and
165 // the r_length bits are used differently. The encoding of the r_length is as
167 // low bit of r_length:
168 // 0 - :lower16: for movw instructions
169 // 1 - :upper16: for movt instructions
170 // high bit of r_length:
171 // 0 - arm instructions
172 // 1 - thumb instructions
173 // the other half of the relocated expression is in the following pair
174 // relocation entry in the the low 16 bits of r_address field.
175 unsigned ThumbBit = 0;
176 unsigned MovtBit = 0;
177 switch ((unsigned)Fixup.getKind()) {
179 case ARM::fixup_arm_movt_hi16:
180 case ARM::fixup_arm_movt_hi16_pcrel:
183 case ARM::fixup_t2_movt_hi16:
184 case ARM::fixup_t2_movt_hi16_pcrel:
187 case ARM::fixup_t2_movw_lo16:
188 case ARM::fixup_t2_movw_lo16_pcrel:
194 if (Type == macho::RIT_ARM_HalfDifference) {
195 uint32_t OtherHalf = MovtBit
196 ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
198 macho::RelocationEntry MRE;
199 MRE.Word0 = ((OtherHalf << 0) |
200 (macho::RIT_Pair << 24) |
204 macho::RF_Scattered);
206 Writer->addRelocation(Fragment->getParent(), MRE);
209 macho::RelocationEntry MRE;
210 MRE.Word0 = ((FixupOffset << 0) |
215 macho::RF_Scattered);
217 Writer->addRelocation(Fragment->getParent(), MRE);
220 void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
221 const MCAssembler &Asm,
222 const MCAsmLayout &Layout,
223 const MCFragment *Fragment,
224 const MCFixup &Fixup,
227 uint64_t &FixedValue) {
228 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
229 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
230 unsigned Type = macho::RIT_Vanilla;
233 const MCSymbol *A = &Target.getSymA()->getSymbol();
234 MCSymbolData *A_SD = &Asm.getSymbolData(*A);
236 if (!A_SD->getFragment())
237 report_fatal_error("symbol '" + A->getName() +
238 "' can not be undefined in a subtraction expression");
240 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
241 uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent());
242 FixedValue += SecAddr;
245 if (const MCSymbolRefExpr *B = Target.getSymB()) {
246 MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
248 if (!B_SD->getFragment())
249 report_fatal_error("symbol '" + B->getSymbol().getName() +
250 "' can not be undefined in a subtraction expression");
252 // Select the appropriate difference relocation type.
253 Type = macho::RIT_Difference;
254 Value2 = Writer->getSymbolAddress(B_SD, Layout);
255 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
258 // Relocations are written out in reverse order, so the PAIR comes first.
259 if (Type == macho::RIT_Difference ||
260 Type == macho::RIT_Generic_LocalDifference) {
261 macho::RelocationEntry MRE;
262 MRE.Word0 = ((0 << 0) |
263 (macho::RIT_Pair << 24) |
266 macho::RF_Scattered);
268 Writer->addRelocation(Fragment->getParent(), MRE);
271 macho::RelocationEntry MRE;
272 MRE.Word0 = ((FixupOffset << 0) |
276 macho::RF_Scattered);
278 Writer->addRelocation(Fragment->getParent(), MRE);
281 void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer,
282 const MCAssembler &Asm,
283 const MCAsmLayout &Layout,
284 const MCFragment *Fragment,
285 const MCFixup &Fixup,
287 uint64_t &FixedValue) {
288 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
290 unsigned RelocType = macho::RIT_Vanilla;
291 if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) {
292 report_fatal_error("unknown ARM fixup kind!");
296 // If this is a difference or a defined symbol plus an offset, then we need a
297 // scattered relocation entry. Differences always require scattered
299 if (Target.getSymB()) {
300 if (RelocType == macho::RIT_ARM_Half ||
301 RelocType == macho::RIT_ARM_HalfDifference)
302 return RecordARMMovwMovtRelocation(Writer, Asm, Layout, Fragment, Fixup,
304 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
305 Target, Log2Size, FixedValue);
308 // Get the symbol data, if any.
309 MCSymbolData *SD = 0;
310 if (Target.getSymA())
311 SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
313 // FIXME: For other platforms, we need to use scattered relocations for
314 // internal relocations with offsets. If this is an internal relocation with
315 // an offset, it also needs a scattered relocation entry.
317 // Is this right for ARM?
318 uint32_t Offset = Target.getConstant();
319 if (IsPCRel && RelocType == macho::RIT_Vanilla)
320 Offset += 1 << Log2Size;
321 if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD))
322 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
323 Target, Log2Size, FixedValue);
326 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
328 unsigned IsExtern = 0;
331 if (Target.isAbsolute()) { // constant
333 report_fatal_error("FIXME: relocations to absolute targets "
334 "not yet implemented");
336 // Resolve constant variables.
337 if (SD->getSymbol().isVariable()) {
339 if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
340 Res, Layout, Writer->getSectionAddressMap())) {
346 // Check whether we need an external or internal relocation.
347 if (Writer->doesSymbolRequireExternRelocation(SD)) {
349 Index = SD->getIndex();
351 // For external relocations, make sure to offset the fixup value to
352 // compensate for the addend of the symbol address, if it was
353 // undefined. This occurs with weak definitions, for example.
354 if (!SD->Symbol->isUndefined())
355 FixedValue -= Layout.getSymbolOffset(SD);
357 // The index is the section ordinal (1-based).
358 const MCSectionData &SymSD = Asm.getSectionData(
359 SD->getSymbol().getSection());
360 Index = SymSD.getOrdinal() + 1;
361 FixedValue += Writer->getSectionAddress(&SymSD);
364 FixedValue -= Writer->getSectionAddress(Fragment->getParent());
366 // The type is determined by the fixup kind.
370 // struct relocation_info (8 bytes)
371 macho::RelocationEntry MRE;
372 MRE.Word0 = FixupOffset;
373 MRE.Word1 = ((Index << 0) |
378 Writer->addRelocation(Fragment->getParent(), MRE);
381 MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS,
384 uint32_t CPUSubtype) {
385 return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit,
388 OS, /*IsLittleEndian=*/true);