1f09d54edSSean Fertile //===-- PPCXCOFFObjectWriter.cpp - PowerPC XCOFF Writer -------------------===//
2f09d54edSSean Fertile //
3f09d54edSSean Fertile //
4f09d54edSSean Fertile // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5f09d54edSSean Fertile // See https://llvm.org/LICENSE.txt for license information.
6f09d54edSSean Fertile // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7f09d54edSSean Fertile //
8f09d54edSSean Fertile //===----------------------------------------------------------------------===//
9f09d54edSSean Fertile 
103bbe7a68Sjasonliu #include "MCTargetDesc/PPCFixupKinds.h"
113bbe7a68Sjasonliu #include "MCTargetDesc/PPCMCTargetDesc.h"
123bbe7a68Sjasonliu #include "llvm/BinaryFormat/XCOFF.h"
133bbe7a68Sjasonliu #include "llvm/MC/MCFixup.h"
143bbe7a68Sjasonliu #include "llvm/MC/MCFixupKindInfo.h"
153bbe7a68Sjasonliu #include "llvm/MC/MCValue.h"
16f09d54edSSean Fertile #include "llvm/MC/MCXCOFFObjectWriter.h"
17f09d54edSSean Fertile 
18f09d54edSSean Fertile using namespace llvm;
19f09d54edSSean Fertile 
20f09d54edSSean Fertile namespace {
21f09d54edSSean Fertile class PPCXCOFFObjectWriter : public MCXCOFFObjectTargetWriter {
223bbe7a68Sjasonliu   static constexpr uint8_t SignBitMask = 0x80;
23f09d54edSSean Fertile 
24f09d54edSSean Fertile public:
25f09d54edSSean Fertile   PPCXCOFFObjectWriter(bool Is64Bit);
263bbe7a68Sjasonliu 
273bbe7a68Sjasonliu   std::pair<uint8_t, uint8_t>
283bbe7a68Sjasonliu   getRelocTypeAndSignSize(const MCValue &Target, const MCFixup &Fixup,
293bbe7a68Sjasonliu                           bool IsPCRel) const override;
30f09d54edSSean Fertile };
31f09d54edSSean Fertile } // end anonymous namespace
32f09d54edSSean Fertile 
PPCXCOFFObjectWriter(bool Is64Bit)33f09d54edSSean Fertile PPCXCOFFObjectWriter::PPCXCOFFObjectWriter(bool Is64Bit)
34f09d54edSSean Fertile     : MCXCOFFObjectTargetWriter(Is64Bit) {}
35f09d54edSSean Fertile 
36f09d54edSSean Fertile std::unique_ptr<MCObjectTargetWriter>
createPPCXCOFFObjectWriter(bool Is64Bit)37f09d54edSSean Fertile llvm::createPPCXCOFFObjectWriter(bool Is64Bit) {
380eaee545SJonas Devlieghere   return std::make_unique<PPCXCOFFObjectWriter>(Is64Bit);
39f09d54edSSean Fertile }
403bbe7a68Sjasonliu 
getRelocTypeAndSignSize(const MCValue & Target,const MCFixup & Fixup,bool IsPCRel) const413bbe7a68Sjasonliu std::pair<uint8_t, uint8_t> PPCXCOFFObjectWriter::getRelocTypeAndSignSize(
423bbe7a68Sjasonliu     const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const {
433bbe7a68Sjasonliu   const MCSymbolRefExpr::VariantKind Modifier =
443bbe7a68Sjasonliu       Target.isAbsolute() ? MCSymbolRefExpr::VK_None
453bbe7a68Sjasonliu                           : Target.getSymA()->getKind();
463bbe7a68Sjasonliu   // People from AIX OS team says AIX link editor does not care about
473bbe7a68Sjasonliu   // the sign bit in the relocation entry "most" of the time.
483bbe7a68Sjasonliu   // The system assembler seems to set the sign bit on relocation entry
493bbe7a68Sjasonliu   // based on similar property of IsPCRel. So we will do the same here.
503bbe7a68Sjasonliu   // TODO: More investigation on how assembler decides to set the sign
513bbe7a68Sjasonliu   // bit, and we might want to match that.
523bbe7a68Sjasonliu   const uint8_t EncodedSignednessIndicator = IsPCRel ? SignBitMask : 0u;
533bbe7a68Sjasonliu 
543bbe7a68Sjasonliu   // The magic number we use in SignAndSize has a strong relationship with
553bbe7a68Sjasonliu   // the corresponding MCFixupKind. In most cases, it's the MCFixupKind
563bbe7a68Sjasonliu   // number - 1, because SignAndSize encodes the bit length being
573bbe7a68Sjasonliu   // relocated minus 1.
583bbe7a68Sjasonliu   switch ((unsigned)Fixup.getKind()) {
593bbe7a68Sjasonliu   default:
603bbe7a68Sjasonliu     report_fatal_error("Unimplemented fixup kind.");
6141305440Sjasonliu   case PPC::fixup_ppc_half16: {
6241305440Sjasonliu     const uint8_t SignAndSizeForHalf16 = EncodedSignednessIndicator | 15;
633bbe7a68Sjasonliu     switch (Modifier) {
643bbe7a68Sjasonliu     default:
653bbe7a68Sjasonliu       report_fatal_error("Unsupported modifier for half16 fixup.");
663bbe7a68Sjasonliu     case MCSymbolRefExpr::VK_None:
6741305440Sjasonliu       return {XCOFF::RelocationType::R_TOC, SignAndSizeForHalf16};
6841305440Sjasonliu     case MCSymbolRefExpr::VK_PPC_U:
6941305440Sjasonliu       return {XCOFF::RelocationType::R_TOCU, SignAndSizeForHalf16};
7041305440Sjasonliu     case MCSymbolRefExpr::VK_PPC_L:
7141305440Sjasonliu       return {XCOFF::RelocationType::R_TOCL, SignAndSizeForHalf16};
723bbe7a68Sjasonliu     }
7341305440Sjasonliu   } break;
74*8d6e2c3eSesmeyi   case PPC::fixup_ppc_half16ds:
75*8d6e2c3eSesmeyi   case PPC::fixup_ppc_half16dq: {
76*8d6e2c3eSesmeyi     if (IsPCRel)
77*8d6e2c3eSesmeyi       report_fatal_error("Invalid PC-relative relocation.");
78*8d6e2c3eSesmeyi     switch (Modifier) {
79*8d6e2c3eSesmeyi     default:
80*8d6e2c3eSesmeyi       llvm_unreachable("Unsupported Modifier");
81*8d6e2c3eSesmeyi     case MCSymbolRefExpr::VK_None:
82*8d6e2c3eSesmeyi       return {XCOFF::RelocationType::R_TOC, 15};
83*8d6e2c3eSesmeyi     case MCSymbolRefExpr::VK_PPC_L:
84*8d6e2c3eSesmeyi       return {XCOFF::RelocationType::R_TOCL, 15};
85*8d6e2c3eSesmeyi     }
86*8d6e2c3eSesmeyi   } break;
873bbe7a68Sjasonliu   case PPC::fixup_ppc_br24:
883bbe7a68Sjasonliu     // Branches are 4 byte aligned, so the 24 bits we encode in
893bbe7a68Sjasonliu     // the instruction actually represents a 26 bit offset.
903bbe7a68Sjasonliu     return {XCOFF::RelocationType::R_RBR, EncodedSignednessIndicator | 25};
91bb113b98SVictor Huang   case PPC::fixup_ppc_br24abs:
92bb113b98SVictor Huang     return {XCOFF::RelocationType::R_RBA, EncodedSignednessIndicator | 25};
933bbe7a68Sjasonliu   case FK_Data_4:
94*8d6e2c3eSesmeyi   case FK_Data_8:
95*8d6e2c3eSesmeyi     const uint8_t SignAndSizeForFKData =
96*8d6e2c3eSesmeyi         EncodedSignednessIndicator |
97*8d6e2c3eSesmeyi         ((unsigned)Fixup.getKind() == FK_Data_4 ? 31 : 63);
98bb113b98SVictor Huang     switch (Modifier) {
99bb113b98SVictor Huang     default:
100bb113b98SVictor Huang       report_fatal_error("Unsupported modifier");
101bb113b98SVictor Huang     case MCSymbolRefExpr::VK_PPC_AIX_TLSGD:
102*8d6e2c3eSesmeyi       return {XCOFF::RelocationType::R_TLS, SignAndSizeForFKData};
103bb113b98SVictor Huang     case MCSymbolRefExpr::VK_PPC_AIX_TLSGDM:
104*8d6e2c3eSesmeyi       return {XCOFF::RelocationType::R_TLSM, SignAndSizeForFKData};
105bb113b98SVictor Huang     case MCSymbolRefExpr::VK_None:
106*8d6e2c3eSesmeyi       return {XCOFF::RelocationType::R_POS, SignAndSizeForFKData};
1073bbe7a68Sjasonliu     }
1083bbe7a68Sjasonliu   }
109bb113b98SVictor Huang }
110