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