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