1 //===-- PPCXCOFFObjectWriter.cpp - PowerPC XCOFF Writer -------------------===// 2 // 3 // 4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "MCTargetDesc/PPCFixupKinds.h" 11 #include "MCTargetDesc/PPCMCTargetDesc.h" 12 #include "llvm/BinaryFormat/XCOFF.h" 13 #include "llvm/MC/MCFixup.h" 14 #include "llvm/MC/MCValue.h" 15 #include "llvm/MC/MCXCOFFObjectWriter.h" 16 17 using namespace llvm; 18 19 namespace { 20 class PPCXCOFFObjectWriter : public MCXCOFFObjectTargetWriter { 21 static constexpr uint8_t SignBitMask = 0x80; 22 23 public: 24 PPCXCOFFObjectWriter(bool Is64Bit); 25 26 std::pair<uint8_t, uint8_t> 27 getRelocTypeAndSignSize(const MCValue &Target, const MCFixup &Fixup, 28 bool IsPCRel) const override; 29 }; 30 } // end anonymous namespace 31 32 PPCXCOFFObjectWriter::PPCXCOFFObjectWriter(bool Is64Bit) 33 : MCXCOFFObjectTargetWriter(Is64Bit) {} 34 35 std::unique_ptr<MCObjectTargetWriter> 36 llvm::createPPCXCOFFObjectWriter(bool Is64Bit) { 37 return std::make_unique<PPCXCOFFObjectWriter>(Is64Bit); 38 } 39 40 std::pair<uint8_t, uint8_t> PPCXCOFFObjectWriter::getRelocTypeAndSignSize( 41 const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { 42 const MCSymbolRefExpr::VariantKind Modifier = 43 Target.isAbsolute() ? MCSymbolRefExpr::VK_None 44 : Target.getSymA()->getKind(); 45 // People from AIX OS team says AIX link editor does not care about 46 // the sign bit in the relocation entry "most" of the time. 47 // The system assembler seems to set the sign bit on relocation entry 48 // based on similar property of IsPCRel. So we will do the same here. 49 // TODO: More investigation on how assembler decides to set the sign 50 // bit, and we might want to match that. 51 const uint8_t EncodedSignednessIndicator = IsPCRel ? SignBitMask : 0u; 52 53 // The magic number we use in SignAndSize has a strong relationship with 54 // the corresponding MCFixupKind. In most cases, it's the MCFixupKind 55 // number - 1, because SignAndSize encodes the bit length being 56 // relocated minus 1. 57 switch ((unsigned)Fixup.getKind()) { 58 default: 59 report_fatal_error("Unimplemented fixup kind."); 60 case PPC::fixup_ppc_half16: { 61 const uint8_t SignAndSizeForHalf16 = EncodedSignednessIndicator | 15; 62 switch (Modifier) { 63 default: 64 report_fatal_error("Unsupported modifier for half16 fixup."); 65 case MCSymbolRefExpr::VK_None: 66 return {XCOFF::RelocationType::R_TOC, SignAndSizeForHalf16}; 67 case MCSymbolRefExpr::VK_PPC_U: 68 return {XCOFF::RelocationType::R_TOCU, SignAndSizeForHalf16}; 69 case MCSymbolRefExpr::VK_PPC_L: 70 return {XCOFF::RelocationType::R_TOCL, SignAndSizeForHalf16}; 71 case MCSymbolRefExpr::VK_PPC_AIX_TLSLE: 72 return {XCOFF::RelocationType::R_TLS_LE, SignAndSizeForHalf16}; 73 case MCSymbolRefExpr::VK_PPC_AIX_TLSLD: 74 return {XCOFF::RelocationType::R_TLS_LD, SignAndSizeForHalf16}; 75 } 76 } break; 77 case PPC::fixup_ppc_half16ds: 78 case PPC::fixup_ppc_half16dq: { 79 if (IsPCRel) 80 report_fatal_error("Invalid PC-relative relocation."); 81 switch (Modifier) { 82 default: 83 llvm_unreachable("Unsupported Modifier"); 84 case MCSymbolRefExpr::VK_None: 85 return {XCOFF::RelocationType::R_TOC, 15}; 86 case MCSymbolRefExpr::VK_PPC_L: 87 return {XCOFF::RelocationType::R_TOCL, 15}; 88 case MCSymbolRefExpr::VK_PPC_AIX_TLSLE: 89 return {XCOFF::RelocationType::R_TLS_LE, 15}; 90 case MCSymbolRefExpr::VK_PPC_AIX_TLSLD: 91 return {XCOFF::RelocationType::R_TLS_LD, 15}; 92 } 93 } break; 94 case PPC::fixup_ppc_br24: 95 // Branches are 4 byte aligned, so the 24 bits we encode in 96 // the instruction actually represents a 26 bit offset. 97 return {XCOFF::RelocationType::R_RBR, EncodedSignednessIndicator | 25}; 98 case PPC::fixup_ppc_br24abs: 99 return {XCOFF::RelocationType::R_RBA, EncodedSignednessIndicator | 25}; 100 case PPC::fixup_ppc_nofixup: { 101 if (Modifier == MCSymbolRefExpr::VK_None) 102 return {XCOFF::RelocationType::R_REF, 0}; 103 else 104 llvm_unreachable("Unsupported Modifier"); 105 } break; 106 case FK_Data_4: 107 case FK_Data_8: 108 const uint8_t SignAndSizeForFKData = 109 EncodedSignednessIndicator | 110 ((unsigned)Fixup.getKind() == FK_Data_4 ? 31 : 63); 111 switch (Modifier) { 112 default: 113 report_fatal_error("Unsupported modifier"); 114 case MCSymbolRefExpr::VK_PPC_AIX_TLSGD: 115 return {XCOFF::RelocationType::R_TLS, SignAndSizeForFKData}; 116 case MCSymbolRefExpr::VK_PPC_AIX_TLSGDM: 117 return {XCOFF::RelocationType::R_TLSM, SignAndSizeForFKData}; 118 case MCSymbolRefExpr::VK_PPC_AIX_TLSIE: 119 return {XCOFF::RelocationType::R_TLS_IE, SignAndSizeForFKData}; 120 case MCSymbolRefExpr::VK_PPC_AIX_TLSLE: 121 return {XCOFF::RelocationType::R_TLS_LE, SignAndSizeForFKData}; 122 case MCSymbolRefExpr::VK_PPC_AIX_TLSLD: 123 return {XCOFF::RelocationType::R_TLS_LD, SignAndSizeForFKData}; 124 case MCSymbolRefExpr::VK_PPC_AIX_TLSML: 125 return {XCOFF::RelocationType::R_TLSML, SignAndSizeForFKData}; 126 case MCSymbolRefExpr::VK_None: 127 return {XCOFF::RelocationType::R_POS, SignAndSizeForFKData}; 128 } 129 } 130 } 131