231 lines
10 KiB
C++
231 lines
10 KiB
C++
//===-------- PPCELFStreamer.cpp - ELF Object Output ---------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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(NULL) {
|
|
}
|
|
|
|
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(64, 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 None. A true returned
|
|
// value means the instruction is the PLDpc and a false value means it is
|
|
// the user instruction.
|
|
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.hasValue() && !IsPartOfGOTToPCRelPair.getValue())
|
|
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.hasValue() && IsPartOfGOTToPCRelPair.getValue())
|
|
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
|
|
// None 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.
|
|
Optional<bool> llvm::isPartOfGOTToPCRelPair(const MCInst &Inst,
|
|
const MCSubtargetInfo &STI) {
|
|
// Need at least two operands.
|
|
if (Inst.getNumOperands() < 2)
|
|
return None;
|
|
|
|
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 None.
|
|
const MCOperand &Operand = Inst.getOperand(LastOp);
|
|
if (!Operand.isExpr())
|
|
return None;
|
|
|
|
// 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 None;
|
|
|
|
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));
|
|
}
|