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/MCFixupKindInfo.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>(args&: Is64Bit); |
39 | } |
40 | |
41 | std::pair<uint8_t, uint8_t> PPCXCOFFObjectWriter::getRelocTypeAndSignSize( |
42 | const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { |
43 | const MCSymbolRefExpr::VariantKind Modifier = |
44 | Target.isAbsolute() ? MCSymbolRefExpr::VK_None |
45 | : Target.getSymA()->getKind(); |
46 | // People from AIX OS team says AIX link editor does not care about |
47 | // the sign bit in the relocation entry "most" of the time. |
48 | // The system assembler seems to set the sign bit on relocation entry |
49 | // based on similar property of IsPCRel. So we will do the same here. |
50 | // TODO: More investigation on how assembler decides to set the sign |
51 | // bit, and we might want to match that. |
52 | const uint8_t EncodedSignednessIndicator = IsPCRel ? SignBitMask : 0u; |
53 | |
54 | // The magic number we use in SignAndSize has a strong relationship with |
55 | // the corresponding MCFixupKind. In most cases, it's the MCFixupKind |
56 | // number - 1, because SignAndSize encodes the bit length being |
57 | // relocated minus 1. |
58 | switch ((unsigned)Fixup.getKind()) { |
59 | default: |
60 | report_fatal_error(reason: "Unimplemented fixup kind." ); |
61 | case PPC::fixup_ppc_half16: { |
62 | const uint8_t SignAndSizeForHalf16 = EncodedSignednessIndicator | 15; |
63 | switch (Modifier) { |
64 | default: |
65 | report_fatal_error(reason: "Unsupported modifier for half16 fixup." ); |
66 | case MCSymbolRefExpr::VK_None: |
67 | return {XCOFF::RelocationType::R_TOC, SignAndSizeForHalf16}; |
68 | case MCSymbolRefExpr::VK_PPC_U: |
69 | return {XCOFF::RelocationType::R_TOCU, SignAndSizeForHalf16}; |
70 | case MCSymbolRefExpr::VK_PPC_L: |
71 | return {XCOFF::RelocationType::R_TOCL, SignAndSizeForHalf16}; |
72 | case MCSymbolRefExpr::VK_PPC_AIX_TLSLE: |
73 | return {XCOFF::RelocationType::R_TLS_LE, SignAndSizeForHalf16}; |
74 | case MCSymbolRefExpr::VK_PPC_AIX_TLSLD: |
75 | return {XCOFF::RelocationType::R_TLS_LD, SignAndSizeForHalf16}; |
76 | } |
77 | } break; |
78 | case PPC::fixup_ppc_half16ds: |
79 | case PPC::fixup_ppc_half16dq: { |
80 | if (IsPCRel) |
81 | report_fatal_error(reason: "Invalid PC-relative relocation." ); |
82 | switch (Modifier) { |
83 | default: |
84 | llvm_unreachable("Unsupported Modifier" ); |
85 | case MCSymbolRefExpr::VK_None: |
86 | return {XCOFF::RelocationType::R_TOC, 15}; |
87 | case MCSymbolRefExpr::VK_PPC_L: |
88 | return {XCOFF::RelocationType::R_TOCL, 15}; |
89 | case MCSymbolRefExpr::VK_PPC_AIX_TLSLE: |
90 | return {XCOFF::RelocationType::R_TLS_LE, 15}; |
91 | case MCSymbolRefExpr::VK_PPC_AIX_TLSLD: |
92 | return {XCOFF::RelocationType::R_TLS_LD, 15}; |
93 | } |
94 | } break; |
95 | case PPC::fixup_ppc_br24: |
96 | // Branches are 4 byte aligned, so the 24 bits we encode in |
97 | // the instruction actually represents a 26 bit offset. |
98 | return {XCOFF::RelocationType::R_RBR, EncodedSignednessIndicator | 25}; |
99 | case PPC::fixup_ppc_br24abs: |
100 | return {XCOFF::RelocationType::R_RBA, EncodedSignednessIndicator | 25}; |
101 | case PPC::fixup_ppc_nofixup: { |
102 | if (Modifier == MCSymbolRefExpr::VK_None) |
103 | return {XCOFF::RelocationType::R_REF, 0}; |
104 | else |
105 | llvm_unreachable("Unsupported Modifier" ); |
106 | } break; |
107 | case FK_Data_4: |
108 | case FK_Data_8: |
109 | const uint8_t SignAndSizeForFKData = |
110 | EncodedSignednessIndicator | |
111 | ((unsigned)Fixup.getKind() == FK_Data_4 ? 31 : 63); |
112 | switch (Modifier) { |
113 | default: |
114 | report_fatal_error(reason: "Unsupported modifier" ); |
115 | case MCSymbolRefExpr::VK_PPC_AIX_TLSGD: |
116 | return {XCOFF::RelocationType::R_TLS, SignAndSizeForFKData}; |
117 | case MCSymbolRefExpr::VK_PPC_AIX_TLSGDM: |
118 | return {XCOFF::RelocationType::R_TLSM, SignAndSizeForFKData}; |
119 | case MCSymbolRefExpr::VK_PPC_AIX_TLSIE: |
120 | return {XCOFF::RelocationType::R_TLS_IE, SignAndSizeForFKData}; |
121 | case MCSymbolRefExpr::VK_PPC_AIX_TLSLE: |
122 | return {XCOFF::RelocationType::R_TLS_LE, SignAndSizeForFKData}; |
123 | case MCSymbolRefExpr::VK_PPC_AIX_TLSLD: |
124 | return {XCOFF::RelocationType::R_TLS_LD, SignAndSizeForFKData}; |
125 | case MCSymbolRefExpr::VK_PPC_AIX_TLSML: |
126 | return {XCOFF::RelocationType::R_TLSML, SignAndSizeForFKData}; |
127 | case MCSymbolRefExpr::VK_None: |
128 | return {XCOFF::RelocationType::R_POS, SignAndSizeForFKData}; |
129 | } |
130 | } |
131 | } |
132 | |