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