LLVM API Documentation
00001 //===-- ARMMachObjectWriter.cpp - ARM Mach Object Writer ------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 00010 #include "MCTargetDesc/ARMMCTargetDesc.h" 00011 #include "MCTargetDesc/ARMBaseInfo.h" 00012 #include "MCTargetDesc/ARMFixupKinds.h" 00013 #include "llvm/ADT/Twine.h" 00014 #include "llvm/MC/MCAsmLayout.h" 00015 #include "llvm/MC/MCAssembler.h" 00016 #include "llvm/MC/MCContext.h" 00017 #include "llvm/MC/MCExpr.h" 00018 #include "llvm/MC/MCFixup.h" 00019 #include "llvm/MC/MCFixupKindInfo.h" 00020 #include "llvm/MC/MCMachOSymbolFlags.h" 00021 #include "llvm/MC/MCMachObjectWriter.h" 00022 #include "llvm/MC/MCValue.h" 00023 #include "llvm/Support/ErrorHandling.h" 00024 #include "llvm/Support/MachO.h" 00025 using namespace llvm; 00026 00027 namespace { 00028 class ARMMachObjectWriter : public MCMachObjectTargetWriter { 00029 void RecordARMScatteredRelocation(MachObjectWriter *Writer, 00030 const MCAssembler &Asm, 00031 const MCAsmLayout &Layout, 00032 const MCFragment *Fragment, 00033 const MCFixup &Fixup, 00034 MCValue Target, 00035 unsigned Type, 00036 unsigned Log2Size, 00037 uint64_t &FixedValue); 00038 void RecordARMScatteredHalfRelocation(MachObjectWriter *Writer, 00039 const MCAssembler &Asm, 00040 const MCAsmLayout &Layout, 00041 const MCFragment *Fragment, 00042 const MCFixup &Fixup, MCValue Target, 00043 uint64_t &FixedValue); 00044 00045 bool requiresExternRelocation(MachObjectWriter *Writer, 00046 const MCAssembler &Asm, 00047 const MCFragment &Fragment, 00048 unsigned RelocType, const MCSymbolData *SD, 00049 uint64_t FixedValue); 00050 00051 public: 00052 ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType, 00053 uint32_t CPUSubtype) 00054 : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype, 00055 /*UseAggressiveSymbolFolding=*/true) {} 00056 00057 void RecordRelocation(MachObjectWriter *Writer, 00058 const MCAssembler &Asm, const MCAsmLayout &Layout, 00059 const MCFragment *Fragment, const MCFixup &Fixup, 00060 MCValue Target, uint64_t &FixedValue) override; 00061 }; 00062 } 00063 00064 static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType, 00065 unsigned &Log2Size) { 00066 RelocType = unsigned(MachO::ARM_RELOC_VANILLA); 00067 Log2Size = ~0U; 00068 00069 switch (Kind) { 00070 default: 00071 return false; 00072 00073 case FK_Data_1: 00074 Log2Size = llvm::Log2_32(1); 00075 return true; 00076 case FK_Data_2: 00077 Log2Size = llvm::Log2_32(2); 00078 return true; 00079 case FK_Data_4: 00080 Log2Size = llvm::Log2_32(4); 00081 return true; 00082 case FK_Data_8: 00083 Log2Size = llvm::Log2_32(8); 00084 return true; 00085 00086 // These fixups are expected to always be resolvable at assembly time and 00087 // have no relocations supported. 00088 case ARM::fixup_arm_ldst_pcrel_12: 00089 case ARM::fixup_arm_pcrel_10: 00090 case ARM::fixup_arm_adr_pcrel_12: 00091 return false; 00092 00093 // Handle 24-bit branch kinds. 00094 case ARM::fixup_arm_condbranch: 00095 case ARM::fixup_arm_uncondbranch: 00096 case ARM::fixup_arm_uncondbl: 00097 case ARM::fixup_arm_condbl: 00098 case ARM::fixup_arm_blx: 00099 RelocType = unsigned(MachO::ARM_RELOC_BR24); 00100 // Report as 'long', even though that is not quite accurate. 00101 Log2Size = llvm::Log2_32(4); 00102 return true; 00103 00104 // Handle Thumb branches. 00105 case ARM::fixup_arm_thumb_br: 00106 RelocType = unsigned(MachO::ARM_THUMB_RELOC_BR22); 00107 Log2Size = llvm::Log2_32(2); 00108 return true; 00109 00110 case ARM::fixup_t2_uncondbranch: 00111 case ARM::fixup_arm_thumb_bl: 00112 case ARM::fixup_arm_thumb_blx: 00113 RelocType = unsigned(MachO::ARM_THUMB_RELOC_BR22); 00114 Log2Size = llvm::Log2_32(4); 00115 return true; 00116 00117 // For movw/movt r_type relocations they always have a pair following them and 00118 // the r_length bits are used differently. The encoding of the r_length is as 00119 // follows: 00120 // low bit of r_length: 00121 // 0 - :lower16: for movw instructions 00122 // 1 - :upper16: for movt instructions 00123 // high bit of r_length: 00124 // 0 - arm instructions 00125 // 1 - thumb instructions 00126 case ARM::fixup_arm_movt_hi16: 00127 RelocType = unsigned(MachO::ARM_RELOC_HALF); 00128 Log2Size = 1; 00129 return true; 00130 case ARM::fixup_t2_movt_hi16: 00131 RelocType = unsigned(MachO::ARM_RELOC_HALF); 00132 Log2Size = 3; 00133 return true; 00134 00135 case ARM::fixup_arm_movw_lo16: 00136 RelocType = unsigned(MachO::ARM_RELOC_HALF); 00137 Log2Size = 0; 00138 return true; 00139 case ARM::fixup_t2_movw_lo16: 00140 RelocType = unsigned(MachO::ARM_RELOC_HALF); 00141 Log2Size = 2; 00142 return true; 00143 } 00144 } 00145 00146 void ARMMachObjectWriter:: 00147 RecordARMScatteredHalfRelocation(MachObjectWriter *Writer, 00148 const MCAssembler &Asm, 00149 const MCAsmLayout &Layout, 00150 const MCFragment *Fragment, 00151 const MCFixup &Fixup, 00152 MCValue Target, 00153 uint64_t &FixedValue) { 00154 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 00155 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 00156 unsigned Type = MachO::ARM_RELOC_HALF; 00157 00158 // See <reloc.h>. 00159 const MCSymbol *A = &Target.getSymA()->getSymbol(); 00160 const MCSymbolData *A_SD = &Asm.getSymbolData(*A); 00161 00162 if (!A_SD->getFragment()) 00163 Asm.getContext().FatalError(Fixup.getLoc(), 00164 "symbol '" + A->getName() + 00165 "' can not be undefined in a subtraction expression"); 00166 00167 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout); 00168 uint32_t Value2 = 0; 00169 uint64_t SecAddr = 00170 Writer->getSectionAddress(A_SD->getFragment()->getParent()); 00171 FixedValue += SecAddr; 00172 00173 if (const MCSymbolRefExpr *B = Target.getSymB()) { 00174 const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); 00175 00176 if (!B_SD->getFragment()) 00177 Asm.getContext().FatalError(Fixup.getLoc(), 00178 "symbol '" + B->getSymbol().getName() + 00179 "' can not be undefined in a subtraction expression"); 00180 00181 // Select the appropriate difference relocation type. 00182 Type = MachO::ARM_RELOC_HALF_SECTDIFF; 00183 Value2 = Writer->getSymbolAddress(B_SD, Layout); 00184 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent()); 00185 } 00186 00187 // Relocations are written out in reverse order, so the PAIR comes first. 00188 // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field: 00189 // 00190 // For these two r_type relocations they always have a pair following them and 00191 // the r_length bits are used differently. The encoding of the r_length is as 00192 // follows: 00193 // low bit of r_length: 00194 // 0 - :lower16: for movw instructions 00195 // 1 - :upper16: for movt instructions 00196 // high bit of r_length: 00197 // 0 - arm instructions 00198 // 1 - thumb instructions 00199 // the other half of the relocated expression is in the following pair 00200 // relocation entry in the low 16 bits of r_address field. 00201 unsigned ThumbBit = 0; 00202 unsigned MovtBit = 0; 00203 switch ((unsigned)Fixup.getKind()) { 00204 default: break; 00205 case ARM::fixup_arm_movt_hi16: 00206 MovtBit = 1; 00207 // The thumb bit shouldn't be set in the 'other-half' bit of the 00208 // relocation, but it will be set in FixedValue if the base symbol 00209 // is a thumb function. Clear it out here. 00210 if (Asm.isThumbFunc(A)) 00211 FixedValue &= 0xfffffffe; 00212 break; 00213 case ARM::fixup_t2_movt_hi16: 00214 if (Asm.isThumbFunc(A)) 00215 FixedValue &= 0xfffffffe; 00216 MovtBit = 1; 00217 // Fallthrough 00218 case ARM::fixup_t2_movw_lo16: 00219 ThumbBit = 1; 00220 break; 00221 } 00222 00223 if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) { 00224 uint32_t OtherHalf = MovtBit 00225 ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16); 00226 00227 MachO::any_relocation_info MRE; 00228 MRE.r_word0 = ((OtherHalf << 0) | 00229 (MachO::ARM_RELOC_PAIR << 24) | 00230 (MovtBit << 28) | 00231 (ThumbBit << 29) | 00232 (IsPCRel << 30) | 00233 MachO::R_SCATTERED); 00234 MRE.r_word1 = Value2; 00235 Writer->addRelocation(Fragment->getParent(), MRE); 00236 } 00237 00238 MachO::any_relocation_info MRE; 00239 MRE.r_word0 = ((FixupOffset << 0) | 00240 (Type << 24) | 00241 (MovtBit << 28) | 00242 (ThumbBit << 29) | 00243 (IsPCRel << 30) | 00244 MachO::R_SCATTERED); 00245 MRE.r_word1 = Value; 00246 Writer->addRelocation(Fragment->getParent(), MRE); 00247 } 00248 00249 void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer, 00250 const MCAssembler &Asm, 00251 const MCAsmLayout &Layout, 00252 const MCFragment *Fragment, 00253 const MCFixup &Fixup, 00254 MCValue Target, 00255 unsigned Type, 00256 unsigned Log2Size, 00257 uint64_t &FixedValue) { 00258 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 00259 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 00260 00261 // See <reloc.h>. 00262 const MCSymbol *A = &Target.getSymA()->getSymbol(); 00263 const MCSymbolData *A_SD = &Asm.getSymbolData(*A); 00264 00265 if (!A_SD->getFragment()) 00266 Asm.getContext().FatalError(Fixup.getLoc(), 00267 "symbol '" + A->getName() + 00268 "' can not be undefined in a subtraction expression"); 00269 00270 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout); 00271 uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent()); 00272 FixedValue += SecAddr; 00273 uint32_t Value2 = 0; 00274 00275 if (const MCSymbolRefExpr *B = Target.getSymB()) { 00276 assert(Type == MachO::ARM_RELOC_VANILLA && "invalid reloc for 2 symbols"); 00277 const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); 00278 00279 if (!B_SD->getFragment()) 00280 Asm.getContext().FatalError(Fixup.getLoc(), 00281 "symbol '" + B->getSymbol().getName() + 00282 "' can not be undefined in a subtraction expression"); 00283 00284 // Select the appropriate difference relocation type. 00285 Type = MachO::ARM_RELOC_SECTDIFF; 00286 Value2 = Writer->getSymbolAddress(B_SD, Layout); 00287 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent()); 00288 } 00289 00290 // Relocations are written out in reverse order, so the PAIR comes first. 00291 if (Type == MachO::ARM_RELOC_SECTDIFF || 00292 Type == MachO::ARM_RELOC_LOCAL_SECTDIFF) { 00293 MachO::any_relocation_info MRE; 00294 MRE.r_word0 = ((0 << 0) | 00295 (MachO::ARM_RELOC_PAIR << 24) | 00296 (Log2Size << 28) | 00297 (IsPCRel << 30) | 00298 MachO::R_SCATTERED); 00299 MRE.r_word1 = Value2; 00300 Writer->addRelocation(Fragment->getParent(), MRE); 00301 } 00302 00303 MachO::any_relocation_info MRE; 00304 MRE.r_word0 = ((FixupOffset << 0) | 00305 (Type << 24) | 00306 (Log2Size << 28) | 00307 (IsPCRel << 30) | 00308 MachO::R_SCATTERED); 00309 MRE.r_word1 = Value; 00310 Writer->addRelocation(Fragment->getParent(), MRE); 00311 } 00312 00313 bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer, 00314 const MCAssembler &Asm, 00315 const MCFragment &Fragment, 00316 unsigned RelocType, 00317 const MCSymbolData *SD, 00318 uint64_t FixedValue) { 00319 // Most cases can be identified purely from the symbol. 00320 if (Writer->doesSymbolRequireExternRelocation(SD)) 00321 return true; 00322 int64_t Value = (int64_t)FixedValue; // The displacement is signed. 00323 int64_t Range; 00324 switch (RelocType) { 00325 default: 00326 return false; 00327 case MachO::ARM_RELOC_BR24: 00328 // PC pre-adjustment of 8 for these instructions. 00329 Value -= 8; 00330 // ARM BL/BLX has a 25-bit offset. 00331 Range = 0x1ffffff; 00332 break; 00333 case MachO::ARM_THUMB_RELOC_BR22: 00334 // PC pre-adjustment of 4 for these instructions. 00335 Value -= 4; 00336 // Thumb BL/BLX has a 24-bit offset. 00337 Range = 0xffffff; 00338 } 00339 // BL/BLX also use external relocations when an internal relocation 00340 // would result in the target being out of range. This gives the linker 00341 // enough information to generate a branch island. 00342 const MCSectionData &SymSD = Asm.getSectionData( 00343 SD->getSymbol().getSection()); 00344 Value += Writer->getSectionAddress(&SymSD); 00345 Value -= Writer->getSectionAddress(Fragment.getParent()); 00346 // If the resultant value would be out of range for an internal relocation, 00347 // use an external instead. 00348 if (Value > Range || Value < -(Range + 1)) 00349 return true; 00350 return false; 00351 } 00352 00353 void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer, 00354 const MCAssembler &Asm, 00355 const MCAsmLayout &Layout, 00356 const MCFragment *Fragment, 00357 const MCFixup &Fixup, 00358 MCValue Target, 00359 uint64_t &FixedValue) { 00360 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind()); 00361 unsigned Log2Size; 00362 unsigned RelocType = MachO::ARM_RELOC_VANILLA; 00363 if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) 00364 // If we failed to get fixup kind info, it's because there's no legal 00365 // relocation type for the fixup kind. This happens when it's a fixup that's 00366 // expected to always be resolvable at assembly time and not have any 00367 // relocations needed. 00368 Asm.getContext().FatalError(Fixup.getLoc(), 00369 "unsupported relocation on symbol"); 00370 00371 // If this is a difference or a defined symbol plus an offset, then we need a 00372 // scattered relocation entry. Differences always require scattered 00373 // relocations. 00374 if (Target.getSymB()) { 00375 if (RelocType == MachO::ARM_RELOC_HALF) 00376 return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment, 00377 Fixup, Target, FixedValue); 00378 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 00379 Target, RelocType, Log2Size, 00380 FixedValue); 00381 } 00382 00383 // Get the symbol data, if any. 00384 const MCSymbolData *SD = nullptr; 00385 if (Target.getSymA()) 00386 SD = &Asm.getSymbolData(Target.getSymA()->getSymbol()); 00387 00388 // FIXME: For other platforms, we need to use scattered relocations for 00389 // internal relocations with offsets. If this is an internal relocation with 00390 // an offset, it also needs a scattered relocation entry. 00391 // 00392 // Is this right for ARM? 00393 uint32_t Offset = Target.getConstant(); 00394 if (IsPCRel && RelocType == MachO::ARM_RELOC_VANILLA) 00395 Offset += 1 << Log2Size; 00396 if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD)) 00397 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, 00398 Target, RelocType, Log2Size, 00399 FixedValue); 00400 00401 // See <reloc.h>. 00402 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); 00403 unsigned Index = 0; 00404 unsigned IsExtern = 0; 00405 unsigned Type = 0; 00406 00407 if (Target.isAbsolute()) { // constant 00408 // FIXME! 00409 report_fatal_error("FIXME: relocations to absolute targets " 00410 "not yet implemented"); 00411 } else { 00412 // Resolve constant variables. 00413 if (SD->getSymbol().isVariable()) { 00414 int64_t Res; 00415 if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( 00416 Res, Layout, Writer->getSectionAddressMap())) { 00417 FixedValue = Res; 00418 return; 00419 } 00420 } 00421 00422 // Check whether we need an external or internal relocation. 00423 if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, SD, 00424 FixedValue)) { 00425 IsExtern = 1; 00426 Index = SD->getIndex(); 00427 00428 // For external relocations, make sure to offset the fixup value to 00429 // compensate for the addend of the symbol address, if it was 00430 // undefined. This occurs with weak definitions, for example. 00431 if (!SD->Symbol->isUndefined()) 00432 FixedValue -= Layout.getSymbolOffset(SD); 00433 } else { 00434 // The index is the section ordinal (1-based). 00435 const MCSectionData &SymSD = Asm.getSectionData( 00436 SD->getSymbol().getSection()); 00437 Index = SymSD.getOrdinal() + 1; 00438 FixedValue += Writer->getSectionAddress(&SymSD); 00439 } 00440 if (IsPCRel) 00441 FixedValue -= Writer->getSectionAddress(Fragment->getParent()); 00442 00443 // The type is determined by the fixup kind. 00444 Type = RelocType; 00445 } 00446 00447 // struct relocation_info (8 bytes) 00448 MachO::any_relocation_info MRE; 00449 MRE.r_word0 = FixupOffset; 00450 MRE.r_word1 = ((Index << 0) | 00451 (IsPCRel << 24) | 00452 (Log2Size << 25) | 00453 (IsExtern << 27) | 00454 (Type << 28)); 00455 00456 // Even when it's not a scattered relocation, movw/movt always uses 00457 // a PAIR relocation. 00458 if (Type == MachO::ARM_RELOC_HALF) { 00459 // The other-half value only gets populated for the movt and movw 00460 // relocation entries. 00461 uint32_t Value = 0; 00462 switch ((unsigned)Fixup.getKind()) { 00463 default: break; 00464 case ARM::fixup_arm_movw_lo16: 00465 case ARM::fixup_t2_movw_lo16: 00466 Value = (FixedValue >> 16) & 0xffff; 00467 break; 00468 case ARM::fixup_arm_movt_hi16: 00469 case ARM::fixup_t2_movt_hi16: 00470 Value = FixedValue & 0xffff; 00471 break; 00472 } 00473 MachO::any_relocation_info MREPair; 00474 MREPair.r_word0 = Value; 00475 MREPair.r_word1 = ((0xffffff << 0) | 00476 (Log2Size << 25) | 00477 (MachO::ARM_RELOC_PAIR << 28)); 00478 00479 Writer->addRelocation(Fragment->getParent(), MREPair); 00480 } 00481 00482 Writer->addRelocation(Fragment->getParent(), MRE); 00483 } 00484 00485 MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS, 00486 bool Is64Bit, 00487 uint32_t CPUType, 00488 uint32_t CPUSubtype) { 00489 return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit, 00490 CPUType, 00491 CPUSubtype), 00492 OS, /*IsLittleEndian=*/true); 00493 }