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