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 function 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));
}
|