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