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/ARMBaseInfo.h" 11#include "MCTargetDesc/ARMFixupKinds.h" 12#include "llvm/ADT/Twine.h" 13#include "llvm/MC/MCAssembler.h" 14#include "llvm/MC/MCAsmLayout.h" 15#include "llvm/MC/MCMachObjectWriter.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/MCValue.h" 22#include "llvm/Object/MachOFormat.h" 23#include "llvm/Support/ErrorHandling.h" 24using namespace llvm; 25using namespace llvm::object; 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 44public: 45 ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType, 46 uint32_t CPUSubtype) 47 : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype, 48 /*UseAggressiveSymbolFolding=*/true) {} 49 50 void RecordRelocation(MachObjectWriter *Writer, 51 const MCAssembler &Asm, const MCAsmLayout &Layout, 52 const MCFragment *Fragment, const MCFixup &Fixup, 53 MCValue Target, uint64_t &FixedValue); 54}; 55} 56 57static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType, 58 unsigned &Log2Size) { 59 RelocType = unsigned(macho::RIT_Vanilla); 60 Log2Size = ~0U; 61 62 switch (Kind) { 63 default: 64 return false; 65 66 case FK_Data_1: 67 Log2Size = llvm::Log2_32(1); 68 return true; 69 case FK_Data_2: 70 Log2Size = llvm::Log2_32(2); 71 return true; 72 case FK_Data_4: 73 Log2Size = llvm::Log2_32(4); 74 return true; 75 case FK_Data_8: 76 Log2Size = llvm::Log2_32(8); 77 return true; 78 79 // Handle 24-bit branch kinds. 80 case ARM::fixup_arm_ldst_pcrel_12: 81 case ARM::fixup_arm_pcrel_10: 82 case ARM::fixup_arm_adr_pcrel_12: 83 case ARM::fixup_arm_condbranch: 84 case ARM::fixup_arm_uncondbranch: 85 case ARM::fixup_arm_uncondbl: 86 case ARM::fixup_arm_condbl: 87 case ARM::fixup_arm_blx: 88 RelocType = unsigned(macho::RIT_ARM_Branch24Bit); 89 // Report as 'long', even though that is not quite accurate. 90 Log2Size = llvm::Log2_32(4); 91 return true; 92 93 // Handle Thumb branches. 94 case ARM::fixup_arm_thumb_br: 95 RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit); 96 Log2Size = llvm::Log2_32(2); 97 return true; 98 99 case ARM::fixup_t2_uncondbranch: 100 case ARM::fixup_arm_thumb_bl: 101 case ARM::fixup_arm_thumb_blx: 102 RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit); 103 Log2Size = llvm::Log2_32(4); 104 return true; 105 106 // For movw/movt r_type relocations they always have a pair following them and 107 // the r_length bits are used differently. The encoding of the r_length is as 108 // follows: 109 // low bit of r_length: 110 // 0 - :lower16: for movw instructions 111 // 1 - :upper16: for movt instructions 112 // high bit of r_length: 113 // 0 - arm instructions 114 // 1 - thumb instructions 115 case ARM::fixup_arm_movt_hi16: 116 case ARM::fixup_arm_movt_hi16_pcrel: 117 RelocType = unsigned(macho::RIT_ARM_Half); 118 Log2Size = 1; 119 return true; 120 case ARM::fixup_t2_movt_hi16: 121 case ARM::fixup_t2_movt_hi16_pcrel: 122 RelocType = unsigned(macho::RIT_ARM_Half); 123 Log2Size = 3; 124 return true; 125 126 case ARM::fixup_arm_movw_lo16: 127 case ARM::fixup_arm_movw_lo16_pcrel: 128 RelocType = unsigned(macho::RIT_ARM_Half); 129 Log2Size = 0; 130 return true; 131 case ARM::fixup_t2_movw_lo16: 132 case ARM::fixup_t2_movw_lo16_pcrel: 133 RelocType = unsigned(macho::RIT_ARM_Half); 134 Log2Size = 2; 135 return true; 136 } 137} 138 139void ARMMachObjectWriter:: 140RecordARMScatteredHalfRelocation(MachObjectWriter *Writer, 141 const MCAssembler &Asm, 142 const MCAsmLayout &Layout, 143 const MCFragment *Fragment, 144 const MCFixup &Fixup, 145 MCValue Target, 146 uint64_t &FixedValue) { 147 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 148 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 149 unsigned Type = macho::RIT_ARM_Half; 150 151 // See <reloc.h>. 152 const MCSymbol *A = &Target.getSymA()->getSymbol(); 153 MCSymbolData *A_SD = &Asm.getSymbolData(*A); 154 155 if (!A_SD->getFragment()) 156 Asm.getContext().FatalError(Fixup.getLoc(), 157 "symbol '" + A->getName() + 158 "' can not be undefined in a subtraction expression"); 159 160 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout); 161 uint32_t Value2 = 0; 162 uint64_t SecAddr = 163 Writer->getSectionAddress(A_SD->getFragment()->getParent()); 164 FixedValue += SecAddr; 165 166 if (const MCSymbolRefExpr *B = Target.getSymB()) { 167 MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); 168 169 if (!B_SD->getFragment()) 170 Asm.getContext().FatalError(Fixup.getLoc(), 171 "symbol '" + B->getSymbol().getName() + 172 "' can not be undefined in a subtraction expression"); 173 174 // Select the appropriate difference relocation type. 175 Type = macho::RIT_ARM_HalfDifference; 176 Value2 = Writer->getSymbolAddress(B_SD, Layout); 177 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent()); 178 } 179 180 // Relocations are written out in reverse order, so the PAIR comes first. 181 // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field: 182 // 183 // For these two r_type relocations they always have a pair following them and 184 // the r_length bits are used differently. The encoding of the r_length is as 185 // follows: 186 // low bit of r_length: 187 // 0 - :lower16: for movw instructions 188 // 1 - :upper16: for movt instructions 189 // high bit of r_length: 190 // 0 - arm instructions 191 // 1 - thumb instructions 192 // the other half of the relocated expression is in the following pair 193 // relocation entry in the low 16 bits of r_address field. 194 unsigned ThumbBit = 0; 195 unsigned MovtBit = 0; 196 switch ((unsigned)Fixup.getKind()) { 197 default: break; 198 case ARM::fixup_arm_movt_hi16: 199 case ARM::fixup_arm_movt_hi16_pcrel: 200 MovtBit = 1; 201 // The thumb bit shouldn't be set in the 'other-half' bit of the 202 // relocation, but it will be set in FixedValue if the base symbol 203 // is a thumb function. Clear it out here. 204 if (A_SD->getFlags() & SF_ThumbFunc) 205 FixedValue &= 0xfffffffe; 206 break; 207 case ARM::fixup_t2_movt_hi16: 208 case ARM::fixup_t2_movt_hi16_pcrel: 209 if (A_SD->getFlags() & SF_ThumbFunc) 210 FixedValue &= 0xfffffffe; 211 MovtBit = 1; 212 // Fallthrough 213 case ARM::fixup_t2_movw_lo16: 214 case ARM::fixup_t2_movw_lo16_pcrel: 215 ThumbBit = 1; 216 break; 217 } 218 219 if (Type == macho::RIT_ARM_HalfDifference) { 220 uint32_t OtherHalf = MovtBit 221 ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16); 222 223 macho::RelocationEntry MRE; 224 MRE.Word0 = ((OtherHalf << 0) | 225 (macho::RIT_Pair << 24) | 226 (MovtBit << 28) | 227 (ThumbBit << 29) | 228 (IsPCRel << 30) | 229 macho::RF_Scattered); 230 MRE.Word1 = Value2; 231 Writer->addRelocation(Fragment->getParent(), MRE); 232 } 233 234 macho::RelocationEntry MRE; 235 MRE.Word0 = ((FixupOffset << 0) | 236 (Type << 24) | 237 (MovtBit << 28) | 238 (ThumbBit << 29) | 239 (IsPCRel << 30) | 240 macho::RF_Scattered); 241 MRE.Word1 = Value; 242 Writer->addRelocation(Fragment->getParent(), MRE); 243} 244 245void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer, 246 const MCAssembler &Asm, 247 const MCAsmLayout &Layout, 248 const MCFragment *Fragment, 249 const MCFixup &Fixup, 250 MCValue Target, 251 unsigned Log2Size, 252 uint64_t &FixedValue) { 253 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 254 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 255 unsigned Type = macho::RIT_Vanilla; 256 257 // See <reloc.h>. 258 const MCSymbol *A = &Target.getSymA()->getSymbol(); 259 MCSymbolData *A_SD = &Asm.getSymbolData(*A); 260 261 if (!A_SD->getFragment()) 262 Asm.getContext().FatalError(Fixup.getLoc(), 263 "symbol '" + A->getName() + 264 "' can not be undefined in a subtraction expression"); 265 266 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout); 267 uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent()); 268 FixedValue += SecAddr; 269 uint32_t Value2 = 0; 270 271 if (const MCSymbolRefExpr *B = Target.getSymB()) { 272 MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); 273 274 if (!B_SD->getFragment()) 275 Asm.getContext().FatalError(Fixup.getLoc(), 276 "symbol '" + B->getSymbol().getName() + 277 "' can not be undefined in a subtraction expression"); 278 279 // Select the appropriate difference relocation type. 280 Type = macho::RIT_Difference; 281 Value2 = Writer->getSymbolAddress(B_SD, Layout); 282 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent()); 283 } 284 285 // Relocations are written out in reverse order, so the PAIR comes first. 286 if (Type == macho::RIT_Difference || 287 Type == macho::RIT_Generic_LocalDifference) { 288 macho::RelocationEntry MRE; 289 MRE.Word0 = ((0 << 0) | 290 (macho::RIT_Pair << 24) | 291 (Log2Size << 28) | 292 (IsPCRel << 30) | 293 macho::RF_Scattered); 294 MRE.Word1 = Value2; 295 Writer->addRelocation(Fragment->getParent(), MRE); 296 } 297 298 macho::RelocationEntry MRE; 299 MRE.Word0 = ((FixupOffset << 0) | 300 (Type << 24) | 301 (Log2Size << 28) | 302 (IsPCRel << 30) | 303 macho::RF_Scattered); 304 MRE.Word1 = Value; 305 Writer->addRelocation(Fragment->getParent(), MRE); 306} 307 308void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer, 309 const MCAssembler &Asm, 310 const MCAsmLayout &Layout, 311 const MCFragment *Fragment, 312 const MCFixup &Fixup, 313 MCValue Target, 314 uint64_t &FixedValue) { 315 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 316 unsigned Log2Size; 317 unsigned RelocType = macho::RIT_Vanilla; 318 if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) 319 // If we failed to get fixup kind info, it's because there's no legal 320 // relocation type for the fixup kind. This happens when it's a fixup that's 321 // expected to always be resolvable at assembly time and not have any 322 // relocations needed. 323 Asm.getContext().FatalError(Fixup.getLoc(), 324 "unsupported relocation on symbol"); 325 326 // If this is a difference or a defined symbol plus an offset, then we need a 327 // scattered relocation entry. Differences always require scattered 328 // relocations. 329 if (Target.getSymB()) { 330 if (RelocType == macho::RIT_ARM_Half) 331 return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment, 332 Fixup, Target, FixedValue); 333 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 334 Target, Log2Size, FixedValue); 335 } 336 337 // Get the symbol data, if any. 338 MCSymbolData *SD = 0; 339 if (Target.getSymA()) 340 SD = &Asm.getSymbolData(Target.getSymA()->getSymbol()); 341 342 // FIXME: For other platforms, we need to use scattered relocations for 343 // internal relocations with offsets. If this is an internal relocation with 344 // an offset, it also needs a scattered relocation entry. 345 // 346 // Is this right for ARM? 347 uint32_t Offset = Target.getConstant(); 348 if (IsPCRel && RelocType == macho::RIT_Vanilla) 349 Offset += 1 << Log2Size; 350 if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD)) 351 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 352 Target, Log2Size, FixedValue); 353 354 // See <reloc.h>. 355 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 356 unsigned Index = 0; 357 unsigned IsExtern = 0; 358 unsigned Type = 0; 359 360 if (Target.isAbsolute()) { // constant 361 // FIXME! 362 report_fatal_error("FIXME: relocations to absolute targets " 363 "not yet implemented"); 364 } else { 365 // Resolve constant variables. 366 if (SD->getSymbol().isVariable()) { 367 int64_t Res; 368 if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( 369 Res, Layout, Writer->getSectionAddressMap())) { 370 FixedValue = Res; 371 return; 372 } 373 } 374 375 // Check whether we need an external or internal relocation. 376 if (Writer->doesSymbolRequireExternRelocation(SD)) { 377 IsExtern = 1; 378 Index = SD->getIndex(); 379 380 // For external relocations, make sure to offset the fixup value to 381 // compensate for the addend of the symbol address, if it was 382 // undefined. This occurs with weak definitions, for example. 383 if (!SD->Symbol->isUndefined()) 384 FixedValue -= Layout.getSymbolOffset(SD); 385 } else { 386 // The index is the section ordinal (1-based). 387 const MCSectionData &SymSD = Asm.getSectionData( 388 SD->getSymbol().getSection()); 389 Index = SymSD.getOrdinal() + 1; 390 FixedValue += Writer->getSectionAddress(&SymSD); 391 } 392 if (IsPCRel) 393 FixedValue -= Writer->getSectionAddress(Fragment->getParent()); 394 395 // The type is determined by the fixup kind. 396 Type = RelocType; 397 } 398 399 // struct relocation_info (8 bytes) 400 macho::RelocationEntry MRE; 401 MRE.Word0 = FixupOffset; 402 MRE.Word1 = ((Index << 0) | 403 (IsPCRel << 24) | 404 (Log2Size << 25) | 405 (IsExtern << 27) | 406 (Type << 28)); 407 408 // Even when it's not a scattered relocation, movw/movt always uses 409 // a PAIR relocation. 410 if (Type == macho::RIT_ARM_Half) { 411 // The other-half value only gets populated for the movt and movw 412 // relocation entries. 413 uint32_t Value = 0; 414 switch ((unsigned)Fixup.getKind()) { 415 default: break; 416 case ARM::fixup_arm_movw_lo16: 417 case ARM::fixup_arm_movw_lo16_pcrel: 418 case ARM::fixup_t2_movw_lo16: 419 case ARM::fixup_t2_movw_lo16_pcrel: 420 Value = (FixedValue >> 16) & 0xffff; 421 break; 422 case ARM::fixup_arm_movt_hi16: 423 case ARM::fixup_arm_movt_hi16_pcrel: 424 case ARM::fixup_t2_movt_hi16: 425 case ARM::fixup_t2_movt_hi16_pcrel: 426 Value = FixedValue & 0xffff; 427 break; 428 } 429 macho::RelocationEntry MREPair; 430 MREPair.Word0 = Value; 431 MREPair.Word1 = ((0xffffff) | 432 (Log2Size << 25) | 433 (macho::RIT_Pair << 28)); 434 435 Writer->addRelocation(Fragment->getParent(), MREPair); 436 } 437 438 Writer->addRelocation(Fragment->getParent(), MRE); 439} 440 441MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS, 442 bool Is64Bit, 443 uint32_t CPUType, 444 uint32_t CPUSubtype) { 445 return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit, 446 CPUType, 447 CPUSubtype), 448 OS, /*IsLittleEndian=*/true); 449} 450