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);