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