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