106f32e7eSjoerg //===-- PPCXCOFFObjectWriter.cpp - PowerPC XCOFF Writer -------------------===//
206f32e7eSjoerg //
306f32e7eSjoerg //
406f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
506f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
606f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
706f32e7eSjoerg //
806f32e7eSjoerg //===----------------------------------------------------------------------===//
906f32e7eSjoerg 
10*da58b97aSjoerg #include "MCTargetDesc/PPCFixupKinds.h"
11*da58b97aSjoerg #include "MCTargetDesc/PPCMCTargetDesc.h"
12*da58b97aSjoerg #include "llvm/BinaryFormat/XCOFF.h"
13*da58b97aSjoerg #include "llvm/MC/MCFixup.h"
14*da58b97aSjoerg #include "llvm/MC/MCFixupKindInfo.h"
15*da58b97aSjoerg #include "llvm/MC/MCValue.h"
1606f32e7eSjoerg #include "llvm/MC/MCXCOFFObjectWriter.h"
1706f32e7eSjoerg 
1806f32e7eSjoerg using namespace llvm;
1906f32e7eSjoerg 
2006f32e7eSjoerg namespace {
2106f32e7eSjoerg class PPCXCOFFObjectWriter : public MCXCOFFObjectTargetWriter {
22*da58b97aSjoerg   static constexpr uint8_t SignBitMask = 0x80;
2306f32e7eSjoerg 
2406f32e7eSjoerg public:
2506f32e7eSjoerg   PPCXCOFFObjectWriter(bool Is64Bit);
26*da58b97aSjoerg 
27*da58b97aSjoerg   std::pair<uint8_t, uint8_t>
28*da58b97aSjoerg   getRelocTypeAndSignSize(const MCValue &Target, const MCFixup &Fixup,
29*da58b97aSjoerg                           bool IsPCRel) const override;
3006f32e7eSjoerg };
3106f32e7eSjoerg } // end anonymous namespace
3206f32e7eSjoerg 
PPCXCOFFObjectWriter(bool Is64Bit)3306f32e7eSjoerg PPCXCOFFObjectWriter::PPCXCOFFObjectWriter(bool Is64Bit)
3406f32e7eSjoerg     : MCXCOFFObjectTargetWriter(Is64Bit) {}
3506f32e7eSjoerg 
3606f32e7eSjoerg std::unique_ptr<MCObjectTargetWriter>
createPPCXCOFFObjectWriter(bool Is64Bit)3706f32e7eSjoerg llvm::createPPCXCOFFObjectWriter(bool Is64Bit) {
3806f32e7eSjoerg   return std::make_unique<PPCXCOFFObjectWriter>(Is64Bit);
3906f32e7eSjoerg }
40*da58b97aSjoerg 
getRelocTypeAndSignSize(const MCValue & Target,const MCFixup & Fixup,bool IsPCRel) const41*da58b97aSjoerg std::pair<uint8_t, uint8_t> PPCXCOFFObjectWriter::getRelocTypeAndSignSize(
42*da58b97aSjoerg     const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const {
43*da58b97aSjoerg   const MCSymbolRefExpr::VariantKind Modifier =
44*da58b97aSjoerg       Target.isAbsolute() ? MCSymbolRefExpr::VK_None
45*da58b97aSjoerg                           : Target.getSymA()->getKind();
46*da58b97aSjoerg   // People from AIX OS team says AIX link editor does not care about
47*da58b97aSjoerg   // the sign bit in the relocation entry "most" of the time.
48*da58b97aSjoerg   // The system assembler seems to set the sign bit on relocation entry
49*da58b97aSjoerg   // based on similar property of IsPCRel. So we will do the same here.
50*da58b97aSjoerg   // TODO: More investigation on how assembler decides to set the sign
51*da58b97aSjoerg   // bit, and we might want to match that.
52*da58b97aSjoerg   const uint8_t EncodedSignednessIndicator = IsPCRel ? SignBitMask : 0u;
53*da58b97aSjoerg 
54*da58b97aSjoerg   // The magic number we use in SignAndSize has a strong relationship with
55*da58b97aSjoerg   // the corresponding MCFixupKind. In most cases, it's the MCFixupKind
56*da58b97aSjoerg   // number - 1, because SignAndSize encodes the bit length being
57*da58b97aSjoerg   // relocated minus 1.
58*da58b97aSjoerg   switch ((unsigned)Fixup.getKind()) {
59*da58b97aSjoerg   default:
60*da58b97aSjoerg     report_fatal_error("Unimplemented fixup kind.");
61*da58b97aSjoerg   case PPC::fixup_ppc_half16: {
62*da58b97aSjoerg     const uint8_t SignAndSizeForHalf16 = EncodedSignednessIndicator | 15;
63*da58b97aSjoerg     switch (Modifier) {
64*da58b97aSjoerg     default:
65*da58b97aSjoerg       report_fatal_error("Unsupported modifier for half16 fixup.");
66*da58b97aSjoerg     case MCSymbolRefExpr::VK_None:
67*da58b97aSjoerg       return {XCOFF::RelocationType::R_TOC, SignAndSizeForHalf16};
68*da58b97aSjoerg     case MCSymbolRefExpr::VK_PPC_U:
69*da58b97aSjoerg       return {XCOFF::RelocationType::R_TOCU, SignAndSizeForHalf16};
70*da58b97aSjoerg     case MCSymbolRefExpr::VK_PPC_L:
71*da58b97aSjoerg       return {XCOFF::RelocationType::R_TOCL, SignAndSizeForHalf16};
72*da58b97aSjoerg     }
73*da58b97aSjoerg   } break;
74*da58b97aSjoerg   case PPC::fixup_ppc_br24:
75*da58b97aSjoerg     // Branches are 4 byte aligned, so the 24 bits we encode in
76*da58b97aSjoerg     // the instruction actually represents a 26 bit offset.
77*da58b97aSjoerg     return {XCOFF::RelocationType::R_RBR, EncodedSignednessIndicator | 25};
78*da58b97aSjoerg   case PPC::fixup_ppc_br24abs:
79*da58b97aSjoerg     return {XCOFF::RelocationType::R_RBA, EncodedSignednessIndicator | 25};
80*da58b97aSjoerg   case FK_Data_4:
81*da58b97aSjoerg     switch (Modifier) {
82*da58b97aSjoerg     default:
83*da58b97aSjoerg       report_fatal_error("Unsupported modifier");
84*da58b97aSjoerg     case MCSymbolRefExpr::VK_PPC_AIX_TLSGD:
85*da58b97aSjoerg       return {XCOFF::RelocationType::R_TLS, EncodedSignednessIndicator | 31};
86*da58b97aSjoerg     case MCSymbolRefExpr::VK_PPC_AIX_TLSGDM:
87*da58b97aSjoerg       return {XCOFF::RelocationType::R_TLSM, EncodedSignednessIndicator | 31};
88*da58b97aSjoerg     case MCSymbolRefExpr::VK_None:
89*da58b97aSjoerg       return {XCOFF::RelocationType::R_POS, EncodedSignednessIndicator | 31};
90*da58b97aSjoerg     }
91*da58b97aSjoerg   }
92*da58b97aSjoerg }
93