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, 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 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(nullptr, 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(nullptr, 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(nullptr, 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(nullptr, 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 MCAssembler &Asm, 355 const MCAsmLayout &Layout, 356 const MCFragment *Fragment, 357 const MCFixup &Fixup, MCValue Target, 358 uint64_t &FixedValue) { 359 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 360 unsigned Log2Size; 361 unsigned RelocType = MachO::ARM_RELOC_VANILLA; 362 if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) 363 // If we failed to get fixup kind info, it's because there's no legal 364 // relocation type for the fixup kind. This happens when it's a fixup that's 365 // expected to always be resolvable at assembly time and not have any 366 // relocations needed. 367 Asm.getContext().FatalError(Fixup.getLoc(), 368 "unsupported relocation on symbol"); 369 370 // If this is a difference or a defined symbol plus an offset, then we need a 371 // scattered relocation entry. Differences always require scattered 372 // relocations. 373 if (Target.getSymB()) { 374 if (RelocType == MachO::ARM_RELOC_HALF) 375 return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment, 376 Fixup, Target, FixedValue); 377 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 378 Target, RelocType, Log2Size, 379 FixedValue); 380 } 381 382 // Get the symbol data, if any. 383 const MCSymbolData *SD = nullptr; 384 if (Target.getSymA()) 385 SD = &Asm.getSymbolData(Target.getSymA()->getSymbol()); 386 387 // FIXME: For other platforms, we need to use scattered relocations for 388 // internal relocations with offsets. If this is an internal relocation with 389 // an offset, it also needs a scattered relocation entry. 390 // 391 // Is this right for ARM? 392 uint32_t Offset = Target.getConstant(); 393 if (IsPCRel && RelocType == MachO::ARM_RELOC_VANILLA) 394 Offset += 1 << Log2Size; 395 if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD)) 396 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 397 Target, RelocType, Log2Size, 398 FixedValue); 399 400 // See <reloc.h>. 401 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 402 unsigned Index = 0; 403 unsigned Type = 0; 404 const MCSymbolData *RelSymbol = nullptr; 405 406 if (Target.isAbsolute()) { // constant 407 // FIXME! 408 report_fatal_error("FIXME: relocations to absolute targets " 409 "not yet implemented"); 410 } else { 411 // Resolve constant variables. 412 if (SD->getSymbol().isVariable()) { 413 int64_t Res; 414 if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( 415 Res, Layout, Writer->getSectionAddressMap())) { 416 FixedValue = Res; 417 return; 418 } 419 } 420 421 // Check whether we need an external or internal relocation. 422 if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, SD, 423 FixedValue)) { 424 RelSymbol = SD; 425 426 // For external relocations, make sure to offset the fixup value to 427 // compensate for the addend of the symbol address, if it was 428 // undefined. This occurs with weak definitions, for example. 429 if (!SD->getSymbol().isUndefined()) 430 FixedValue -= Layout.getSymbolOffset(SD); 431 } else { 432 // The index is the section ordinal (1-based). 433 const MCSectionData &SymSD = Asm.getSectionData( 434 SD->getSymbol().getSection()); 435 Index = SymSD.getOrdinal() + 1; 436 FixedValue += Writer->getSectionAddress(&SymSD); 437 } 438 if (IsPCRel) 439 FixedValue -= Writer->getSectionAddress(Fragment->getParent()); 440 441 // The type is determined by the fixup kind. 442 Type = RelocType; 443 } 444 445 // struct relocation_info (8 bytes) 446 MachO::any_relocation_info MRE; 447 MRE.r_word0 = FixupOffset; 448 MRE.r_word1 = 449 (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); 450 451 // Even when it's not a scattered relocation, movw/movt always uses 452 // a PAIR relocation. 453 if (Type == MachO::ARM_RELOC_HALF) { 454 // The other-half value only gets populated for the movt and movw 455 // relocation entries. 456 uint32_t Value = 0; 457 switch ((unsigned)Fixup.getKind()) { 458 default: break; 459 case ARM::fixup_arm_movw_lo16: 460 case ARM::fixup_t2_movw_lo16: 461 Value = (FixedValue >> 16) & 0xffff; 462 break; 463 case ARM::fixup_arm_movt_hi16: 464 case ARM::fixup_t2_movt_hi16: 465 Value = FixedValue & 0xffff; 466 break; 467 } 468 MachO::any_relocation_info MREPair; 469 MREPair.r_word0 = Value; 470 MREPair.r_word1 = ((0xffffff << 0) | 471 (Log2Size << 25) | 472 (MachO::ARM_RELOC_PAIR << 28)); 473 474 Writer->addRelocation(nullptr, Fragment->getParent(), MREPair); 475 } 476 477 Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); 478 } 479 480 MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS, 481 bool Is64Bit, 482 uint32_t CPUType, 483 uint32_t CPUSubtype) { 484 return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit, 485 CPUType, 486 CPUSubtype), 487 OS, /*IsLittleEndian=*/true); 488 } 489