1 | //===-------- PPCELFStreamer.cpp - ELF Object Output ---------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This is a custom MCELFStreamer for PowerPC. |
10 | // |
11 | // The purpose of the custom ELF streamer is to allow us to intercept |
12 | // instructions as they are being emitted and align all 8 byte instructions |
13 | // to a 64 byte boundary if required (by adding a 4 byte nop). This is important |
14 | // because 8 byte instructions are not allowed to cross 64 byte boundaries |
15 | // and by aliging anything that is within 4 bytes of the boundary we can |
16 | // guarantee that the 8 byte instructions do not cross that boundary. |
17 | // |
18 | //===----------------------------------------------------------------------===// |
19 | |
20 | #include "PPCELFStreamer.h" |
21 | #include "PPCFixupKinds.h" |
22 | #include "PPCMCCodeEmitter.h" |
23 | #include "PPCMCTargetDesc.h" |
24 | #include "llvm/BinaryFormat/ELF.h" |
25 | #include "llvm/MC/MCAsmBackend.h" |
26 | #include "llvm/MC/MCAssembler.h" |
27 | #include "llvm/MC/MCCodeEmitter.h" |
28 | #include "llvm/MC/MCContext.h" |
29 | #include "llvm/MC/MCInst.h" |
30 | #include "llvm/MC/MCInstrDesc.h" |
31 | #include "llvm/MC/MCObjectWriter.h" |
32 | #include "llvm/MC/MCSymbolELF.h" |
33 | #include "llvm/Support/Casting.h" |
34 | #include "llvm/Support/SourceMgr.h" |
35 | |
36 | using namespace llvm; |
37 | |
38 | PPCELFStreamer::PPCELFStreamer(MCContext &Context, |
39 | std::unique_ptr<MCAsmBackend> MAB, |
40 | std::unique_ptr<MCObjectWriter> OW, |
41 | std::unique_ptr<MCCodeEmitter> Emitter) |
42 | : MCELFStreamer(Context, std::move(MAB), std::move(OW), std::move(Emitter)), |
43 | LastLabel(nullptr) {} |
44 | |
45 | void PPCELFStreamer::emitPrefixedInstruction(const MCInst &Inst, |
46 | const MCSubtargetInfo &STI) { |
47 | // Prefixed instructions must not cross a 64-byte boundary (i.e. prefix is |
48 | // before the boundary and the remaining 4-bytes are after the boundary). In |
49 | // order to achieve this, a nop is added prior to any such boundary-crossing |
50 | // prefixed instruction. Align to 64 bytes if possible but add a maximum of 4 |
51 | // bytes when trying to do that. If alignment requires adding more than 4 |
52 | // bytes then the instruction won't be aligned. When emitting a code alignment |
53 | // a new fragment is created for this alignment. This fragment will contain |
54 | // all of the nops required as part of the alignment operation. In the cases |
55 | // when no nops are added then The fragment is still created but it remains |
56 | // empty. |
57 | emitCodeAlignment(ByteAlignment: Align(64), STI: &STI, MaxBytesToEmit: 4); |
58 | |
59 | // Emit the instruction. |
60 | // Since the previous emit created a new fragment then adding this instruction |
61 | // also forces the addition of a new fragment. Inst is now the first |
62 | // instruction in that new fragment. |
63 | MCELFStreamer::emitInstruction(Inst, STI); |
64 | |
65 | // The above instruction is forced to start a new fragment because it |
66 | // comes after a code alignment fragment. Get that new fragment. |
67 | MCFragment *InstructionFragment = getCurrentFragment(); |
68 | SMLoc InstLoc = Inst.getLoc(); |
69 | // Check if there was a last label emitted. |
70 | if (LastLabel && !LastLabel->isUnset() && LastLabelLoc.isValid() && |
71 | InstLoc.isValid()) { |
72 | const SourceMgr *SourceManager = getContext().getSourceManager(); |
73 | unsigned InstLine = SourceManager->FindLineNumber(Loc: InstLoc); |
74 | unsigned LabelLine = SourceManager->FindLineNumber(Loc: LastLabelLoc); |
75 | // If the Label and the Instruction are on the same line then move the |
76 | // label to the top of the fragment containing the aligned instruction that |
77 | // was just added. |
78 | if (InstLine == LabelLine) { |
79 | LastLabel->setFragment(InstructionFragment); |
80 | LastLabel->setOffset(0); |
81 | } |
82 | } |
83 | } |
84 | |
85 | void PPCELFStreamer::emitInstruction(const MCInst &Inst, |
86 | const MCSubtargetInfo &STI) { |
87 | PPCMCCodeEmitter *Emitter = |
88 | static_cast<PPCMCCodeEmitter*>(getAssembler().getEmitterPtr()); |
89 | |
90 | // If the instruction is a part of the GOT to PC-Rel link time optimization |
91 | // instruction pair, return a value, otherwise return std::nullopt. A true |
92 | // returned value means the instruction is the PLDpc and a false value means |
93 | // it is the user instruction. |
94 | std::optional<bool> IsPartOfGOTToPCRelPair = |
95 | isPartOfGOTToPCRelPair(Inst, STI); |
96 | |
97 | // User of the GOT-indirect address. |
98 | // For example, the load that will get the relocation as follows: |
99 | // .reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8) |
100 | // lwa 3, 4(3) |
101 | if (IsPartOfGOTToPCRelPair && !*IsPartOfGOTToPCRelPair) |
102 | emitGOTToPCRelReloc(Inst); |
103 | |
104 | // Special handling is only for prefixed instructions. |
105 | if (!Emitter->isPrefixedInstruction(MI: Inst)) { |
106 | MCELFStreamer::emitInstruction(Inst, STI); |
107 | return; |
108 | } |
109 | emitPrefixedInstruction(Inst, STI); |
110 | |
111 | // Producer of the GOT-indirect address. |
112 | // For example, the prefixed load from the got that will get the label as |
113 | // follows: |
114 | // pld 3, vec@got@pcrel(0), 1 |
115 | // .Lpcrel1: |
116 | if (IsPartOfGOTToPCRelPair && *IsPartOfGOTToPCRelPair) |
117 | emitGOTToPCRelLabel(Inst); |
118 | } |
119 | |
120 | void PPCELFStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) { |
121 | LastLabel = Symbol; |
122 | LastLabelLoc = Loc; |
123 | MCELFStreamer::emitLabel(Symbol); |
124 | } |
125 | |
126 | // This linker time GOT PC Relative optimization relocation will look like this: |
127 | // pld <reg> symbol@got@pcrel |
128 | // <Label###>: |
129 | // .reloc Label###-8,R_PPC64_PCREL_OPT,.-(Label###-8) |
130 | // load <loadedreg>, 0(<reg>) |
131 | // The reason we place the label after the PLDpc instruction is that there |
132 | // may be an alignment nop before it since prefixed instructions must not |
133 | // cross a 64-byte boundary (please see |
134 | // PPCELFStreamer::emitPrefixedInstruction()). When referring to the |
135 | // label, we subtract the width of a prefixed instruction (8 bytes) to ensure |
136 | // we refer to the PLDpc. |
137 | void PPCELFStreamer::emitGOTToPCRelReloc(const MCInst &Inst) { |
138 | // Get the last operand which contains the symbol. |
139 | const MCOperand &Operand = Inst.getOperand(i: Inst.getNumOperands() - 1); |
140 | assert(Operand.isExpr() && "Expecting an MCExpr." ); |
141 | // Cast the last operand to MCSymbolRefExpr to get the symbol. |
142 | const MCExpr *Expr = Operand.getExpr(); |
143 | const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr); |
144 | assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT && |
145 | "Expecting a symbol of type VK_PPC_PCREL_OPT" ); |
146 | MCSymbol *LabelSym = |
147 | getContext().getOrCreateSymbol(Name: SymExpr->getSymbol().getName()); |
148 | const MCExpr *LabelExpr = MCSymbolRefExpr::create(Symbol: LabelSym, Ctx&: getContext()); |
149 | const MCExpr *Eight = MCConstantExpr::create(Value: 8, Ctx&: getContext()); |
150 | // SubExpr is just Label###-8 |
151 | const MCExpr *SubExpr = |
152 | MCBinaryExpr::createSub(LHS: LabelExpr, RHS: Eight, Ctx&: getContext()); |
153 | MCSymbol *CurrentLocation = getContext().createTempSymbol(); |
154 | const MCExpr *CurrentLocationExpr = |
155 | MCSymbolRefExpr::create(Symbol: CurrentLocation, Ctx&: getContext()); |
156 | // SubExpr2 is .-(Label###-8) |
157 | const MCExpr *SubExpr2 = |
158 | MCBinaryExpr::createSub(LHS: CurrentLocationExpr, RHS: SubExpr, Ctx&: getContext()); |
159 | |
160 | MCDataFragment *DF = static_cast<MCDataFragment *>(LabelSym->getFragment()); |
161 | assert(DF && "Expecting a valid data fragment." ); |
162 | MCFixupKind FixupKind = static_cast<MCFixupKind>(FirstLiteralRelocationKind + |
163 | ELF::R_PPC64_PCREL_OPT); |
164 | DF->getFixups().push_back( |
165 | Elt: MCFixup::create(Offset: LabelSym->getOffset() - 8, Value: SubExpr2, |
166 | Kind: FixupKind, Loc: Inst.getLoc())); |
167 | emitLabel(Symbol: CurrentLocation, Loc: Inst.getLoc()); |
168 | } |
169 | |
170 | // Emit the label that immediately follows the PLDpc for a link time GOT PC Rel |
171 | // optimization. |
172 | void PPCELFStreamer::emitGOTToPCRelLabel(const MCInst &Inst) { |
173 | // Get the last operand which contains the symbol. |
174 | const MCOperand &Operand = Inst.getOperand(i: Inst.getNumOperands() - 1); |
175 | assert(Operand.isExpr() && "Expecting an MCExpr." ); |
176 | // Cast the last operand to MCSymbolRefExpr to get the symbol. |
177 | const MCExpr *Expr = Operand.getExpr(); |
178 | const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr); |
179 | assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT && |
180 | "Expecting a symbol of type VK_PPC_PCREL_OPT" ); |
181 | MCSymbol *LabelSym = |
182 | getContext().getOrCreateSymbol(Name: SymExpr->getSymbol().getName()); |
183 | emitLabel(Symbol: LabelSym, Loc: Inst.getLoc()); |
184 | } |
185 | |
186 | // This function checks if the parameter Inst is part of the setup for a link |
187 | // time GOT PC Relative optimization. For example in this situation: |
188 | // <MCInst PLDpc <MCOperand Reg:282> <MCOperand Expr:(glob_double@got@pcrel)> |
189 | // <MCOperand Imm:0> <MCOperand Expr:(.Lpcrel@<<invalid>>)>> |
190 | // <MCInst SOME_LOAD <MCOperand Reg:22> <MCOperand Imm:0> <MCOperand Reg:282> |
191 | // <MCOperand Expr:(.Lpcrel@<<invalid>>)>> |
192 | // The above is a pair of such instructions and this function will not return |
193 | // std::nullopt for either one of them. In both cases we are looking for the |
194 | // last operand <MCOperand Expr:(.Lpcrel@<<invalid>>)> which needs to be an |
195 | // MCExpr and has the flag MCSymbolRefExpr::VK_PPC_PCREL_OPT. After that we just |
196 | // look at the opcode and in the case of PLDpc we will return true. For the load |
197 | // (or store) this function will return false indicating it has found the second |
198 | // instruciton in the pair. |
199 | std::optional<bool> llvm::isPartOfGOTToPCRelPair(const MCInst &Inst, |
200 | const MCSubtargetInfo &STI) { |
201 | // Need at least two operands. |
202 | if (Inst.getNumOperands() < 2) |
203 | return std::nullopt; |
204 | |
205 | unsigned LastOp = Inst.getNumOperands() - 1; |
206 | // The last operand needs to be an MCExpr and it needs to have a variant kind |
207 | // of VK_PPC_PCREL_OPT. If it does not satisfy these conditions it is not a |
208 | // link time GOT PC Rel opt instruction and we can ignore it and return |
209 | // std::nullopt. |
210 | const MCOperand &Operand = Inst.getOperand(i: LastOp); |
211 | if (!Operand.isExpr()) |
212 | return std::nullopt; |
213 | |
214 | // Check for the variant kind VK_PPC_PCREL_OPT in this expression. |
215 | const MCExpr *Expr = Operand.getExpr(); |
216 | const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr); |
217 | if (!SymExpr || SymExpr->getKind() != MCSymbolRefExpr::VK_PPC_PCREL_OPT) |
218 | return std::nullopt; |
219 | |
220 | return (Inst.getOpcode() == PPC::PLDpc); |
221 | } |
222 | |
223 | MCELFStreamer *llvm::createPPCELFStreamer( |
224 | MCContext &Context, std::unique_ptr<MCAsmBackend> MAB, |
225 | std::unique_ptr<MCObjectWriter> OW, |
226 | std::unique_ptr<MCCodeEmitter> Emitter) { |
227 | return new PPCELFStreamer(Context, std::move(MAB), std::move(OW), |
228 | std::move(Emitter)); |
229 | } |
230 | |