xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- PPCXCOFFObjectWriter.cpp - PowerPC XCOFF Writer -------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric //
40b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
50b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
60b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
70b57cec5SDimitry Andric //
80b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
90b57cec5SDimitry Andric 
105ffd83dbSDimitry Andric #include "MCTargetDesc/PPCFixupKinds.h"
115ffd83dbSDimitry Andric #include "MCTargetDesc/PPCMCTargetDesc.h"
125ffd83dbSDimitry Andric #include "llvm/BinaryFormat/XCOFF.h"
135ffd83dbSDimitry Andric #include "llvm/MC/MCFixup.h"
145ffd83dbSDimitry Andric #include "llvm/MC/MCFixupKindInfo.h"
155ffd83dbSDimitry Andric #include "llvm/MC/MCValue.h"
160b57cec5SDimitry Andric #include "llvm/MC/MCXCOFFObjectWriter.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric using namespace llvm;
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric namespace {
210b57cec5SDimitry Andric class PPCXCOFFObjectWriter : public MCXCOFFObjectTargetWriter {
225ffd83dbSDimitry Andric   static constexpr uint8_t SignBitMask = 0x80;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric public:
250b57cec5SDimitry Andric   PPCXCOFFObjectWriter(bool Is64Bit);
265ffd83dbSDimitry Andric 
275ffd83dbSDimitry Andric   std::pair<uint8_t, uint8_t>
285ffd83dbSDimitry Andric   getRelocTypeAndSignSize(const MCValue &Target, const MCFixup &Fixup,
295ffd83dbSDimitry Andric                           bool IsPCRel) const override;
300b57cec5SDimitry Andric };
310b57cec5SDimitry Andric } // end anonymous namespace
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric PPCXCOFFObjectWriter::PPCXCOFFObjectWriter(bool Is64Bit)
340b57cec5SDimitry Andric     : MCXCOFFObjectTargetWriter(Is64Bit) {}
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter>
370b57cec5SDimitry Andric llvm::createPPCXCOFFObjectWriter(bool Is64Bit) {
388bcb0991SDimitry Andric   return std::make_unique<PPCXCOFFObjectWriter>(Is64Bit);
390b57cec5SDimitry Andric }
405ffd83dbSDimitry Andric 
415ffd83dbSDimitry Andric std::pair<uint8_t, uint8_t> PPCXCOFFObjectWriter::getRelocTypeAndSignSize(
425ffd83dbSDimitry Andric     const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const {
435ffd83dbSDimitry Andric   const MCSymbolRefExpr::VariantKind Modifier =
445ffd83dbSDimitry Andric       Target.isAbsolute() ? MCSymbolRefExpr::VK_None
455ffd83dbSDimitry Andric                           : Target.getSymA()->getKind();
465ffd83dbSDimitry Andric   // People from AIX OS team says AIX link editor does not care about
475ffd83dbSDimitry Andric   // the sign bit in the relocation entry "most" of the time.
485ffd83dbSDimitry Andric   // The system assembler seems to set the sign bit on relocation entry
495ffd83dbSDimitry Andric   // based on similar property of IsPCRel. So we will do the same here.
505ffd83dbSDimitry Andric   // TODO: More investigation on how assembler decides to set the sign
515ffd83dbSDimitry Andric   // bit, and we might want to match that.
525ffd83dbSDimitry Andric   const uint8_t EncodedSignednessIndicator = IsPCRel ? SignBitMask : 0u;
535ffd83dbSDimitry Andric 
545ffd83dbSDimitry Andric   // The magic number we use in SignAndSize has a strong relationship with
555ffd83dbSDimitry Andric   // the corresponding MCFixupKind. In most cases, it's the MCFixupKind
565ffd83dbSDimitry Andric   // number - 1, because SignAndSize encodes the bit length being
575ffd83dbSDimitry Andric   // relocated minus 1.
585ffd83dbSDimitry Andric   switch ((unsigned)Fixup.getKind()) {
595ffd83dbSDimitry Andric   default:
605ffd83dbSDimitry Andric     report_fatal_error("Unimplemented fixup kind.");
61e8d8bef9SDimitry Andric   case PPC::fixup_ppc_half16: {
62e8d8bef9SDimitry Andric     const uint8_t SignAndSizeForHalf16 = EncodedSignednessIndicator | 15;
635ffd83dbSDimitry Andric     switch (Modifier) {
645ffd83dbSDimitry Andric     default:
655ffd83dbSDimitry Andric       report_fatal_error("Unsupported modifier for half16 fixup.");
665ffd83dbSDimitry Andric     case MCSymbolRefExpr::VK_None:
67e8d8bef9SDimitry Andric       return {XCOFF::RelocationType::R_TOC, SignAndSizeForHalf16};
68e8d8bef9SDimitry Andric     case MCSymbolRefExpr::VK_PPC_U:
69e8d8bef9SDimitry Andric       return {XCOFF::RelocationType::R_TOCU, SignAndSizeForHalf16};
70e8d8bef9SDimitry Andric     case MCSymbolRefExpr::VK_PPC_L:
71e8d8bef9SDimitry Andric       return {XCOFF::RelocationType::R_TOCL, SignAndSizeForHalf16};
725f757f3fSDimitry Andric     case MCSymbolRefExpr::VK_PPC_AIX_TLSLE:
735f757f3fSDimitry Andric       return {XCOFF::RelocationType::R_TLS_LE, SignAndSizeForHalf16};
74*0fca6ea1SDimitry Andric     case MCSymbolRefExpr::VK_PPC_AIX_TLSLD:
75*0fca6ea1SDimitry Andric       return {XCOFF::RelocationType::R_TLS_LD, SignAndSizeForHalf16};
765ffd83dbSDimitry Andric     }
77e8d8bef9SDimitry Andric   } break;
7881ad6265SDimitry Andric   case PPC::fixup_ppc_half16ds:
7981ad6265SDimitry Andric   case PPC::fixup_ppc_half16dq: {
8081ad6265SDimitry Andric     if (IsPCRel)
8181ad6265SDimitry Andric       report_fatal_error("Invalid PC-relative relocation.");
8281ad6265SDimitry Andric     switch (Modifier) {
8381ad6265SDimitry Andric     default:
8481ad6265SDimitry Andric       llvm_unreachable("Unsupported Modifier");
8581ad6265SDimitry Andric     case MCSymbolRefExpr::VK_None:
8681ad6265SDimitry Andric       return {XCOFF::RelocationType::R_TOC, 15};
8781ad6265SDimitry Andric     case MCSymbolRefExpr::VK_PPC_L:
8881ad6265SDimitry Andric       return {XCOFF::RelocationType::R_TOCL, 15};
895f757f3fSDimitry Andric     case MCSymbolRefExpr::VK_PPC_AIX_TLSLE:
905f757f3fSDimitry Andric       return {XCOFF::RelocationType::R_TLS_LE, 15};
91*0fca6ea1SDimitry Andric     case MCSymbolRefExpr::VK_PPC_AIX_TLSLD:
92*0fca6ea1SDimitry Andric       return {XCOFF::RelocationType::R_TLS_LD, 15};
9381ad6265SDimitry Andric     }
9481ad6265SDimitry Andric   } break;
955ffd83dbSDimitry Andric   case PPC::fixup_ppc_br24:
965ffd83dbSDimitry Andric     // Branches are 4 byte aligned, so the 24 bits we encode in
975ffd83dbSDimitry Andric     // the instruction actually represents a 26 bit offset.
985ffd83dbSDimitry Andric     return {XCOFF::RelocationType::R_RBR, EncodedSignednessIndicator | 25};
99fe6060f1SDimitry Andric   case PPC::fixup_ppc_br24abs:
100fe6060f1SDimitry Andric     return {XCOFF::RelocationType::R_RBA, EncodedSignednessIndicator | 25};
10106c3fb27SDimitry Andric   case PPC::fixup_ppc_nofixup: {
10206c3fb27SDimitry Andric     if (Modifier == MCSymbolRefExpr::VK_None)
10306c3fb27SDimitry Andric       return {XCOFF::RelocationType::R_REF, 0};
10406c3fb27SDimitry Andric     else
10506c3fb27SDimitry Andric       llvm_unreachable("Unsupported Modifier");
10606c3fb27SDimitry Andric   } break;
1075ffd83dbSDimitry Andric   case FK_Data_4:
10881ad6265SDimitry Andric   case FK_Data_8:
10981ad6265SDimitry Andric     const uint8_t SignAndSizeForFKData =
11081ad6265SDimitry Andric         EncodedSignednessIndicator |
11181ad6265SDimitry Andric         ((unsigned)Fixup.getKind() == FK_Data_4 ? 31 : 63);
112fe6060f1SDimitry Andric     switch (Modifier) {
113fe6060f1SDimitry Andric     default:
114fe6060f1SDimitry Andric       report_fatal_error("Unsupported modifier");
115fe6060f1SDimitry Andric     case MCSymbolRefExpr::VK_PPC_AIX_TLSGD:
11681ad6265SDimitry Andric       return {XCOFF::RelocationType::R_TLS, SignAndSizeForFKData};
117fe6060f1SDimitry Andric     case MCSymbolRefExpr::VK_PPC_AIX_TLSGDM:
11881ad6265SDimitry Andric       return {XCOFF::RelocationType::R_TLSM, SignAndSizeForFKData};
1195f757f3fSDimitry Andric     case MCSymbolRefExpr::VK_PPC_AIX_TLSIE:
1205f757f3fSDimitry Andric       return {XCOFF::RelocationType::R_TLS_IE, SignAndSizeForFKData};
12106c3fb27SDimitry Andric     case MCSymbolRefExpr::VK_PPC_AIX_TLSLE:
12206c3fb27SDimitry Andric       return {XCOFF::RelocationType::R_TLS_LE, SignAndSizeForFKData};
123*0fca6ea1SDimitry Andric     case MCSymbolRefExpr::VK_PPC_AIX_TLSLD:
124*0fca6ea1SDimitry Andric       return {XCOFF::RelocationType::R_TLS_LD, SignAndSizeForFKData};
125*0fca6ea1SDimitry Andric     case MCSymbolRefExpr::VK_PPC_AIX_TLSML:
126*0fca6ea1SDimitry Andric       return {XCOFF::RelocationType::R_TLSML, SignAndSizeForFKData};
127fe6060f1SDimitry Andric     case MCSymbolRefExpr::VK_None:
12881ad6265SDimitry Andric       return {XCOFF::RelocationType::R_POS, SignAndSizeForFKData};
1295ffd83dbSDimitry Andric     }
1305ffd83dbSDimitry Andric   }
131fe6060f1SDimitry Andric }
132