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