ARMMachObjectWriter.cpp revision 288943
1139749Simp//===-- ARMMachObjectWriter.cpp - ARM Mach Object Writer ------------------===// 2193640Sariff// 3193640Sariff// The LLVM Compiler Infrastructure 450724Scg// 550724Scg// This file is distributed under the University of Illinois Open Source 650724Scg// License. See LICENSE.TXT for details. 750724Scg// 850724Scg//===----------------------------------------------------------------------===// 950724Scg 1050724Scg#include "MCTargetDesc/ARMMCTargetDesc.h" 1150724Scg#include "MCTargetDesc/ARMBaseInfo.h" 1250724Scg#include "MCTargetDesc/ARMFixupKinds.h" 1350724Scg#include "llvm/ADT/Twine.h" 1450724Scg#include "llvm/MC/MCAsmLayout.h" 1550724Scg#include "llvm/MC/MCAssembler.h" 1650724Scg#include "llvm/MC/MCContext.h" 1750724Scg#include "llvm/MC/MCExpr.h" 1850724Scg#include "llvm/MC/MCFixup.h" 1950724Scg#include "llvm/MC/MCFixupKindInfo.h" 2050724Scg#include "llvm/MC/MCMachObjectWriter.h" 2150724Scg#include "llvm/MC/MCSection.h" 2250724Scg#include "llvm/MC/MCValue.h" 2350724Scg#include "llvm/Support/ErrorHandling.h" 2450724Scg#include "llvm/Support/MachO.h" 2550724Scgusing namespace llvm; 2650724Scg 2750733Speternamespace { 2850724Scgclass ARMMachObjectWriter : public MCMachObjectTargetWriter { 2950724Scg void RecordARMScatteredRelocation(MachObjectWriter *Writer, 30242435Shselasky const MCAssembler &Asm, 31242435Shselasky const MCAsmLayout &Layout, 32242435Shselasky const MCFragment *Fragment, 33170815Sariff const MCFixup &Fixup, 34170815Sariff MCValue Target, 35170815Sariff unsigned Type, 3674763Scg unsigned Log2Size, 3774763Scg uint64_t &FixedValue); 3874763Scg void RecordARMScatteredHalfRelocation(MachObjectWriter *Writer, 39170815Sariff const MCAssembler &Asm, 40162588Snetchild const MCAsmLayout &Layout, 4150724Scg const MCFragment *Fragment, 4270944Sjhb const MCFixup &Fixup, MCValue Target, 43246454Shselasky uint64_t &FixedValue); 4470944Sjhb 45246454Shselasky bool requiresExternRelocation(MachObjectWriter *Writer, 4670944Sjhb const MCAssembler &Asm, 4770618Sjhb const MCFragment &Fragment, unsigned RelocType, 48170815Sariff const MCSymbol &S, uint64_t FixedValue); 49170815Sariff 50246421Shselaskypublic: 51246421Shselasky ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype) 52170815Sariff : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {} 53170815Sariff 54170815Sariff void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm, 55170815Sariff const MCAsmLayout &Layout, const MCFragment *Fragment, 56170815Sariff const MCFixup &Fixup, MCValue Target, 57170815Sariff uint64_t &FixedValue) override; 5874763Scg}; 5974763Scg} 6074763Scg 6174763Scgstatic bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType, 62162738Sariff unsigned &Log2Size) { 63162738Sariff RelocType = unsigned(MachO::ARM_RELOC_VANILLA); 64162738Sariff Log2Size = ~0U; 65162738Sariff 6674763Scg switch (Kind) { 67184610Salfred default: 6850724Scg return false; 69162588Snetchild 70162588Snetchild case FK_Data_1: 71170815Sariff Log2Size = llvm::Log2_32(1); 72170815Sariff return true; 73170815Sariff case FK_Data_2: 74170815Sariff Log2Size = llvm::Log2_32(2); 75170815Sariff return true; 76170815Sariff case FK_Data_4: 7774763Scg Log2Size = llvm::Log2_32(4); 7874763Scg return true; 7974763Scg case FK_Data_8: 8074763Scg Log2Size = llvm::Log2_32(8); 81170815Sariff return true; 82170815Sariff 8370134Scg // These fixups are expected to always be resolvable at assembly time and 84160385Snetchild // have no relocations supported. 85242435Shselasky case ARM::fixup_arm_ldst_pcrel_12: 86242435Shselasky case ARM::fixup_arm_pcrel_10: 87 case ARM::fixup_arm_adr_pcrel_12: 88 case ARM::fixup_arm_thumb_br: 89 return false; 90 91 // Handle 24-bit branch kinds. 92 case ARM::fixup_arm_condbranch: 93 case ARM::fixup_arm_uncondbranch: 94 case ARM::fixup_arm_uncondbl: 95 case ARM::fixup_arm_condbl: 96 case ARM::fixup_arm_blx: 97 RelocType = unsigned(MachO::ARM_RELOC_BR24); 98 // Report as 'long', even though that is not quite accurate. 99 Log2Size = llvm::Log2_32(4); 100 return true; 101 102 case ARM::fixup_t2_uncondbranch: 103 case ARM::fixup_arm_thumb_bl: 104 case ARM::fixup_arm_thumb_blx: 105 RelocType = unsigned(MachO::ARM_THUMB_RELOC_BR22); 106 Log2Size = llvm::Log2_32(4); 107 return true; 108 109 // For movw/movt r_type relocations they always have a pair following them and 110 // the r_length bits are used differently. The encoding of the r_length is as 111 // follows: 112 // low bit of r_length: 113 // 0 - :lower16: for movw instructions 114 // 1 - :upper16: for movt instructions 115 // high bit of r_length: 116 // 0 - arm instructions 117 // 1 - thumb instructions 118 case ARM::fixup_arm_movt_hi16: 119 RelocType = unsigned(MachO::ARM_RELOC_HALF); 120 Log2Size = 1; 121 return true; 122 case ARM::fixup_t2_movt_hi16: 123 RelocType = unsigned(MachO::ARM_RELOC_HALF); 124 Log2Size = 3; 125 return true; 126 127 case ARM::fixup_arm_movw_lo16: 128 RelocType = unsigned(MachO::ARM_RELOC_HALF); 129 Log2Size = 0; 130 return true; 131 case ARM::fixup_t2_movw_lo16: 132 RelocType = unsigned(MachO::ARM_RELOC_HALF); 133 Log2Size = 2; 134 return true; 135 } 136} 137 138void ARMMachObjectWriter:: 139RecordARMScatteredHalfRelocation(MachObjectWriter *Writer, 140 const MCAssembler &Asm, 141 const MCAsmLayout &Layout, 142 const MCFragment *Fragment, 143 const MCFixup &Fixup, 144 MCValue Target, 145 uint64_t &FixedValue) { 146 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 147 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 148 unsigned Type = MachO::ARM_RELOC_HALF; 149 150 // See <reloc.h>. 151 const MCSymbol *A = &Target.getSymA()->getSymbol(); 152 153 if (!A->getFragment()) 154 Asm.getContext().reportFatalError(Fixup.getLoc(), 155 "symbol '" + A->getName() + 156 "' can not be undefined in a subtraction expression"); 157 158 uint32_t Value = Writer->getSymbolAddress(*A, Layout); 159 uint32_t Value2 = 0; 160 uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent()); 161 FixedValue += SecAddr; 162 163 if (const MCSymbolRefExpr *B = Target.getSymB()) { 164 const MCSymbol *SB = &B->getSymbol(); 165 166 if (!SB->getFragment()) 167 Asm.getContext().reportFatalError(Fixup.getLoc(), 168 "symbol '" + B->getSymbol().getName() + 169 "' can not be undefined in a subtraction expression"); 170 171 // Select the appropriate difference relocation type. 172 Type = MachO::ARM_RELOC_HALF_SECTDIFF; 173 Value2 = Writer->getSymbolAddress(B->getSymbol(), Layout); 174 FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent()); 175 } 176 177 // Relocations are written out in reverse order, so the PAIR comes first. 178 // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field: 179 // 180 // For these two r_type relocations they always have a pair following them and 181 // the r_length bits are used differently. The encoding of the r_length is as 182 // follows: 183 // low bit of r_length: 184 // 0 - :lower16: for movw instructions 185 // 1 - :upper16: for movt instructions 186 // high bit of r_length: 187 // 0 - arm instructions 188 // 1 - thumb instructions 189 // the other half of the relocated expression is in the following pair 190 // relocation entry in the low 16 bits of r_address field. 191 unsigned ThumbBit = 0; 192 unsigned MovtBit = 0; 193 switch ((unsigned)Fixup.getKind()) { 194 default: break; 195 case ARM::fixup_arm_movt_hi16: 196 MovtBit = 1; 197 // The thumb bit shouldn't be set in the 'other-half' bit of the 198 // relocation, but it will be set in FixedValue if the base symbol 199 // is a thumb function. Clear it out here. 200 if (Asm.isThumbFunc(A)) 201 FixedValue &= 0xfffffffe; 202 break; 203 case ARM::fixup_t2_movt_hi16: 204 if (Asm.isThumbFunc(A)) 205 FixedValue &= 0xfffffffe; 206 MovtBit = 1; 207 // Fallthrough 208 case ARM::fixup_t2_movw_lo16: 209 ThumbBit = 1; 210 break; 211 } 212 213 if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) { 214 uint32_t OtherHalf = MovtBit 215 ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16); 216 217 MachO::any_relocation_info MRE; 218 MRE.r_word0 = ((OtherHalf << 0) | 219 (MachO::ARM_RELOC_PAIR << 24) | 220 (MovtBit << 28) | 221 (ThumbBit << 29) | 222 (IsPCRel << 30) | 223 MachO::R_SCATTERED); 224 MRE.r_word1 = Value2; 225 Writer->addRelocation(nullptr, Fragment->getParent(), MRE); 226 } 227 228 MachO::any_relocation_info MRE; 229 MRE.r_word0 = ((FixupOffset << 0) | 230 (Type << 24) | 231 (MovtBit << 28) | 232 (ThumbBit << 29) | 233 (IsPCRel << 30) | 234 MachO::R_SCATTERED); 235 MRE.r_word1 = Value; 236 Writer->addRelocation(nullptr, Fragment->getParent(), MRE); 237} 238 239void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer, 240 const MCAssembler &Asm, 241 const MCAsmLayout &Layout, 242 const MCFragment *Fragment, 243 const MCFixup &Fixup, 244 MCValue Target, 245 unsigned Type, 246 unsigned Log2Size, 247 uint64_t &FixedValue) { 248 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 249 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 250 251 // See <reloc.h>. 252 const MCSymbol *A = &Target.getSymA()->getSymbol(); 253 254 if (!A->getFragment()) 255 Asm.getContext().reportFatalError(Fixup.getLoc(), 256 "symbol '" + A->getName() + 257 "' can not be undefined in a subtraction expression"); 258 259 uint32_t Value = Writer->getSymbolAddress(*A, Layout); 260 uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent()); 261 FixedValue += SecAddr; 262 uint32_t Value2 = 0; 263 264 if (const MCSymbolRefExpr *B = Target.getSymB()) { 265 assert(Type == MachO::ARM_RELOC_VANILLA && "invalid reloc for 2 symbols"); 266 const MCSymbol *SB = &B->getSymbol(); 267 268 if (!SB->getFragment()) 269 Asm.getContext().reportFatalError(Fixup.getLoc(), 270 "symbol '" + B->getSymbol().getName() + 271 "' can not be undefined in a subtraction expression"); 272 273 // Select the appropriate difference relocation type. 274 Type = MachO::ARM_RELOC_SECTDIFF; 275 Value2 = Writer->getSymbolAddress(B->getSymbol(), Layout); 276 FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent()); 277 } 278 279 // Relocations are written out in reverse order, so the PAIR comes first. 280 if (Type == MachO::ARM_RELOC_SECTDIFF || 281 Type == MachO::ARM_RELOC_LOCAL_SECTDIFF) { 282 MachO::any_relocation_info MRE; 283 MRE.r_word0 = ((0 << 0) | 284 (MachO::ARM_RELOC_PAIR << 24) | 285 (Log2Size << 28) | 286 (IsPCRel << 30) | 287 MachO::R_SCATTERED); 288 MRE.r_word1 = Value2; 289 Writer->addRelocation(nullptr, Fragment->getParent(), MRE); 290 } 291 292 MachO::any_relocation_info MRE; 293 MRE.r_word0 = ((FixupOffset << 0) | 294 (Type << 24) | 295 (Log2Size << 28) | 296 (IsPCRel << 30) | 297 MachO::R_SCATTERED); 298 MRE.r_word1 = Value; 299 Writer->addRelocation(nullptr, Fragment->getParent(), MRE); 300} 301 302bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer, 303 const MCAssembler &Asm, 304 const MCFragment &Fragment, 305 unsigned RelocType, 306 const MCSymbol &S, 307 uint64_t FixedValue) { 308 // Most cases can be identified purely from the symbol. 309 if (Writer->doesSymbolRequireExternRelocation(S)) 310 return true; 311 int64_t Value = (int64_t)FixedValue; // The displacement is signed. 312 int64_t Range; 313 switch (RelocType) { 314 default: 315 return false; 316 case MachO::ARM_RELOC_BR24: 317 // PC pre-adjustment of 8 for these instructions. 318 Value -= 8; 319 // ARM BL/BLX has a 25-bit offset. 320 Range = 0x1ffffff; 321 break; 322 case MachO::ARM_THUMB_RELOC_BR22: 323 // PC pre-adjustment of 4 for these instructions. 324 Value -= 4; 325 // Thumb BL/BLX has a 24-bit offset. 326 Range = 0xffffff; 327 } 328 // BL/BLX also use external relocations when an internal relocation 329 // would result in the target being out of range. This gives the linker 330 // enough information to generate a branch island. 331 Value += Writer->getSectionAddress(&S.getSection()); 332 Value -= Writer->getSectionAddress(Fragment.getParent()); 333 // If the resultant value would be out of range for an internal relocation, 334 // use an external instead. 335 if (Value > Range || Value < -(Range + 1)) 336 return true; 337 return false; 338} 339 340void ARMMachObjectWriter::recordRelocation(MachObjectWriter *Writer, 341 MCAssembler &Asm, 342 const MCAsmLayout &Layout, 343 const MCFragment *Fragment, 344 const MCFixup &Fixup, MCValue Target, 345 uint64_t &FixedValue) { 346 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 347 unsigned Log2Size; 348 unsigned RelocType = MachO::ARM_RELOC_VANILLA; 349 if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) 350 // If we failed to get fixup kind info, it's because there's no legal 351 // relocation type for the fixup kind. This happens when it's a fixup that's 352 // expected to always be resolvable at assembly time and not have any 353 // relocations needed. 354 Asm.getContext().reportFatalError(Fixup.getLoc(), 355 "unsupported relocation on symbol"); 356 357 // If this is a difference or a defined symbol plus an offset, then we need a 358 // scattered relocation entry. Differences always require scattered 359 // relocations. 360 if (Target.getSymB()) { 361 if (RelocType == MachO::ARM_RELOC_HALF) 362 return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment, 363 Fixup, Target, FixedValue); 364 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 365 Target, RelocType, Log2Size, 366 FixedValue); 367 } 368 369 // Get the symbol data, if any. 370 const MCSymbol *A = nullptr; 371 if (Target.getSymA()) 372 A = &Target.getSymA()->getSymbol(); 373 374 // FIXME: For other platforms, we need to use scattered relocations for 375 // internal relocations with offsets. If this is an internal relocation with 376 // an offset, it also needs a scattered relocation entry. 377 // 378 // Is this right for ARM? 379 uint32_t Offset = Target.getConstant(); 380 if (IsPCRel && RelocType == MachO::ARM_RELOC_VANILLA) 381 Offset += 1 << Log2Size; 382 if (Offset && A && !Writer->doesSymbolRequireExternRelocation(*A)) 383 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 384 Target, RelocType, Log2Size, 385 FixedValue); 386 387 // See <reloc.h>. 388 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 389 unsigned Index = 0; 390 unsigned Type = 0; 391 const MCSymbol *RelSymbol = nullptr; 392 393 if (Target.isAbsolute()) { // constant 394 // FIXME! 395 report_fatal_error("FIXME: relocations to absolute targets " 396 "not yet implemented"); 397 } else { 398 // Resolve constant variables. 399 if (A->isVariable()) { 400 int64_t Res; 401 if (A->getVariableValue()->evaluateAsAbsolute( 402 Res, Layout, Writer->getSectionAddressMap())) { 403 FixedValue = Res; 404 return; 405 } 406 } 407 408 // Check whether we need an external or internal relocation. 409 if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, *A, 410 FixedValue)) { 411 RelSymbol = A; 412 413 // For external relocations, make sure to offset the fixup value to 414 // compensate for the addend of the symbol address, if it was 415 // undefined. This occurs with weak definitions, for example. 416 if (!A->isUndefined()) 417 FixedValue -= Layout.getSymbolOffset(*A); 418 } else { 419 // The index is the section ordinal (1-based). 420 const MCSection &Sec = A->getSection(); 421 Index = Sec.getOrdinal() + 1; 422 FixedValue += Writer->getSectionAddress(&Sec); 423 } 424 if (IsPCRel) 425 FixedValue -= Writer->getSectionAddress(Fragment->getParent()); 426 427 // The type is determined by the fixup kind. 428 Type = RelocType; 429 } 430 431 // struct relocation_info (8 bytes) 432 MachO::any_relocation_info MRE; 433 MRE.r_word0 = FixupOffset; 434 MRE.r_word1 = 435 (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); 436 437 // Even when it's not a scattered relocation, movw/movt always uses 438 // a PAIR relocation. 439 if (Type == MachO::ARM_RELOC_HALF) { 440 // The other-half value only gets populated for the movt and movw 441 // relocation entries. 442 uint32_t Value = 0; 443 switch ((unsigned)Fixup.getKind()) { 444 default: break; 445 case ARM::fixup_arm_movw_lo16: 446 case ARM::fixup_t2_movw_lo16: 447 Value = (FixedValue >> 16) & 0xffff; 448 break; 449 case ARM::fixup_arm_movt_hi16: 450 case ARM::fixup_t2_movt_hi16: 451 Value = FixedValue & 0xffff; 452 break; 453 } 454 MachO::any_relocation_info MREPair; 455 MREPair.r_word0 = Value; 456 MREPair.r_word1 = ((0xffffff << 0) | 457 (Log2Size << 25) | 458 (MachO::ARM_RELOC_PAIR << 28)); 459 460 Writer->addRelocation(nullptr, Fragment->getParent(), MREPair); 461 } 462 463 Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); 464} 465 466MCObjectWriter *llvm::createARMMachObjectWriter(raw_pwrite_stream &OS, 467 bool Is64Bit, uint32_t CPUType, 468 uint32_t CPUSubtype) { 469 return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit, 470 CPUType, 471 CPUSubtype), 472 OS, /*IsLittleEndian=*/true); 473} 474