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