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/Object/MachOFormat.h" 24 #include "llvm/Support/ErrorHandling.h" 25 using namespace llvm; 26 using namespace llvm::object; 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 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); 61 }; 62 } 63 64 static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType, 65 unsigned &Log2Size) { 66 RelocType = unsigned(macho::RIT_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 // Handle 24-bit branch kinds. 87 case ARM::fixup_arm_ldst_pcrel_12: 88 case ARM::fixup_arm_pcrel_10: 89 case ARM::fixup_arm_adr_pcrel_12: 90 case ARM::fixup_arm_condbranch: 91 case ARM::fixup_arm_uncondbranch: 92 case ARM::fixup_arm_uncondbl: 93 case ARM::fixup_arm_condbl: 94 case ARM::fixup_arm_blx: 95 RelocType = unsigned(macho::RIT_ARM_Branch24Bit); 96 // Report as 'long', even though that is not quite accurate. 97 Log2Size = llvm::Log2_32(4); 98 return true; 99 100 // Handle Thumb branches. 101 case ARM::fixup_arm_thumb_br: 102 RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit); 103 Log2Size = llvm::Log2_32(2); 104 return true; 105 106 case ARM::fixup_t2_uncondbranch: 107 case ARM::fixup_arm_thumb_bl: 108 case ARM::fixup_arm_thumb_blx: 109 RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit); 110 Log2Size = llvm::Log2_32(4); 111 return true; 112 113 // For movw/movt r_type relocations they always have a pair following them and 114 // the r_length bits are used differently. The encoding of the r_length is as 115 // follows: 116 // low bit of r_length: 117 // 0 - :lower16: for movw instructions 118 // 1 - :upper16: for movt instructions 119 // high bit of r_length: 120 // 0 - arm instructions 121 // 1 - thumb instructions 122 case ARM::fixup_arm_movt_hi16: 123 case ARM::fixup_arm_movt_hi16_pcrel: 124 RelocType = unsigned(macho::RIT_ARM_Half); 125 Log2Size = 1; 126 return true; 127 case ARM::fixup_t2_movt_hi16: 128 case ARM::fixup_t2_movt_hi16_pcrel: 129 RelocType = unsigned(macho::RIT_ARM_Half); 130 Log2Size = 3; 131 return true; 132 133 case ARM::fixup_arm_movw_lo16: 134 case ARM::fixup_arm_movw_lo16_pcrel: 135 RelocType = unsigned(macho::RIT_ARM_Half); 136 Log2Size = 0; 137 return true; 138 case ARM::fixup_t2_movw_lo16: 139 case ARM::fixup_t2_movw_lo16_pcrel: 140 RelocType = unsigned(macho::RIT_ARM_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::RIT_ARM_Half; 157 158 // See <reloc.h>. 159 const MCSymbol *A = &Target.getSymA()->getSymbol(); 160 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 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::RIT_ARM_HalfDifference; 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 case ARM::fixup_arm_movt_hi16_pcrel: 207 MovtBit = 1; 208 // The thumb bit shouldn't be set in the 'other-half' bit of the 209 // relocation, but it will be set in FixedValue if the base symbol 210 // is a thumb function. Clear it out here. 211 if (A_SD->getFlags() & SF_ThumbFunc) 212 FixedValue &= 0xfffffffe; 213 break; 214 case ARM::fixup_t2_movt_hi16: 215 case ARM::fixup_t2_movt_hi16_pcrel: 216 if (A_SD->getFlags() & SF_ThumbFunc) 217 FixedValue &= 0xfffffffe; 218 MovtBit = 1; 219 // Fallthrough 220 case ARM::fixup_t2_movw_lo16: 221 case ARM::fixup_t2_movw_lo16_pcrel: 222 ThumbBit = 1; 223 break; 224 } 225 226 if (Type == macho::RIT_ARM_HalfDifference) { 227 uint32_t OtherHalf = MovtBit 228 ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16); 229 230 macho::RelocationEntry MRE; 231 MRE.Word0 = ((OtherHalf << 0) | 232 (macho::RIT_Pair << 24) | 233 (MovtBit << 28) | 234 (ThumbBit << 29) | 235 (IsPCRel << 30) | 236 macho::RF_Scattered); 237 MRE.Word1 = Value2; 238 Writer->addRelocation(Fragment->getParent(), MRE); 239 } 240 241 macho::RelocationEntry MRE; 242 MRE.Word0 = ((FixupOffset << 0) | 243 (Type << 24) | 244 (MovtBit << 28) | 245 (ThumbBit << 29) | 246 (IsPCRel << 30) | 247 macho::RF_Scattered); 248 MRE.Word1 = Value; 249 Writer->addRelocation(Fragment->getParent(), MRE); 250 } 251 252 void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer, 253 const MCAssembler &Asm, 254 const MCAsmLayout &Layout, 255 const MCFragment *Fragment, 256 const MCFixup &Fixup, 257 MCValue Target, 258 unsigned Log2Size, 259 uint64_t &FixedValue) { 260 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 261 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 262 unsigned Type = macho::RIT_Vanilla; 263 264 // See <reloc.h>. 265 const MCSymbol *A = &Target.getSymA()->getSymbol(); 266 MCSymbolData *A_SD = &Asm.getSymbolData(*A); 267 268 if (!A_SD->getFragment()) 269 Asm.getContext().FatalError(Fixup.getLoc(), 270 "symbol '" + A->getName() + 271 "' can not be undefined in a subtraction expression"); 272 273 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout); 274 uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent()); 275 FixedValue += SecAddr; 276 uint32_t Value2 = 0; 277 278 if (const MCSymbolRefExpr *B = Target.getSymB()) { 279 MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); 280 281 if (!B_SD->getFragment()) 282 Asm.getContext().FatalError(Fixup.getLoc(), 283 "symbol '" + B->getSymbol().getName() + 284 "' can not be undefined in a subtraction expression"); 285 286 // Select the appropriate difference relocation type. 287 Type = macho::RIT_Difference; 288 Value2 = Writer->getSymbolAddress(B_SD, Layout); 289 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent()); 290 } 291 292 // Relocations are written out in reverse order, so the PAIR comes first. 293 if (Type == macho::RIT_Difference || 294 Type == macho::RIT_Generic_LocalDifference) { 295 macho::RelocationEntry MRE; 296 MRE.Word0 = ((0 << 0) | 297 (macho::RIT_Pair << 24) | 298 (Log2Size << 28) | 299 (IsPCRel << 30) | 300 macho::RF_Scattered); 301 MRE.Word1 = Value2; 302 Writer->addRelocation(Fragment->getParent(), MRE); 303 } 304 305 macho::RelocationEntry MRE; 306 MRE.Word0 = ((FixupOffset << 0) | 307 (Type << 24) | 308 (Log2Size << 28) | 309 (IsPCRel << 30) | 310 macho::RF_Scattered); 311 MRE.Word1 = Value; 312 Writer->addRelocation(Fragment->getParent(), MRE); 313 } 314 315 bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer, 316 const MCAssembler &Asm, 317 const MCFragment &Fragment, 318 unsigned RelocType, 319 const MCSymbolData *SD, 320 uint64_t FixedValue) { 321 // Most cases can be identified purely from the symbol. 322 if (Writer->doesSymbolRequireExternRelocation(SD)) 323 return true; 324 int64_t Value = (int64_t)FixedValue; // The displacement is signed. 325 int64_t Range; 326 switch (RelocType) { 327 default: 328 return false; 329 case macho::RIT_ARM_Branch24Bit: 330 // PC pre-adjustment of 8 for these instructions. 331 Value -= 8; 332 // ARM BL/BLX has a 25-bit offset. 333 Range = 0x1ffffff; 334 break; 335 case macho::RIT_ARM_ThumbBranch22Bit: 336 // PC pre-adjustment of 4 for these instructions. 337 Value -= 4; 338 // Thumb BL/BLX has a 24-bit offset. 339 Range = 0xffffff; 340 } 341 // BL/BLX also use external relocations when an internal relocation 342 // would result in the target being out of range. This gives the linker 343 // enough information to generate a branch island. 344 const MCSectionData &SymSD = Asm.getSectionData( 345 SD->getSymbol().getSection()); 346 Value += Writer->getSectionAddress(&SymSD); 347 Value -= Writer->getSectionAddress(Fragment.getParent()); 348 // If the resultant value would be out of range for an internal relocation, 349 // use an external instead. 350 if (Value > Range || Value < -(Range + 1)) 351 return true; 352 return false; 353 } 354 355 void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer, 356 const MCAssembler &Asm, 357 const MCAsmLayout &Layout, 358 const MCFragment *Fragment, 359 const MCFixup &Fixup, 360 MCValue Target, 361 uint64_t &FixedValue) { 362 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 363 unsigned Log2Size; 364 unsigned RelocType = macho::RIT_Vanilla; 365 if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) 366 // If we failed to get fixup kind info, it's because there's no legal 367 // relocation type for the fixup kind. This happens when it's a fixup that's 368 // expected to always be resolvable at assembly time and not have any 369 // relocations needed. 370 Asm.getContext().FatalError(Fixup.getLoc(), 371 "unsupported relocation on symbol"); 372 373 // If this is a difference or a defined symbol plus an offset, then we need a 374 // scattered relocation entry. Differences always require scattered 375 // relocations. 376 if (Target.getSymB()) { 377 if (RelocType == macho::RIT_ARM_Half) 378 return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment, 379 Fixup, Target, FixedValue); 380 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 381 Target, Log2Size, FixedValue); 382 } 383 384 // Get the symbol data, if any. 385 MCSymbolData *SD = 0; 386 if (Target.getSymA()) 387 SD = &Asm.getSymbolData(Target.getSymA()->getSymbol()); 388 389 // FIXME: For other platforms, we need to use scattered relocations for 390 // internal relocations with offsets. If this is an internal relocation with 391 // an offset, it also needs a scattered relocation entry. 392 // 393 // Is this right for ARM? 394 uint32_t Offset = Target.getConstant(); 395 if (IsPCRel && RelocType == macho::RIT_Vanilla) 396 Offset += 1 << Log2Size; 397 if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD)) 398 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 399 Target, Log2Size, 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::RelocationEntry MRE; 449 MRE.Word0 = FixupOffset; 450 MRE.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::RIT_ARM_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_arm_movw_lo16_pcrel: 466 case ARM::fixup_t2_movw_lo16: 467 case ARM::fixup_t2_movw_lo16_pcrel: 468 Value = (FixedValue >> 16) & 0xffff; 469 break; 470 case ARM::fixup_arm_movt_hi16: 471 case ARM::fixup_arm_movt_hi16_pcrel: 472 case ARM::fixup_t2_movt_hi16: 473 case ARM::fixup_t2_movt_hi16_pcrel: 474 Value = FixedValue & 0xffff; 475 break; 476 } 477 macho::RelocationEntry MREPair; 478 MREPair.Word0 = Value; 479 MREPair.Word1 = ((0xffffff) | 480 (Log2Size << 25) | 481 (macho::RIT_Pair << 28)); 482 483 Writer->addRelocation(Fragment->getParent(), MREPair); 484 } 485 486 Writer->addRelocation(Fragment->getParent(), MRE); 487 } 488 489 MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS, 490 bool Is64Bit, 491 uint32_t CPUType, 492 uint32_t CPUSubtype) { 493 return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit, 494 CPUType, 495 CPUSubtype), 496 OS, /*IsLittleEndian=*/true); 497 } 498