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