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/Object/MachOFormat.h"
24 #include "llvm/Support/ErrorHandling.h"
26 using namespace llvm::object
;
29 class ARMMachObjectWriter
: public MCMachObjectTargetWriter
{
30 void RecordARMScatteredRelocation(MachObjectWriter
*Writer
,
31 const MCAssembler
&Asm
,
32 const MCAsmLayout
&Layout
,
33 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
);
64 static bool getARMFixupKindMachOInfo(unsigned Kind
, unsigned &RelocType
,
66 RelocType
= unsigned(macho::RIT_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 // Handle 24-bit branch kinds.
87 case ARM::fixup_arm_ldst_pcrel_12
:
88 case ARM::fixup_arm_pcrel_10
:
89 case ARM::fixup_arm_adr_pcrel_12
:
90 case ARM::fixup_arm_condbranch
:
91 case ARM::fixup_arm_uncondbranch
:
92 case ARM::fixup_arm_uncondbl
:
93 case ARM::fixup_arm_condbl
:
94 case ARM::fixup_arm_blx
:
95 RelocType
= unsigned(macho::RIT_ARM_Branch24Bit
);
96 // Report as 'long', even though that is not quite accurate.
97 Log2Size
= llvm::Log2_32(4);
100 // Handle Thumb branches.
101 case ARM::fixup_arm_thumb_br
:
102 RelocType
= unsigned(macho::RIT_ARM_ThumbBranch22Bit
);
103 Log2Size
= llvm::Log2_32(2);
106 case ARM::fixup_t2_uncondbranch
:
107 case ARM::fixup_arm_thumb_bl
:
108 case ARM::fixup_arm_thumb_blx
:
109 RelocType
= unsigned(macho::RIT_ARM_ThumbBranch22Bit
);
110 Log2Size
= llvm::Log2_32(4);
113 // For movw/movt r_type relocations they always have a pair following them and
114 // the r_length bits are used differently. The encoding of the r_length is as
116 // low bit of r_length:
117 // 0 - :lower16: for movw instructions
118 // 1 - :upper16: for movt instructions
119 // high bit of r_length:
120 // 0 - arm instructions
121 // 1 - thumb instructions
122 case ARM::fixup_arm_movt_hi16
:
123 case ARM::fixup_arm_movt_hi16_pcrel
:
124 RelocType
= unsigned(macho::RIT_ARM_Half
);
127 case ARM::fixup_t2_movt_hi16
:
128 case ARM::fixup_t2_movt_hi16_pcrel
:
129 RelocType
= unsigned(macho::RIT_ARM_Half
);
133 case ARM::fixup_arm_movw_lo16
:
134 case ARM::fixup_arm_movw_lo16_pcrel
:
135 RelocType
= unsigned(macho::RIT_ARM_Half
);
138 case ARM::fixup_t2_movw_lo16
:
139 case ARM::fixup_t2_movw_lo16_pcrel
:
140 RelocType
= unsigned(macho::RIT_ARM_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::RIT_ARM_Half
;
159 const MCSymbol
*A
= &Target
.getSymA()->getSymbol();
160 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 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::RIT_ARM_HalfDifference
;
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
:
206 case ARM::fixup_arm_movt_hi16_pcrel
:
208 // The thumb bit shouldn't be set in the 'other-half' bit of the
209 // relocation, but it will be set in FixedValue if the base symbol
210 // is a thumb function. Clear it out here.
211 if (A_SD
->getFlags() & SF_ThumbFunc
)
212 FixedValue
&= 0xfffffffe;
214 case ARM::fixup_t2_movt_hi16
:
215 case ARM::fixup_t2_movt_hi16_pcrel
:
216 if (A_SD
->getFlags() & SF_ThumbFunc
)
217 FixedValue
&= 0xfffffffe;
220 case ARM::fixup_t2_movw_lo16
:
221 case ARM::fixup_t2_movw_lo16_pcrel
:
226 if (Type
== macho::RIT_ARM_HalfDifference
) {
227 uint32_t OtherHalf
= MovtBit
228 ? (FixedValue
& 0xffff) : ((FixedValue
& 0xffff0000) >> 16);
230 macho::RelocationEntry MRE
;
231 MRE
.Word0
= ((OtherHalf
<< 0) |
232 (macho::RIT_Pair
<< 24) |
236 macho::RF_Scattered
);
238 Writer
->addRelocation(Fragment
->getParent(), MRE
);
241 macho::RelocationEntry MRE
;
242 MRE
.Word0
= ((FixupOffset
<< 0) |
247 macho::RF_Scattered
);
249 Writer
->addRelocation(Fragment
->getParent(), MRE
);
252 void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter
*Writer
,
253 const MCAssembler
&Asm
,
254 const MCAsmLayout
&Layout
,
255 const MCFragment
*Fragment
,
256 const MCFixup
&Fixup
,
259 uint64_t &FixedValue
) {
260 uint32_t FixupOffset
= Layout
.getFragmentOffset(Fragment
)+Fixup
.getOffset();
261 unsigned IsPCRel
= Writer
->isFixupKindPCRel(Asm
, Fixup
.getKind());
262 unsigned Type
= macho::RIT_Vanilla
;
265 const MCSymbol
*A
= &Target
.getSymA()->getSymbol();
266 MCSymbolData
*A_SD
= &Asm
.getSymbolData(*A
);
268 if (!A_SD
->getFragment())
269 Asm
.getContext().FatalError(Fixup
.getLoc(),
270 "symbol '" + A
->getName() +
271 "' can not be undefined in a subtraction expression");
273 uint32_t Value
= Writer
->getSymbolAddress(A_SD
, Layout
);
274 uint64_t SecAddr
= Writer
->getSectionAddress(A_SD
->getFragment()->getParent());
275 FixedValue
+= SecAddr
;
278 if (const MCSymbolRefExpr
*B
= Target
.getSymB()) {
279 MCSymbolData
*B_SD
= &Asm
.getSymbolData(B
->getSymbol());
281 if (!B_SD
->getFragment())
282 Asm
.getContext().FatalError(Fixup
.getLoc(),
283 "symbol '" + B
->getSymbol().getName() +
284 "' can not be undefined in a subtraction expression");
286 // Select the appropriate difference relocation type.
287 Type
= macho::RIT_Difference
;
288 Value2
= Writer
->getSymbolAddress(B_SD
, Layout
);
289 FixedValue
-= Writer
->getSectionAddress(B_SD
->getFragment()->getParent());
292 // Relocations are written out in reverse order, so the PAIR comes first.
293 if (Type
== macho::RIT_Difference
||
294 Type
== macho::RIT_Generic_LocalDifference
) {
295 macho::RelocationEntry MRE
;
296 MRE
.Word0
= ((0 << 0) |
297 (macho::RIT_Pair
<< 24) |
300 macho::RF_Scattered
);
302 Writer
->addRelocation(Fragment
->getParent(), MRE
);
305 macho::RelocationEntry MRE
;
306 MRE
.Word0
= ((FixupOffset
<< 0) |
310 macho::RF_Scattered
);
312 Writer
->addRelocation(Fragment
->getParent(), MRE
);
315 bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter
*Writer
,
316 const MCAssembler
&Asm
,
317 const MCFragment
&Fragment
,
319 const MCSymbolData
*SD
,
320 uint64_t FixedValue
) {
321 // Most cases can be identified purely from the symbol.
322 if (Writer
->doesSymbolRequireExternRelocation(SD
))
324 int64_t Value
= (int64_t)FixedValue
; // The displacement is signed.
329 case macho::RIT_ARM_Branch24Bit
:
330 // PC pre-adjustment of 8 for these instructions.
332 // ARM BL/BLX has a 25-bit offset.
335 case macho::RIT_ARM_ThumbBranch22Bit
:
336 // PC pre-adjustment of 4 for these instructions.
338 // Thumb BL/BLX has a 24-bit offset.
341 // BL/BLX also use external relocations when an internal relocation
342 // would result in the target being out of range. This gives the linker
343 // enough information to generate a branch island.
344 const MCSectionData
&SymSD
= Asm
.getSectionData(
345 SD
->getSymbol().getSection());
346 Value
+= Writer
->getSectionAddress(&SymSD
);
347 Value
-= Writer
->getSectionAddress(Fragment
.getParent());
348 // If the resultant value would be out of range for an internal relocation,
349 // use an external instead.
350 if (Value
> Range
|| Value
< -(Range
+ 1))
355 void ARMMachObjectWriter::RecordRelocation(MachObjectWriter
*Writer
,
356 const MCAssembler
&Asm
,
357 const MCAsmLayout
&Layout
,
358 const MCFragment
*Fragment
,
359 const MCFixup
&Fixup
,
361 uint64_t &FixedValue
) {
362 unsigned IsPCRel
= Writer
->isFixupKindPCRel(Asm
, Fixup
.getKind());
364 unsigned RelocType
= macho::RIT_Vanilla
;
365 if (!getARMFixupKindMachOInfo(Fixup
.getKind(), RelocType
, Log2Size
))
366 // If we failed to get fixup kind info, it's because there's no legal
367 // relocation type for the fixup kind. This happens when it's a fixup that's
368 // expected to always be resolvable at assembly time and not have any
369 // relocations needed.
370 Asm
.getContext().FatalError(Fixup
.getLoc(),
371 "unsupported relocation on symbol");
373 // If this is a difference or a defined symbol plus an offset, then we need a
374 // scattered relocation entry. Differences always require scattered
376 if (Target
.getSymB()) {
377 if (RelocType
== macho::RIT_ARM_Half
)
378 return RecordARMScatteredHalfRelocation(Writer
, Asm
, Layout
, Fragment
,
379 Fixup
, Target
, FixedValue
);
380 return RecordARMScatteredRelocation(Writer
, Asm
, Layout
, Fragment
, Fixup
,
381 Target
, Log2Size
, FixedValue
);
384 // Get the symbol data, if any.
385 MCSymbolData
*SD
= 0;
386 if (Target
.getSymA())
387 SD
= &Asm
.getSymbolData(Target
.getSymA()->getSymbol());
389 // FIXME: For other platforms, we need to use scattered relocations for
390 // internal relocations with offsets. If this is an internal relocation with
391 // an offset, it also needs a scattered relocation entry.
393 // Is this right for ARM?
394 uint32_t Offset
= Target
.getConstant();
395 if (IsPCRel
&& RelocType
== macho::RIT_Vanilla
)
396 Offset
+= 1 << Log2Size
;
397 if (Offset
&& SD
&& !Writer
->doesSymbolRequireExternRelocation(SD
))
398 return RecordARMScatteredRelocation(Writer
, Asm
, Layout
, Fragment
, Fixup
,
399 Target
, Log2Size
, FixedValue
);
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::RelocationEntry MRE
;
449 MRE
.Word0
= FixupOffset
;
450 MRE
.Word1
= ((Index
<< 0) |
456 // Even when it's not a scattered relocation, movw/movt always uses
457 // a PAIR relocation.
458 if (Type
== macho::RIT_ARM_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_arm_movw_lo16_pcrel
:
466 case ARM::fixup_t2_movw_lo16
:
467 case ARM::fixup_t2_movw_lo16_pcrel
:
468 Value
= (FixedValue
>> 16) & 0xffff;
470 case ARM::fixup_arm_movt_hi16
:
471 case ARM::fixup_arm_movt_hi16_pcrel
:
472 case ARM::fixup_t2_movt_hi16
:
473 case ARM::fixup_t2_movt_hi16_pcrel
:
474 Value
= FixedValue
& 0xffff;
477 macho::RelocationEntry MREPair
;
478 MREPair
.Word0
= Value
;
479 MREPair
.Word1
= ((0xffffff) |
481 (macho::RIT_Pair
<< 28));
483 Writer
->addRelocation(Fragment
->getParent(), MREPair
);
486 Writer
->addRelocation(Fragment
->getParent(), MRE
);
489 MCObjectWriter
*llvm::createARMMachObjectWriter(raw_ostream
&OS
,
492 uint32_t CPUSubtype
) {
493 return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit
,
496 OS
, /*IsLittleEndian=*/true);