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