ARMMachObjectWriter.cpp revision 9c3dd1b0d1e96ef408b68da3b06c6ebd6c943601
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 MachO::scattered_relocation_info MRE; 226 if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) { 227 uint32_t OtherHalf = MovtBit 228 ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16); 229 230 MRE.r_address = OtherHalf; 231 MRE.r_type = MachO::ARM_RELOC_PAIR; 232 MRE.r_length = ((MovtBit << 0) | 233 (ThumbBit << 1)); 234 MRE.r_pcrel = IsPCRel; 235 MRE.r_scattered = 1; 236 MRE.r_value = Value2; 237 Writer->addRelocation(Fragment->getParent(), MRE); 238 } 239 240 MRE.r_address = FixupOffset; 241 MRE.r_type = Type; 242 MRE.r_length = ((MovtBit << 0) | 243 (ThumbBit << 1)); 244 MRE.r_pcrel = IsPCRel; 245 MRE.r_scattered = 1; 246 MRE.r_value = Value; 247 Writer->addRelocation(Fragment->getParent(), MRE); 248} 249 250void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer, 251 const MCAssembler &Asm, 252 const MCAsmLayout &Layout, 253 const MCFragment *Fragment, 254 const MCFixup &Fixup, 255 MCValue Target, 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 unsigned Type = MachO::ARM_RELOC_VANILLA; 261 262 // See <reloc.h>. 263 const MCSymbol *A = &Target.getSymA()->getSymbol(); 264 MCSymbolData *A_SD = &Asm.getSymbolData(*A); 265 266 if (!A_SD->getFragment()) 267 Asm.getContext().FatalError(Fixup.getLoc(), 268 "symbol '" + A->getName() + 269 "' can not be undefined in a subtraction expression"); 270 271 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout); 272 uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent()); 273 FixedValue += SecAddr; 274 uint32_t Value2 = 0; 275 276 if (const MCSymbolRefExpr *B = Target.getSymB()) { 277 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 MachO::scattered_relocation_info MRE; 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 MRE.r_address = 0; 295 MRE.r_type = MachO::ARM_RELOC_PAIR; 296 MRE.r_length = Log2Size; 297 MRE.r_pcrel = IsPCRel; 298 MRE.r_scattered = 1; 299 MRE.r_value = Value2; 300 Writer->addRelocation(Fragment->getParent(), MRE); 301 } 302 303 MRE.r_address = FixupOffset; 304 MRE.r_type = Type; 305 MRE.r_length = Log2Size; 306 MRE.r_pcrel = IsPCRel; 307 MRE.r_scattered = 1; 308 MRE.r_value = Value; 309 Writer->addRelocation(Fragment->getParent(), MRE); 310} 311 312bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer, 313 const MCAssembler &Asm, 314 const MCFragment &Fragment, 315 unsigned RelocType, 316 const MCSymbolData *SD, 317 uint64_t FixedValue) { 318 // Most cases can be identified purely from the symbol. 319 if (Writer->doesSymbolRequireExternRelocation(SD)) 320 return true; 321 int64_t Value = (int64_t)FixedValue; // The displacement is signed. 322 int64_t Range; 323 switch (RelocType) { 324 default: 325 return false; 326 case MachO::ARM_RELOC_BR24: 327 // PC pre-adjustment of 8 for these instructions. 328 Value -= 8; 329 // ARM BL/BLX has a 25-bit offset. 330 Range = 0x1ffffff; 331 break; 332 case MachO::ARM_THUMB_RELOC_BR22: 333 // PC pre-adjustment of 4 for these instructions. 334 Value -= 4; 335 // Thumb BL/BLX has a 24-bit offset. 336 Range = 0xffffff; 337 } 338 // BL/BLX also use external relocations when an internal relocation 339 // would result in the target being out of range. This gives the linker 340 // enough information to generate a branch island. 341 const MCSectionData &SymSD = Asm.getSectionData( 342 SD->getSymbol().getSection()); 343 Value += Writer->getSectionAddress(&SymSD); 344 Value -= Writer->getSectionAddress(Fragment.getParent()); 345 // If the resultant value would be out of range for an internal relocation, 346 // use an external instead. 347 if (Value > Range || Value < -(Range + 1)) 348 return true; 349 return false; 350} 351 352void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer, 353 const MCAssembler &Asm, 354 const MCAsmLayout &Layout, 355 const MCFragment *Fragment, 356 const MCFixup &Fixup, 357 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, Log2Size, FixedValue); 379 } 380 381 // Get the symbol data, if any. 382 MCSymbolData *SD = 0; 383 if (Target.getSymA()) 384 SD = &Asm.getSymbolData(Target.getSymA()->getSymbol()); 385 386 // FIXME: For other platforms, we need to use scattered relocations for 387 // internal relocations with offsets. If this is an internal relocation with 388 // an offset, it also needs a scattered relocation entry. 389 // 390 // Is this right for ARM? 391 uint32_t Offset = Target.getConstant(); 392 if (IsPCRel && RelocType == MachO::ARM_RELOC_VANILLA) 393 Offset += 1 << Log2Size; 394 if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD)) 395 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 396 Target, Log2Size, FixedValue); 397 398 // See <reloc.h>. 399 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 400 unsigned Index = 0; 401 unsigned IsExtern = 0; 402 unsigned Type = 0; 403 404 if (Target.isAbsolute()) { // constant 405 // FIXME! 406 report_fatal_error("FIXME: relocations to absolute targets " 407 "not yet implemented"); 408 } else { 409 // Resolve constant variables. 410 if (SD->getSymbol().isVariable()) { 411 int64_t Res; 412 if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( 413 Res, Layout, Writer->getSectionAddressMap())) { 414 FixedValue = Res; 415 return; 416 } 417 } 418 419 // Check whether we need an external or internal relocation. 420 if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, SD, 421 FixedValue)) { 422 IsExtern = 1; 423 Index = SD->getIndex(); 424 425 // For external relocations, make sure to offset the fixup value to 426 // compensate for the addend of the symbol address, if it was 427 // undefined. This occurs with weak definitions, for example. 428 if (!SD->Symbol->isUndefined()) 429 FixedValue -= Layout.getSymbolOffset(SD); 430 } else { 431 // The index is the section ordinal (1-based). 432 const MCSectionData &SymSD = Asm.getSectionData( 433 SD->getSymbol().getSection()); 434 Index = SymSD.getOrdinal() + 1; 435 FixedValue += Writer->getSectionAddress(&SymSD); 436 } 437 if (IsPCRel) 438 FixedValue -= Writer->getSectionAddress(Fragment->getParent()); 439 440 // The type is determined by the fixup kind. 441 Type = RelocType; 442 } 443 444 // struct relocation_info (8 bytes) 445 MachO::relocation_info MRE; 446 MRE.r_address = FixupOffset; 447 MRE.r_symbolnum = Index; 448 MRE.r_pcrel = IsPCRel; 449 MRE.r_length = Log2Size; 450 MRE.r_extern = IsExtern; 451 MRE.r_type = Type; 452 453 // Even when it's not a scattered relocation, movw/movt always uses 454 // a PAIR relocation. 455 if (Type == MachO::ARM_RELOC_HALF) { 456 // The other-half value only gets populated for the movt and movw 457 // relocation entries. 458 uint32_t Value = 0; 459 switch ((unsigned)Fixup.getKind()) { 460 default: break; 461 case ARM::fixup_arm_movw_lo16: 462 case ARM::fixup_arm_movw_lo16_pcrel: 463 case ARM::fixup_t2_movw_lo16: 464 case ARM::fixup_t2_movw_lo16_pcrel: 465 Value = (FixedValue >> 16) & 0xffff; 466 break; 467 case ARM::fixup_arm_movt_hi16: 468 case ARM::fixup_arm_movt_hi16_pcrel: 469 case ARM::fixup_t2_movt_hi16: 470 case ARM::fixup_t2_movt_hi16_pcrel: 471 Value = FixedValue & 0xffff; 472 break; 473 } 474 MachO::relocation_info MREPair; 475 MREPair.r_address = Value; 476 MREPair.r_symbolnum = 0xffffff; 477 MREPair.r_length = Log2Size; 478 MREPair.r_pcrel = MREPair.r_extern = 0; 479 MREPair.r_type = MachO::ARM_RELOC_PAIR; 480 481 Writer->addRelocation(Fragment->getParent(), MREPair); 482 } 483 484 Writer->addRelocation(Fragment->getParent(), MRE); 485} 486 487MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS, 488 bool Is64Bit, 489 uint32_t CPUType, 490 uint32_t CPUSubtype) { 491 return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit, 492 CPUType, 493 CPUSubtype), 494 OS, /*IsLittleEndian=*/true); 495} 496