ARMMachObjectWriter.cpp revision 288943
1//===-- 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 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/MCMachObjectWriter.h" 21#include "llvm/MC/MCSection.h" 22#include "llvm/MC/MCValue.h" 23#include "llvm/Support/ErrorHandling.h" 24#include "llvm/Support/MachO.h" 25using namespace llvm; 26 27namespace { 28class ARMMachObjectWriter : public MCMachObjectTargetWriter { 29 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 Type, 36 unsigned Log2Size, 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); 44 45 bool requiresExternRelocation(MachObjectWriter *Writer, 46 const MCAssembler &Asm, 47 const MCFragment &Fragment, unsigned RelocType, 48 const MCSymbol &S, uint64_t FixedValue); 49 50public: 51 ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype) 52 : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {} 53 54 void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm, 55 const MCAsmLayout &Layout, const MCFragment *Fragment, 56 const MCFixup &Fixup, MCValue Target, 57 uint64_t &FixedValue) override; 58}; 59} 60 61static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType, 62 unsigned &Log2Size) { 63 RelocType = unsigned(MachO::ARM_RELOC_VANILLA); 64 Log2Size = ~0U; 65 66 switch (Kind) { 67 default: 68 return false; 69 70 case FK_Data_1: 71 Log2Size = llvm::Log2_32(1); 72 return true; 73 case FK_Data_2: 74 Log2Size = llvm::Log2_32(2); 75 return true; 76 case FK_Data_4: 77 Log2Size = llvm::Log2_32(4); 78 return true; 79 case FK_Data_8: 80 Log2Size = llvm::Log2_32(8); 81 return true; 82 83 // These fixups are expected to always be resolvable at assembly time and 84 // have no relocations supported. 85 case ARM::fixup_arm_ldst_pcrel_12: 86 case ARM::fixup_arm_pcrel_10: 87 case ARM::fixup_arm_adr_pcrel_12: 88 case ARM::fixup_arm_thumb_br: 89 return false; 90 91 // Handle 24-bit branch kinds. 92 case ARM::fixup_arm_condbranch: 93 case ARM::fixup_arm_uncondbranch: 94 case ARM::fixup_arm_uncondbl: 95 case ARM::fixup_arm_condbl: 96 case ARM::fixup_arm_blx: 97 RelocType = unsigned(MachO::ARM_RELOC_BR24); 98 // Report as 'long', even though that is not quite accurate. 99 Log2Size = llvm::Log2_32(4); 100 return true; 101 102 case ARM::fixup_t2_uncondbranch: 103 case ARM::fixup_arm_thumb_bl: 104 case ARM::fixup_arm_thumb_blx: 105 RelocType = unsigned(MachO::ARM_THUMB_RELOC_BR22); 106 Log2Size = llvm::Log2_32(4); 107 return true; 108 109 // For movw/movt r_type relocations they always have a pair following them and 110 // the r_length bits are used differently. The encoding of the r_length is as 111 // follows: 112 // low bit of r_length: 113 // 0 - :lower16: for movw instructions 114 // 1 - :upper16: for movt instructions 115 // high bit of r_length: 116 // 0 - arm instructions 117 // 1 - thumb instructions 118 case ARM::fixup_arm_movt_hi16: 119 RelocType = unsigned(MachO::ARM_RELOC_HALF); 120 Log2Size = 1; 121 return true; 122 case ARM::fixup_t2_movt_hi16: 123 RelocType = unsigned(MachO::ARM_RELOC_HALF); 124 Log2Size = 3; 125 return true; 126 127 case ARM::fixup_arm_movw_lo16: 128 RelocType = unsigned(MachO::ARM_RELOC_HALF); 129 Log2Size = 0; 130 return true; 131 case ARM::fixup_t2_movw_lo16: 132 RelocType = unsigned(MachO::ARM_RELOC_HALF); 133 Log2Size = 2; 134 return true; 135 } 136} 137 138void ARMMachObjectWriter:: 139RecordARMScatteredHalfRelocation(MachObjectWriter *Writer, 140 const MCAssembler &Asm, 141 const MCAsmLayout &Layout, 142 const MCFragment *Fragment, 143 const MCFixup &Fixup, 144 MCValue Target, 145 uint64_t &FixedValue) { 146 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 147 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 148 unsigned Type = MachO::ARM_RELOC_HALF; 149 150 // See <reloc.h>. 151 const MCSymbol *A = &Target.getSymA()->getSymbol(); 152 153 if (!A->getFragment()) 154 Asm.getContext().reportFatalError(Fixup.getLoc(), 155 "symbol '" + A->getName() + 156 "' can not be undefined in a subtraction expression"); 157 158 uint32_t Value = Writer->getSymbolAddress(*A, Layout); 159 uint32_t Value2 = 0; 160 uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent()); 161 FixedValue += SecAddr; 162 163 if (const MCSymbolRefExpr *B = Target.getSymB()) { 164 const MCSymbol *SB = &B->getSymbol(); 165 166 if (!SB->getFragment()) 167 Asm.getContext().reportFatalError(Fixup.getLoc(), 168 "symbol '" + B->getSymbol().getName() + 169 "' can not be undefined in a subtraction expression"); 170 171 // Select the appropriate difference relocation type. 172 Type = MachO::ARM_RELOC_HALF_SECTDIFF; 173 Value2 = Writer->getSymbolAddress(B->getSymbol(), Layout); 174 FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent()); 175 } 176 177 // Relocations are written out in reverse order, so the PAIR comes first. 178 // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field: 179 // 180 // For these two r_type relocations they always have a pair following them and 181 // the r_length bits are used differently. The encoding of the r_length is as 182 // follows: 183 // low bit of r_length: 184 // 0 - :lower16: for movw instructions 185 // 1 - :upper16: for movt instructions 186 // high bit of r_length: 187 // 0 - arm instructions 188 // 1 - thumb instructions 189 // the other half of the relocated expression is in the following pair 190 // relocation entry in the low 16 bits of r_address field. 191 unsigned ThumbBit = 0; 192 unsigned MovtBit = 0; 193 switch ((unsigned)Fixup.getKind()) { 194 default: break; 195 case ARM::fixup_arm_movt_hi16: 196 MovtBit = 1; 197 // The thumb bit shouldn't be set in the 'other-half' bit of the 198 // relocation, but it will be set in FixedValue if the base symbol 199 // is a thumb function. Clear it out here. 200 if (Asm.isThumbFunc(A)) 201 FixedValue &= 0xfffffffe; 202 break; 203 case ARM::fixup_t2_movt_hi16: 204 if (Asm.isThumbFunc(A)) 205 FixedValue &= 0xfffffffe; 206 MovtBit = 1; 207 // Fallthrough 208 case ARM::fixup_t2_movw_lo16: 209 ThumbBit = 1; 210 break; 211 } 212 213 if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) { 214 uint32_t OtherHalf = MovtBit 215 ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16); 216 217 MachO::any_relocation_info MRE; 218 MRE.r_word0 = ((OtherHalf << 0) | 219 (MachO::ARM_RELOC_PAIR << 24) | 220 (MovtBit << 28) | 221 (ThumbBit << 29) | 222 (IsPCRel << 30) | 223 MachO::R_SCATTERED); 224 MRE.r_word1 = Value2; 225 Writer->addRelocation(nullptr, Fragment->getParent(), MRE); 226 } 227 228 MachO::any_relocation_info MRE; 229 MRE.r_word0 = ((FixupOffset << 0) | 230 (Type << 24) | 231 (MovtBit << 28) | 232 (ThumbBit << 29) | 233 (IsPCRel << 30) | 234 MachO::R_SCATTERED); 235 MRE.r_word1 = Value; 236 Writer->addRelocation(nullptr, Fragment->getParent(), MRE); 237} 238 239void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer, 240 const MCAssembler &Asm, 241 const MCAsmLayout &Layout, 242 const MCFragment *Fragment, 243 const MCFixup &Fixup, 244 MCValue Target, 245 unsigned Type, 246 unsigned Log2Size, 247 uint64_t &FixedValue) { 248 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 249 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 250 251 // See <reloc.h>. 252 const MCSymbol *A = &Target.getSymA()->getSymbol(); 253 254 if (!A->getFragment()) 255 Asm.getContext().reportFatalError(Fixup.getLoc(), 256 "symbol '" + A->getName() + 257 "' can not be undefined in a subtraction expression"); 258 259 uint32_t Value = Writer->getSymbolAddress(*A, Layout); 260 uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent()); 261 FixedValue += SecAddr; 262 uint32_t Value2 = 0; 263 264 if (const MCSymbolRefExpr *B = Target.getSymB()) { 265 assert(Type == MachO::ARM_RELOC_VANILLA && "invalid reloc for 2 symbols"); 266 const MCSymbol *SB = &B->getSymbol(); 267 268 if (!SB->getFragment()) 269 Asm.getContext().reportFatalError(Fixup.getLoc(), 270 "symbol '" + B->getSymbol().getName() + 271 "' can not be undefined in a subtraction expression"); 272 273 // Select the appropriate difference relocation type. 274 Type = MachO::ARM_RELOC_SECTDIFF; 275 Value2 = Writer->getSymbolAddress(B->getSymbol(), Layout); 276 FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent()); 277 } 278 279 // Relocations are written out in reverse order, so the PAIR comes first. 280 if (Type == MachO::ARM_RELOC_SECTDIFF || 281 Type == MachO::ARM_RELOC_LOCAL_SECTDIFF) { 282 MachO::any_relocation_info MRE; 283 MRE.r_word0 = ((0 << 0) | 284 (MachO::ARM_RELOC_PAIR << 24) | 285 (Log2Size << 28) | 286 (IsPCRel << 30) | 287 MachO::R_SCATTERED); 288 MRE.r_word1 = Value2; 289 Writer->addRelocation(nullptr, Fragment->getParent(), MRE); 290 } 291 292 MachO::any_relocation_info MRE; 293 MRE.r_word0 = ((FixupOffset << 0) | 294 (Type << 24) | 295 (Log2Size << 28) | 296 (IsPCRel << 30) | 297 MachO::R_SCATTERED); 298 MRE.r_word1 = Value; 299 Writer->addRelocation(nullptr, Fragment->getParent(), MRE); 300} 301 302bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer, 303 const MCAssembler &Asm, 304 const MCFragment &Fragment, 305 unsigned RelocType, 306 const MCSymbol &S, 307 uint64_t FixedValue) { 308 // Most cases can be identified purely from the symbol. 309 if (Writer->doesSymbolRequireExternRelocation(S)) 310 return true; 311 int64_t Value = (int64_t)FixedValue; // The displacement is signed. 312 int64_t Range; 313 switch (RelocType) { 314 default: 315 return false; 316 case MachO::ARM_RELOC_BR24: 317 // PC pre-adjustment of 8 for these instructions. 318 Value -= 8; 319 // ARM BL/BLX has a 25-bit offset. 320 Range = 0x1ffffff; 321 break; 322 case MachO::ARM_THUMB_RELOC_BR22: 323 // PC pre-adjustment of 4 for these instructions. 324 Value -= 4; 325 // Thumb BL/BLX has a 24-bit offset. 326 Range = 0xffffff; 327 } 328 // BL/BLX also use external relocations when an internal relocation 329 // would result in the target being out of range. This gives the linker 330 // enough information to generate a branch island. 331 Value += Writer->getSectionAddress(&S.getSection()); 332 Value -= Writer->getSectionAddress(Fragment.getParent()); 333 // If the resultant value would be out of range for an internal relocation, 334 // use an external instead. 335 if (Value > Range || Value < -(Range + 1)) 336 return true; 337 return false; 338} 339 340void ARMMachObjectWriter::recordRelocation(MachObjectWriter *Writer, 341 MCAssembler &Asm, 342 const MCAsmLayout &Layout, 343 const MCFragment *Fragment, 344 const MCFixup &Fixup, MCValue Target, 345 uint64_t &FixedValue) { 346 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 347 unsigned Log2Size; 348 unsigned RelocType = MachO::ARM_RELOC_VANILLA; 349 if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) 350 // If we failed to get fixup kind info, it's because there's no legal 351 // relocation type for the fixup kind. This happens when it's a fixup that's 352 // expected to always be resolvable at assembly time and not have any 353 // relocations needed. 354 Asm.getContext().reportFatalError(Fixup.getLoc(), 355 "unsupported relocation on symbol"); 356 357 // If this is a difference or a defined symbol plus an offset, then we need a 358 // scattered relocation entry. Differences always require scattered 359 // relocations. 360 if (Target.getSymB()) { 361 if (RelocType == MachO::ARM_RELOC_HALF) 362 return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment, 363 Fixup, Target, FixedValue); 364 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 365 Target, RelocType, Log2Size, 366 FixedValue); 367 } 368 369 // Get the symbol data, if any. 370 const MCSymbol *A = nullptr; 371 if (Target.getSymA()) 372 A = &Target.getSymA()->getSymbol(); 373 374 // FIXME: For other platforms, we need to use scattered relocations for 375 // internal relocations with offsets. If this is an internal relocation with 376 // an offset, it also needs a scattered relocation entry. 377 // 378 // Is this right for ARM? 379 uint32_t Offset = Target.getConstant(); 380 if (IsPCRel && RelocType == MachO::ARM_RELOC_VANILLA) 381 Offset += 1 << Log2Size; 382 if (Offset && A && !Writer->doesSymbolRequireExternRelocation(*A)) 383 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 384 Target, RelocType, Log2Size, 385 FixedValue); 386 387 // See <reloc.h>. 388 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 389 unsigned Index = 0; 390 unsigned Type = 0; 391 const MCSymbol *RelSymbol = nullptr; 392 393 if (Target.isAbsolute()) { // constant 394 // FIXME! 395 report_fatal_error("FIXME: relocations to absolute targets " 396 "not yet implemented"); 397 } else { 398 // Resolve constant variables. 399 if (A->isVariable()) { 400 int64_t Res; 401 if (A->getVariableValue()->evaluateAsAbsolute( 402 Res, Layout, Writer->getSectionAddressMap())) { 403 FixedValue = Res; 404 return; 405 } 406 } 407 408 // Check whether we need an external or internal relocation. 409 if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, *A, 410 FixedValue)) { 411 RelSymbol = A; 412 413 // For external relocations, make sure to offset the fixup value to 414 // compensate for the addend of the symbol address, if it was 415 // undefined. This occurs with weak definitions, for example. 416 if (!A->isUndefined()) 417 FixedValue -= Layout.getSymbolOffset(*A); 418 } else { 419 // The index is the section ordinal (1-based). 420 const MCSection &Sec = A->getSection(); 421 Index = Sec.getOrdinal() + 1; 422 FixedValue += Writer->getSectionAddress(&Sec); 423 } 424 if (IsPCRel) 425 FixedValue -= Writer->getSectionAddress(Fragment->getParent()); 426 427 // The type is determined by the fixup kind. 428 Type = RelocType; 429 } 430 431 // struct relocation_info (8 bytes) 432 MachO::any_relocation_info MRE; 433 MRE.r_word0 = FixupOffset; 434 MRE.r_word1 = 435 (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); 436 437 // Even when it's not a scattered relocation, movw/movt always uses 438 // a PAIR relocation. 439 if (Type == MachO::ARM_RELOC_HALF) { 440 // The other-half value only gets populated for the movt and movw 441 // relocation entries. 442 uint32_t Value = 0; 443 switch ((unsigned)Fixup.getKind()) { 444 default: break; 445 case ARM::fixup_arm_movw_lo16: 446 case ARM::fixup_t2_movw_lo16: 447 Value = (FixedValue >> 16) & 0xffff; 448 break; 449 case ARM::fixup_arm_movt_hi16: 450 case ARM::fixup_t2_movt_hi16: 451 Value = FixedValue & 0xffff; 452 break; 453 } 454 MachO::any_relocation_info MREPair; 455 MREPair.r_word0 = Value; 456 MREPair.r_word1 = ((0xffffff << 0) | 457 (Log2Size << 25) | 458 (MachO::ARM_RELOC_PAIR << 28)); 459 460 Writer->addRelocation(nullptr, Fragment->getParent(), MREPair); 461 } 462 463 Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); 464} 465 466MCObjectWriter *llvm::createARMMachObjectWriter(raw_pwrite_stream &OS, 467 bool Is64Bit, uint32_t CPUType, 468 uint32_t CPUSubtype) { 469 return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit, 470 CPUType, 471 CPUSubtype), 472 OS, /*IsLittleEndian=*/true); 473} 474