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