|  | //===-------- 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)); | 
|  | } |