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