LLVM API Documentation
00001 //===-- PPCMachObjectWriter.cpp - PPC Mach-O 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/PPCMCTargetDesc.h" 00011 #include "MCTargetDesc/PPCFixupKinds.h" 00012 #include "llvm/ADT/Twine.h" 00013 #include "llvm/MC/MCAsmLayout.h" 00014 #include "llvm/MC/MCAssembler.h" 00015 #include "llvm/MC/MCContext.h" 00016 #include "llvm/MC/MCMachObjectWriter.h" 00017 #include "llvm/MC/MCSectionMachO.h" 00018 #include "llvm/MC/MCValue.h" 00019 #include "llvm/Support/ErrorHandling.h" 00020 #include "llvm/Support/Format.h" 00021 #include "llvm/Support/MachO.h" 00022 00023 using namespace llvm; 00024 00025 namespace { 00026 class PPCMachObjectWriter : public MCMachObjectTargetWriter { 00027 bool RecordScatteredRelocation(MachObjectWriter *Writer, 00028 const MCAssembler &Asm, 00029 const MCAsmLayout &Layout, 00030 const MCFragment *Fragment, 00031 const MCFixup &Fixup, MCValue Target, 00032 unsigned Log2Size, uint64_t &FixedValue); 00033 00034 void RecordPPCRelocation(MachObjectWriter *Writer, const MCAssembler &Asm, 00035 const MCAsmLayout &Layout, 00036 const MCFragment *Fragment, const MCFixup &Fixup, 00037 MCValue Target, uint64_t &FixedValue); 00038 00039 public: 00040 PPCMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype) 00041 : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype, 00042 /*UseAggressiveSymbolFolding=*/Is64Bit) {} 00043 00044 void RecordRelocation(MachObjectWriter *Writer, const MCAssembler &Asm, 00045 const MCAsmLayout &Layout, const MCFragment *Fragment, 00046 const MCFixup &Fixup, MCValue Target, 00047 uint64_t &FixedValue) override { 00048 if (Writer->is64Bit()) { 00049 report_fatal_error("Relocation emission for MachO/PPC64 unimplemented."); 00050 } else 00051 RecordPPCRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, 00052 FixedValue); 00053 } 00054 }; 00055 } 00056 00057 /// computes the log2 of the size of the relocation, 00058 /// used for relocation_info::r_length. 00059 static unsigned getFixupKindLog2Size(unsigned Kind) { 00060 switch (Kind) { 00061 default: 00062 report_fatal_error("log2size(FixupKind): Unhandled fixup kind!"); 00063 case FK_PCRel_1: 00064 case FK_Data_1: 00065 return 0; 00066 case FK_PCRel_2: 00067 case FK_Data_2: 00068 return 1; 00069 case FK_PCRel_4: 00070 case PPC::fixup_ppc_brcond14: 00071 case PPC::fixup_ppc_half16: 00072 case PPC::fixup_ppc_br24: 00073 case FK_Data_4: 00074 return 2; 00075 case FK_PCRel_8: 00076 case FK_Data_8: 00077 return 3; 00078 } 00079 return 0; 00080 } 00081 00082 /// Translates generic PPC fixup kind to Mach-O/PPC relocation type enum. 00083 /// Outline based on PPCELFObjectWriter::GetRelocType(). 00084 static unsigned getRelocType(const MCValue &Target, 00085 const MCFixupKind FixupKind, // from 00086 // Fixup.getKind() 00087 const bool IsPCRel) { 00088 const MCSymbolRefExpr::VariantKind Modifier = 00089 Target.isAbsolute() ? MCSymbolRefExpr::VK_None 00090 : Target.getSymA()->getKind(); 00091 // determine the type of the relocation 00092 unsigned Type = MachO::GENERIC_RELOC_VANILLA; 00093 if (IsPCRel) { // relative to PC 00094 switch ((unsigned)FixupKind) { 00095 default: 00096 report_fatal_error("Unimplemented fixup kind (relative)"); 00097 case PPC::fixup_ppc_br24: 00098 Type = MachO::PPC_RELOC_BR24; // R_PPC_REL24 00099 break; 00100 case PPC::fixup_ppc_brcond14: 00101 Type = MachO::PPC_RELOC_BR14; 00102 break; 00103 case PPC::fixup_ppc_half16: 00104 switch (Modifier) { 00105 default: 00106 llvm_unreachable("Unsupported modifier for half16 fixup"); 00107 case MCSymbolRefExpr::VK_PPC_HA: 00108 Type = MachO::PPC_RELOC_HA16; 00109 break; 00110 case MCSymbolRefExpr::VK_PPC_LO: 00111 Type = MachO::PPC_RELOC_LO16; 00112 break; 00113 case MCSymbolRefExpr::VK_PPC_HI: 00114 Type = MachO::PPC_RELOC_HI16; 00115 break; 00116 } 00117 break; 00118 } 00119 } else { 00120 switch ((unsigned)FixupKind) { 00121 default: 00122 report_fatal_error("Unimplemented fixup kind (absolute)!"); 00123 case PPC::fixup_ppc_half16: 00124 switch (Modifier) { 00125 default: 00126 llvm_unreachable("Unsupported modifier for half16 fixup"); 00127 case MCSymbolRefExpr::VK_PPC_HA: 00128 Type = MachO::PPC_RELOC_HA16_SECTDIFF; 00129 break; 00130 case MCSymbolRefExpr::VK_PPC_LO: 00131 Type = MachO::PPC_RELOC_LO16_SECTDIFF; 00132 break; 00133 case MCSymbolRefExpr::VK_PPC_HI: 00134 Type = MachO::PPC_RELOC_HI16_SECTDIFF; 00135 break; 00136 } 00137 break; 00138 case FK_Data_4: 00139 break; 00140 case FK_Data_2: 00141 break; 00142 } 00143 } 00144 return Type; 00145 } 00146 00147 static void makeRelocationInfo(MachO::any_relocation_info &MRE, 00148 const uint32_t FixupOffset, const uint32_t Index, 00149 const unsigned IsPCRel, const unsigned Log2Size, 00150 const unsigned IsExtern, const unsigned Type) { 00151 MRE.r_word0 = FixupOffset; 00152 // The bitfield offsets that work (as determined by trial-and-error) 00153 // are different than what is documented in the mach-o manuals. 00154 // This appears to be an endianness issue; reversing the order of the 00155 // documented bitfields in <llvm/Support/MachO.h> fixes this (but 00156 // breaks x86/ARM assembly). 00157 MRE.r_word1 = ((Index << 8) | // was << 0 00158 (IsPCRel << 7) | // was << 24 00159 (Log2Size << 5) | // was << 25 00160 (IsExtern << 4) | // was << 27 00161 (Type << 0)); // was << 28 00162 } 00163 00164 static void 00165 makeScatteredRelocationInfo(MachO::any_relocation_info &MRE, 00166 const uint32_t Addr, const unsigned Type, 00167 const unsigned Log2Size, const unsigned IsPCRel, 00168 const uint32_t Value2) { 00169 // For notes on bitfield positions and endianness, see: 00170 // https://developer.apple.com/library/mac/documentation/developertools/conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/uid/20001298-scattered_relocation_entry 00171 MRE.r_word0 = ((Addr << 0) | (Type << 24) | (Log2Size << 28) | 00172 (IsPCRel << 30) | MachO::R_SCATTERED); 00173 MRE.r_word1 = Value2; 00174 } 00175 00176 /// Compute fixup offset (address). 00177 static uint32_t getFixupOffset(const MCAsmLayout &Layout, 00178 const MCFragment *Fragment, 00179 const MCFixup &Fixup) { 00180 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); 00181 // On Mach-O, ppc_fixup_half16 relocations must refer to the 00182 // start of the instruction, not the second halfword, as ELF does 00183 if (unsigned(Fixup.getKind()) == PPC::fixup_ppc_half16) 00184 FixupOffset &= ~uint32_t(3); 00185 return FixupOffset; 00186 } 00187 00188 /// \return false if falling back to using non-scattered relocation, 00189 /// otherwise true for normal scattered relocation. 00190 /// based on X86MachObjectWriter::RecordScatteredRelocation 00191 /// and ARMMachObjectWriter::RecordScatteredRelocation 00192 bool PPCMachObjectWriter::RecordScatteredRelocation( 00193 MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout, 00194 const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, 00195 unsigned Log2Size, uint64_t &FixedValue) { 00196 // caller already computes these, can we just pass and reuse? 00197 const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup); 00198 const MCFixupKind FK = Fixup.getKind(); 00199 const unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, FK); 00200 const unsigned Type = getRelocType(Target, FK, IsPCRel); 00201 00202 // Is this a local or SECTDIFF relocation entry? 00203 // SECTDIFF relocation entries have symbol subtractions, 00204 // and require two entries, the first for the add-symbol value, 00205 // the second for the subtract-symbol value. 00206 00207 // See <reloc.h>. 00208 const MCSymbol *A = &Target.getSymA()->getSymbol(); 00209 const MCSymbolData *A_SD = &Asm.getSymbolData(*A); 00210 00211 if (!A_SD->getFragment()) 00212 report_fatal_error("symbol '" + A->getName() + 00213 "' can not be undefined in a subtraction expression"); 00214 00215 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout); 00216 uint64_t SecAddr = 00217 Writer->getSectionAddress(A_SD->getFragment()->getParent()); 00218 FixedValue += SecAddr; 00219 uint32_t Value2 = 0; 00220 00221 if (const MCSymbolRefExpr *B = Target.getSymB()) { 00222 const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); 00223 00224 if (!B_SD->getFragment()) 00225 report_fatal_error("symbol '" + B->getSymbol().getName() + 00226 "' can not be undefined in a subtraction expression"); 00227 00228 // FIXME: is Type correct? see include/llvm/Support/MachO.h 00229 Value2 = Writer->getSymbolAddress(B_SD, Layout); 00230 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent()); 00231 } 00232 // FIXME: does FixedValue get used?? 00233 00234 // Relocations are written out in reverse order, so the PAIR comes first. 00235 if (Type == MachO::PPC_RELOC_SECTDIFF || 00236 Type == MachO::PPC_RELOC_HI16_SECTDIFF || 00237 Type == MachO::PPC_RELOC_LO16_SECTDIFF || 00238 Type == MachO::PPC_RELOC_HA16_SECTDIFF || 00239 Type == MachO::PPC_RELOC_LO14_SECTDIFF || 00240 Type == MachO::PPC_RELOC_LOCAL_SECTDIFF) { 00241 // X86 had this piece, but ARM does not 00242 // If the offset is too large to fit in a scattered relocation, 00243 // we're hosed. It's an unfortunate limitation of the MachO format. 00244 if (FixupOffset > 0xffffff) { 00245 char Buffer[32]; 00246 format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer)); 00247 Asm.getContext().FatalError(Fixup.getLoc(), 00248 Twine("Section too large, can't encode " 00249 "r_address (") + 00250 Buffer + ") into 24 bits of scattered " 00251 "relocation entry."); 00252 llvm_unreachable("fatal error returned?!"); 00253 } 00254 00255 // Is this supposed to follow MCTarget/PPCAsmBackend.cpp:adjustFixupValue()? 00256 // see PPCMCExpr::EvaluateAsRelocatableImpl() 00257 uint32_t other_half = 0; 00258 switch (Type) { 00259 case MachO::PPC_RELOC_LO16_SECTDIFF: 00260 other_half = (FixedValue >> 16) & 0xffff; 00261 // applyFixupOffset longer extracts the high part because it now assumes 00262 // this was already done. 00263 // It looks like this is not true for the FixedValue needed with Mach-O 00264 // relocs. 00265 // So we need to adjust FixedValue again here. 00266 FixedValue &= 0xffff; 00267 break; 00268 case MachO::PPC_RELOC_HA16_SECTDIFF: 00269 other_half = FixedValue & 0xffff; 00270 FixedValue = 00271 ((FixedValue >> 16) + ((FixedValue & 0x8000) ? 1 : 0)) & 0xffff; 00272 break; 00273 case MachO::PPC_RELOC_HI16_SECTDIFF: 00274 other_half = FixedValue & 0xffff; 00275 FixedValue = (FixedValue >> 16) & 0xffff; 00276 break; 00277 default: 00278 llvm_unreachable("Invalid PPC scattered relocation type."); 00279 break; 00280 } 00281 00282 MachO::any_relocation_info MRE; 00283 makeScatteredRelocationInfo(MRE, other_half, MachO::GENERIC_RELOC_PAIR, 00284 Log2Size, IsPCRel, Value2); 00285 Writer->addRelocation(Fragment->getParent(), MRE); 00286 } else { 00287 // If the offset is more than 24-bits, it won't fit in a scattered 00288 // relocation offset field, so we fall back to using a non-scattered 00289 // relocation. This is a bit risky, as if the offset reaches out of 00290 // the block and the linker is doing scattered loading on this 00291 // symbol, things can go badly. 00292 // 00293 // Required for 'as' compatibility. 00294 if (FixupOffset > 0xffffff) 00295 return false; 00296 } 00297 MachO::any_relocation_info MRE; 00298 makeScatteredRelocationInfo(MRE, FixupOffset, Type, Log2Size, IsPCRel, Value); 00299 Writer->addRelocation(Fragment->getParent(), MRE); 00300 return true; 00301 } 00302 00303 // see PPCELFObjectWriter for a general outline of cases 00304 void PPCMachObjectWriter::RecordPPCRelocation( 00305 MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout, 00306 const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, 00307 uint64_t &FixedValue) { 00308 const MCFixupKind FK = Fixup.getKind(); // unsigned 00309 const unsigned Log2Size = getFixupKindLog2Size(FK); 00310 const bool IsPCRel = Writer->isFixupKindPCRel(Asm, FK); 00311 const unsigned RelocType = getRelocType(Target, FK, IsPCRel); 00312 00313 // If this is a difference or a defined symbol plus an offset, then we need a 00314 // scattered relocation entry. Differences always require scattered 00315 // relocations. 00316 if (Target.getSymB() && 00317 // Q: are branch targets ever scattered? 00318 RelocType != MachO::PPC_RELOC_BR24 && 00319 RelocType != MachO::PPC_RELOC_BR14) { 00320 RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, 00321 Log2Size, FixedValue); 00322 return; 00323 } 00324 00325 // this doesn't seem right for RIT_PPC_BR24 00326 // Get the symbol data, if any. 00327 const MCSymbolData *SD = nullptr; 00328 if (Target.getSymA()) 00329 SD = &Asm.getSymbolData(Target.getSymA()->getSymbol()); 00330 00331 // See <reloc.h>. 00332 const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup); 00333 unsigned Index = 0; 00334 unsigned IsExtern = 0; 00335 unsigned Type = RelocType; 00336 00337 if (Target.isAbsolute()) { // constant 00338 // SymbolNum of 0 indicates the absolute section. 00339 // 00340 // FIXME: Currently, these are never generated (see code below). I cannot 00341 // find a case where they are actually emitted. 00342 report_fatal_error("FIXME: relocations to absolute targets " 00343 "not yet implemented"); 00344 // the above line stolen from ARM, not sure 00345 } else { 00346 // Resolve constant variables. 00347 if (SD->getSymbol().isVariable()) { 00348 int64_t Res; 00349 if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( 00350 Res, Layout, Writer->getSectionAddressMap())) { 00351 FixedValue = Res; 00352 return; 00353 } 00354 } 00355 00356 // Check whether we need an external or internal relocation. 00357 if (Writer->doesSymbolRequireExternRelocation(SD)) { 00358 IsExtern = 1; 00359 Index = SD->getIndex(); 00360 // For external relocations, make sure to offset the fixup value to 00361 // compensate for the addend of the symbol address, if it was 00362 // undefined. This occurs with weak definitions, for example. 00363 if (!SD->Symbol->isUndefined()) 00364 FixedValue -= Layout.getSymbolOffset(SD); 00365 } else { 00366 // The index is the section ordinal (1-based). 00367 const MCSectionData &SymSD = 00368 Asm.getSectionData(SD->getSymbol().getSection()); 00369 Index = SymSD.getOrdinal() + 1; 00370 FixedValue += Writer->getSectionAddress(&SymSD); 00371 } 00372 if (IsPCRel) 00373 FixedValue -= Writer->getSectionAddress(Fragment->getParent()); 00374 } 00375 00376 // struct relocation_info (8 bytes) 00377 MachO::any_relocation_info MRE; 00378 makeRelocationInfo(MRE, FixupOffset, Index, IsPCRel, Log2Size, IsExtern, 00379 Type); 00380 Writer->addRelocation(Fragment->getParent(), MRE); 00381 } 00382 00383 MCObjectWriter *llvm::createPPCMachObjectWriter(raw_ostream &OS, bool Is64Bit, 00384 uint32_t CPUType, 00385 uint32_t CPUSubtype) { 00386 return createMachObjectWriter( 00387 new PPCMachObjectWriter(Is64Bit, CPUType, CPUSubtype), OS, 00388 /*IsLittleEndian=*/false); 00389 }