PPCMachObjectWriter.cpp revision 280031
143410Snewton//===-- PPCMachObjectWriter.cpp - PPC Mach-O Writer -----------------------===// 243410Snewton// 343410Snewton// The LLVM Compiler Infrastructure 443410Snewton// 543410Snewton// This file is distributed under the University of Illinois Open Source 643410Snewton// License. See LICENSE.TXT for details. 743410Snewton// 843410Snewton//===----------------------------------------------------------------------===// 943410Snewton 1043410Snewton#include "MCTargetDesc/PPCMCTargetDesc.h" 1143410Snewton#include "MCTargetDesc/PPCFixupKinds.h" 1243410Snewton#include "llvm/ADT/Twine.h" 1343410Snewton#include "llvm/MC/MCAsmLayout.h" 1443410Snewton#include "llvm/MC/MCAssembler.h" 1543410Snewton#include "llvm/MC/MCContext.h" 1643410Snewton#include "llvm/MC/MCMachObjectWriter.h" 1743410Snewton#include "llvm/MC/MCSectionMachO.h" 1843410Snewton#include "llvm/MC/MCValue.h" 1943410Snewton#include "llvm/Support/ErrorHandling.h" 2043410Snewton#include "llvm/Support/Format.h" 2143410Snewton#include "llvm/Support/MachO.h" 2243410Snewton 2343410Snewtonusing namespace llvm; 2443410Snewton 2543410Snewtonnamespace { 2643410Snewtonclass PPCMachObjectWriter : public MCMachObjectTargetWriter { 2743410Snewton bool RecordScatteredRelocation(MachObjectWriter *Writer, 2843410Snewton const MCAssembler &Asm, 2943410Snewton const MCAsmLayout &Layout, 3043410Snewton const MCFragment *Fragment, 3143410Snewton const MCFixup &Fixup, MCValue Target, 3249263Snewton unsigned Log2Size, uint64_t &FixedValue); 3350477Speter 3443410Snewton void RecordPPCRelocation(MachObjectWriter *Writer, const MCAssembler &Asm, 3543410Snewton const MCAsmLayout &Layout, 3643410Snewton const MCFragment *Fragment, const MCFixup &Fixup, 3743410Snewton MCValue Target, uint64_t &FixedValue); 3843410Snewton 3943410Snewtonpublic: 4043410Snewton PPCMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype) 4143410Snewton : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype, 4243410Snewton /*UseAggressiveSymbolFolding=*/Is64Bit) {} 4343410Snewton 4443410Snewton void RecordRelocation(MachObjectWriter *Writer, const MCAssembler &Asm, 4543410Snewton const MCAsmLayout &Layout, const MCFragment *Fragment, 4643410Snewton const MCFixup &Fixup, MCValue Target, 4743410Snewton uint64_t &FixedValue) override { 4843410Snewton if (Writer->is64Bit()) { 4943410Snewton report_fatal_error("Relocation emission for MachO/PPC64 unimplemented."); 5043410Snewton } else 5143410Snewton RecordPPCRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, 5243410Snewton FixedValue); 5343410Snewton } 5443410Snewton}; 5543410Snewton} 5643410Snewton 5765314Sobrien/// computes the log2 of the size of the relocation, 5865314Sobrien/// used for relocation_info::r_length. 5965314Sobrienstatic unsigned getFixupKindLog2Size(unsigned Kind) { 6065314Sobrien switch (Kind) { 6165314Sobrien default: 6265314Sobrien report_fatal_error("log2size(FixupKind): Unhandled fixup kind!"); 6343410Snewton case FK_PCRel_1: 6492739Salfred case FK_Data_1: 6592739Salfred return 0; 6643410Snewton case FK_PCRel_2: 6743410Snewton case FK_Data_2: 6843410Snewton return 1; 6943410Snewton case FK_PCRel_4: 7043410Snewton case PPC::fixup_ppc_brcond14: 7143410Snewton case PPC::fixup_ppc_half16: 7243410Snewton case PPC::fixup_ppc_br24: 7343410Snewton case FK_Data_4: 7460938Sjake return 2; 7543410Snewton case FK_PCRel_8: 7643410Snewton case FK_Data_8: 7760938Sjake return 3; 7843410Snewton } 7943410Snewton return 0; 8043410Snewton} 8143410Snewton 8243410Snewton/// Translates generic PPC fixup kind to Mach-O/PPC relocation type enum. 8343410Snewton/// Outline based on PPCELFObjectWriter::GetRelocType(). 8443410Snewtonstatic unsigned getRelocType(const MCValue &Target, 8543410Snewton const MCFixupKind FixupKind, // from 8643410Snewton // Fixup.getKind() 8743410Snewton const bool IsPCRel) { 8843410Snewton const MCSymbolRefExpr::VariantKind Modifier = 8943410Snewton Target.isAbsolute() ? MCSymbolRefExpr::VK_None 9043410Snewton : Target.getSymA()->getKind(); 9143410Snewton // determine the type of the relocation 9243410Snewton unsigned Type = MachO::GENERIC_RELOC_VANILLA; 9343410Snewton if (IsPCRel) { // relative to PC 9443410Snewton switch ((unsigned)FixupKind) { 9543410Snewton default: 9643410Snewton report_fatal_error("Unimplemented fixup kind (relative)"); 9743410Snewton case PPC::fixup_ppc_br24: 9889059Smsmith Type = MachO::PPC_RELOC_BR24; // R_PPC_REL24 9952114Snewton break; 10052114Snewton case PPC::fixup_ppc_brcond14: 10143410Snewton Type = MachO::PPC_RELOC_BR14; 102108235Sphk break; 10372521Sjlemon case PPC::fixup_ppc_half16: 10443410Snewton switch (Modifier) { 10543410Snewton default: 10643410Snewton llvm_unreachable("Unsupported modifier for half16 fixup"); 10743410Snewton case MCSymbolRefExpr::VK_PPC_HA: 108111815Sphk Type = MachO::PPC_RELOC_HA16; 109111815Sphk break; 110111815Sphk case MCSymbolRefExpr::VK_PPC_LO: 11147625Sphk Type = MachO::PPC_RELOC_LO16; 11243410Snewton break; 11343410Snewton case MCSymbolRefExpr::VK_PPC_HI: 11443410Snewton Type = MachO::PPC_RELOC_HI16; 11543410Snewton break; 11643410Snewton } 11743410Snewton break; 11843410Snewton } 11943410Snewton } else { 12043410Snewton switch ((unsigned)FixupKind) { 12144208Snewton default: 12244208Snewton report_fatal_error("Unimplemented fixup kind (absolute)!"); 12344208Snewton case PPC::fixup_ppc_half16: 12444208Snewton switch (Modifier) { 12544208Snewton default: 12649344Snewton llvm_unreachable("Unsupported modifier for half16 fixup"); 12752114Snewton case MCSymbolRefExpr::VK_PPC_HA: 12852114Snewton Type = MachO::PPC_RELOC_HA16_SECTDIFF; 12952114Snewton break; 13052114Snewton case MCSymbolRefExpr::VK_PPC_LO: 13152114Snewton Type = MachO::PPC_RELOC_LO16_SECTDIFF; 13252114Snewton break; 13352114Snewton case MCSymbolRefExpr::VK_PPC_HI: 13452114Snewton Type = MachO::PPC_RELOC_HI16_SECTDIFF; 13552114Snewton break; 13652114Snewton } 13752114Snewton break; 13852114Snewton case FK_Data_4: 13952114Snewton break; 14052114Snewton case FK_Data_2: 14152114Snewton break; 14252114Snewton } 14352114Snewton } 14452114Snewton return Type; 14552114Snewton} 14652114Snewton 14752114Snewtonstatic void makeRelocationInfo(MachO::any_relocation_info &MRE, 14852114Snewton const uint32_t FixupOffset, const uint32_t Index, 14952114Snewton const unsigned IsPCRel, const unsigned Log2Size, 15052114Snewton const unsigned IsExtern, const unsigned Type) { 15152114Snewton MRE.r_word0 = FixupOffset; 15252114Snewton // The bitfield offsets that work (as determined by trial-and-error) 15352114Snewton // are different than what is documented in the mach-o manuals. 15444208Snewton // This appears to be an endianness issue; reversing the order of the 15544208Snewton // documented bitfields in <llvm/Support/MachO.h> fixes this (but 15649344Snewton // breaks x86/ARM assembly). 15753000Sphk MRE.r_word1 = ((Index << 8) | // was << 0 15853000Sphk (IsPCRel << 7) | // was << 24 15953000Sphk (Log2Size << 5) | // was << 25 16053000Sphk (IsExtern << 4) | // was << 27 16153000Sphk (Type << 0)); // was << 28 16253000Sphk} 16353000Sphk 16453000Sphkstatic void 16553000SphkmakeScatteredRelocationInfo(MachO::any_relocation_info &MRE, 16653000Sphk const uint32_t Addr, const unsigned Type, 16752114Snewton const unsigned Log2Size, const unsigned IsPCRel, 16844208Snewton const uint32_t Value2) { 16944208Snewton // For notes on bitfield positions and endianness, see: 17044208Snewton // https://developer.apple.com/library/mac/documentation/developertools/conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/uid/20001298-scattered_relocation_entry 17144208Snewton MRE.r_word0 = ((Addr << 0) | (Type << 24) | (Log2Size << 28) | 17244208Snewton (IsPCRel << 30) | MachO::R_SCATTERED); 17344208Snewton MRE.r_word1 = Value2; 17444208Snewton} 17544208Snewton 17644208Snewton/// Compute fixup offset (address). 17744208Snewtonstatic uint32_t getFixupOffset(const MCAsmLayout &Layout, 17844208Snewton const MCFragment *Fragment, 17944208Snewton const MCFixup &Fixup) { 18044208Snewton uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); 18160060Sgreen // On Mach-O, ppc_fixup_half16 relocations must refer to the 18244208Snewton // start of the instruction, not the second halfword, as ELF does 18343410Snewton if (unsigned(Fixup.getKind()) == PPC::fixup_ppc_half16) 18443410Snewton FixupOffset &= ~uint32_t(3); 18543410Snewton return FixupOffset; 18643410Snewton} 18743410Snewton 18843410Snewton/// \return false if falling back to using non-scattered relocation, 18943410Snewton/// otherwise true for normal scattered relocation. 19043410Snewton/// based on X86MachObjectWriter::RecordScatteredRelocation 19183366Sjulian/// and ARMMachObjectWriter::RecordScatteredRelocation 19243410Snewtonbool PPCMachObjectWriter::RecordScatteredRelocation( 19343410Snewton MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout, 19443410Snewton const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, 19543410Snewton unsigned Log2Size, uint64_t &FixedValue) { 19643410Snewton // caller already computes these, can we just pass and reuse? 19743410Snewton const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup); 19843410Snewton const MCFixupKind FK = Fixup.getKind(); 19983366Sjulian const unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, FK); 20043410Snewton const unsigned Type = getRelocType(Target, FK, IsPCRel); 20171448Sjhb 20283366Sjulian // Is this a local or SECTDIFF relocation entry? 20371448Sjhb // SECTDIFF relocation entries have symbol subtractions, 20443410Snewton // and require two entries, the first for the add-symbol value, 20571448Sjhb // the second for the subtract-symbol value. 20671448Sjhb 20743410Snewton // See <reloc.h>. 20843410Snewton const MCSymbol *A = &Target.getSymA()->getSymbol(); 20943410Snewton const MCSymbolData *A_SD = &Asm.getSymbolData(*A); 21043410Snewton 21143410Snewton if (!A_SD->getFragment()) 21243410Snewton report_fatal_error("symbol '" + A->getName() + 21343410Snewton "' can not be undefined in a subtraction expression"); 21443410Snewton 21543410Snewton uint32_t Value = Writer->getSymbolAddress(A_SD, Layout); 21643410Snewton uint64_t SecAddr = 21743410Snewton Writer->getSectionAddress(A_SD->getFragment()->getParent()); 21843410Snewton FixedValue += SecAddr; 21943410Snewton uint32_t Value2 = 0; 22043410Snewton 22143410Snewton if (const MCSymbolRefExpr *B = Target.getSymB()) { 22243410Snewton const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); 22343410Snewton 22443410Snewton if (!B_SD->getFragment()) 22543410Snewton report_fatal_error("symbol '" + B->getSymbol().getName() + 22643410Snewton "' can not be undefined in a subtraction expression"); 22743410Snewton 22843410Snewton // FIXME: is Type correct? see include/llvm/Support/MachO.h 22943410Snewton Value2 = Writer->getSymbolAddress(B_SD, Layout); 23043410Snewton FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent()); 23143410Snewton } 23243410Snewton // FIXME: does FixedValue get used?? 23343410Snewton 23443410Snewton // Relocations are written out in reverse order, so the PAIR comes first. 23543410Snewton if (Type == MachO::PPC_RELOC_SECTDIFF || 23643410Snewton Type == MachO::PPC_RELOC_HI16_SECTDIFF || 23743410Snewton Type == MachO::PPC_RELOC_LO16_SECTDIFF || 23843410Snewton Type == MachO::PPC_RELOC_HA16_SECTDIFF || 23943410Snewton Type == MachO::PPC_RELOC_LO14_SECTDIFF || 24043410Snewton Type == MachO::PPC_RELOC_LOCAL_SECTDIFF) { 24143410Snewton // X86 had this piece, but ARM does not 24243410Snewton // If the offset is too large to fit in a scattered relocation, 24343410Snewton // we're hosed. It's an unfortunate limitation of the MachO format. 24443410Snewton if (FixupOffset > 0xffffff) { 24543410Snewton char Buffer[32]; 24643410Snewton format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer)); 24743410Snewton Asm.getContext().FatalError(Fixup.getLoc(), 24883366Sjulian Twine("Section too large, can't encode " 24943410Snewton "r_address (") + 25043410Snewton Buffer + ") into 24 bits of scattered " 25143410Snewton "relocation entry."); 25243410Snewton llvm_unreachable("fatal error returned?!"); 25343410Snewton } 25483366Sjulian 25543410Snewton // Is this supposed to follow MCTarget/PPCAsmBackend.cpp:adjustFixupValue()? 25643410Snewton // see PPCMCExpr::EvaluateAsRelocatableImpl() 25788739Srwatson uint32_t other_half = 0; 25891406Sjhb switch (Type) { 25989306Salfred case MachO::PPC_RELOC_LO16_SECTDIFF: 26043410Snewton other_half = (FixedValue >> 16) & 0xffff; 26189306Salfred // applyFixupOffset longer extracts the high part because it now assumes 26243410Snewton // this was already done. 26343410Snewton // It looks like this is not true for the FixedValue needed with Mach-O 26443410Snewton // relocs. 26543410Snewton // So we need to adjust FixedValue again here. 26689306Salfred FixedValue &= 0xffff; 267109153Sdillon break; 26843410Snewton case MachO::PPC_RELOC_HA16_SECTDIFF: 26949413Sgreen other_half = FixedValue & 0xffff; 27043410Snewton FixedValue = 27189306Salfred ((FixedValue >> 16) + ((FixedValue & 0x8000) ? 1 : 0)) & 0xffff; 27243410Snewton break; 27343410Snewton case MachO::PPC_RELOC_HI16_SECTDIFF: 27471448Sjhb other_half = FixedValue & 0xffff; 27583366Sjulian FixedValue = (FixedValue >> 16) & 0xffff; 27671448Sjhb break; 27743410Snewton default: 27843410Snewton llvm_unreachable("Invalid PPC scattered relocation type."); 27943410Snewton break; 28043410Snewton } 28183366Sjulian 28283366Sjulian MachO::any_relocation_info MRE; 28343410Snewton makeScatteredRelocationInfo(MRE, other_half, MachO::GENERIC_RELOC_PAIR, 28483366Sjulian Log2Size, IsPCRel, Value2); 28543410Snewton Writer->addRelocation(Fragment->getParent(), MRE); 28643410Snewton } else { 28743410Snewton // If the offset is more than 24-bits, it won't fit in a scattered 28843410Snewton // relocation offset field, so we fall back to using a non-scattered 28943410Snewton // relocation. This is a bit risky, as if the offset reaches out of 29043410Snewton // the block and the linker is doing scattered loading on this 29143410Snewton // symbol, things can go badly. 29243410Snewton // 29343410Snewton // Required for 'as' compatibility. 29443410Snewton if (FixupOffset > 0xffffff) 29543410Snewton return false; 29643410Snewton } 29743410Snewton MachO::any_relocation_info MRE; 29843410Snewton makeScatteredRelocationInfo(MRE, FixupOffset, Type, Log2Size, IsPCRel, Value); 29943410Snewton Writer->addRelocation(Fragment->getParent(), MRE); 30043410Snewton return true; 30143410Snewton} 30243410Snewton 30343410Snewton// see PPCELFObjectWriter for a general outline of cases 30443410Snewtonvoid PPCMachObjectWriter::RecordPPCRelocation( 30543410Snewton MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout, 30643410Snewton const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, 30743410Snewton uint64_t &FixedValue) { 308107849Salfred const MCFixupKind FK = Fixup.getKind(); // unsigned 309107849Salfred const unsigned Log2Size = getFixupKindLog2Size(FK); 310107849Salfred const bool IsPCRel = Writer->isFixupKindPCRel(Asm, FK); 31143410Snewton const unsigned RelocType = getRelocType(Target, FK, IsPCRel); 31243410Snewton 31343410Snewton // If this is a difference or a defined symbol plus an offset, then we need a 31443410Snewton // scattered relocation entry. Differences always require scattered 31543410Snewton // relocations. 31643410Snewton if (Target.getSymB() && 31743410Snewton // Q: are branch targets ever scattered? 31843410Snewton RelocType != MachO::PPC_RELOC_BR24 && 31983366Sjulian RelocType != MachO::PPC_RELOC_BR14) { 32043410Snewton RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, 32143410Snewton Log2Size, FixedValue); 32243410Snewton return; 32343410Snewton } 32471448Sjhb 32583366Sjulian // this doesn't seem right for RIT_PPC_BR24 32671448Sjhb // Get the symbol data, if any. 32743410Snewton const MCSymbolData *SD = nullptr; 32843410Snewton if (Target.getSymA()) 32943410Snewton SD = &Asm.getSymbolData(Target.getSymA()->getSymbol()); 33043410Snewton 33143410Snewton // See <reloc.h>. 33243410Snewton const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup); 33343410Snewton unsigned Index = 0; 33443410Snewton unsigned IsExtern = 0; 33543410Snewton unsigned Type = RelocType; 33643410Snewton 33743410Snewton if (Target.isAbsolute()) { // constant 33843410Snewton // SymbolNum of 0 indicates the absolute section. 33943410Snewton // 34043410Snewton // FIXME: Currently, these are never generated (see code below). I cannot 34143410Snewton // find a case where they are actually emitted. 34243410Snewton report_fatal_error("FIXME: relocations to absolute targets " 34343410Snewton "not yet implemented"); 34443410Snewton // the above line stolen from ARM, not sure 34543410Snewton } else { 34643410Snewton // Resolve constant variables. 34743410Snewton if (SD->getSymbol().isVariable()) { 34843410Snewton int64_t Res; 34943410Snewton if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( 350109153Sdillon Res, Layout, Writer->getSectionAddressMap())) { 35143410Snewton FixedValue = Res; 35289306Salfred return; 35389306Salfred } 35489306Salfred } 35589306Salfred 35643410Snewton // Check whether we need an external or internal relocation. 35789306Salfred if (Writer->doesSymbolRequireExternRelocation(SD)) { 35843410Snewton IsExtern = 1; 35943410Snewton Index = SD->getIndex(); 360111119Simp // For external relocations, make sure to offset the fixup value to 36143410Snewton // compensate for the addend of the symbol address, if it was 36243410Snewton // undefined. This occurs with weak definitions, for example. 36343410Snewton if (!SD->getSymbol().isUndefined()) 36443410Snewton FixedValue -= Layout.getSymbolOffset(SD); 36589306Salfred } else { 36689306Salfred // The index is the section ordinal (1-based). 36789306Salfred const MCSectionData &SymSD = 36889306Salfred Asm.getSectionData(SD->getSymbol().getSection()); 36989306Salfred Index = SymSD.getOrdinal() + 1; 37089306Salfred FixedValue += Writer->getSectionAddress(&SymSD); 37189306Salfred } 37289306Salfred if (IsPCRel) 37389306Salfred FixedValue -= Writer->getSectionAddress(Fragment->getParent()); 37489306Salfred } 37589306Salfred 37689306Salfred // struct relocation_info (8 bytes) 37789306Salfred MachO::any_relocation_info MRE; 37843410Snewton makeRelocationInfo(MRE, FixupOffset, Index, IsPCRel, Log2Size, IsExtern, 37943410Snewton Type); 38043410Snewton Writer->addRelocation(Fragment->getParent(), MRE); 38143410Snewton} 38243410Snewton 38343410SnewtonMCObjectWriter *llvm::createPPCMachObjectWriter(raw_ostream &OS, bool Is64Bit, 38443410Snewton uint32_t CPUType, 38543410Snewton uint32_t CPUSubtype) { 38643410Snewton return createMachObjectWriter( 38743410Snewton new PPCMachObjectWriter(Is64Bit, CPUType, CPUSubtype), OS, 388109153Sdillon /*IsLittleEndian=*/false); 38943410Snewton} 39071448Sjhb