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
PPCELFStreamer(MCContext & Context,std::unique_ptr<MCAsmBackend> MAB,std::unique_ptr<MCObjectWriter> OW,std::unique_ptr<MCCodeEmitter> Emitter)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
emitPrefixedInstruction(const MCInst & Inst,const MCSubtargetInfo & STI)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(Align(64), &STI, 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(InstLoc);
74 unsigned LabelLine = SourceManager->FindLineNumber(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
emitInstruction(const MCInst & Inst,const MCSubtargetInfo & STI)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(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
emitLabel(MCSymbol * Symbol,SMLoc Loc)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.
emitGOTToPCRelReloc(const MCInst & Inst)137 void PPCELFStreamer::emitGOTToPCRelReloc(const MCInst &Inst) {
138 // Get the last operand which contains the symbol.
139 const MCOperand &Operand = Inst.getOperand(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(SymExpr->getSymbol().getName());
148 const MCExpr *LabelExpr = MCSymbolRefExpr::create(LabelSym, getContext());
149 const MCExpr *Eight = MCConstantExpr::create(8, getContext());
150 // SubExpr is just Label###-8
151 const MCExpr *SubExpr =
152 MCBinaryExpr::createSub(LabelExpr, Eight, getContext());
153 MCSymbol *CurrentLocation = getContext().createTempSymbol();
154 const MCExpr *CurrentLocationExpr =
155 MCSymbolRefExpr::create(CurrentLocation, getContext());
156 // SubExpr2 is .-(Label###-8)
157 const MCExpr *SubExpr2 =
158 MCBinaryExpr::createSub(CurrentLocationExpr, SubExpr, 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 MCFixup::create(LabelSym->getOffset() - 8, SubExpr2,
166 FixupKind, Inst.getLoc()));
167 emitLabel(CurrentLocation, Inst.getLoc());
168 }
169
170 // Emit the label that immediately follows the PLDpc for a link time GOT PC Rel
171 // optimization.
emitGOTToPCRelLabel(const MCInst & Inst)172 void PPCELFStreamer::emitGOTToPCRelLabel(const MCInst &Inst) {
173 // Get the last operand which contains the symbol.
174 const MCOperand &Operand = Inst.getOperand(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(SymExpr->getSymbol().getName());
183 emitLabel(LabelSym, 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.
isPartOfGOTToPCRelPair(const MCInst & Inst,const MCSubtargetInfo & STI)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(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
createPPCELFStreamer(MCContext & Context,std::unique_ptr<MCAsmBackend> MAB,std::unique_ptr<MCObjectWriter> OW,std::unique_ptr<MCCodeEmitter> Emitter)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