1 //===- bolt/Target/X86/X86MCSymbolizer.cpp --------------------------------===// 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 #include "X86MCSymbolizer.h" 10 #include "MCTargetDesc/X86BaseInfo.h" 11 #include "bolt/Core/BinaryContext.h" 12 #include "bolt/Core/BinaryFunction.h" 13 #include "bolt/Core/MCPlusBuilder.h" 14 #include "bolt/Core/Relocation.h" 15 #include "llvm/MC/MCInst.h" 16 #include "llvm/MC/MCRegisterInfo.h" 17 18 #define DEBUG_TYPE "bolt-symbolizer" 19 20 namespace llvm { 21 namespace bolt { 22 23 X86MCSymbolizer::~X86MCSymbolizer() {} 24 25 bool X86MCSymbolizer::tryAddingSymbolicOperand( 26 MCInst &Inst, raw_ostream &CStream, int64_t Value, uint64_t InstAddress, 27 bool IsBranch, uint64_t ImmOffset, uint64_t ImmSize, uint64_t InstSize) { 28 if (IsBranch) 29 return false; 30 31 // Ignore implicit operands. 32 if (ImmSize == 0) 33 return false; 34 35 BinaryContext &BC = Function.getBinaryContext(); 36 MCContext *Ctx = BC.Ctx.get(); 37 38 if (BC.MIB->isBranch(Inst) || BC.MIB->isCall(Inst)) 39 return false; 40 41 /// Add symbolic operand to the instruction with an optional addend. 42 auto addOperand = [&](const MCSymbol *Symbol, uint64_t Addend) { 43 const MCExpr *Expr = MCSymbolRefExpr::create(Symbol, *Ctx); 44 if (Addend) 45 Expr = MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Addend, *Ctx), 46 *Ctx); 47 Inst.addOperand(MCOperand::createExpr(Expr)); 48 }; 49 50 // Check if the operand being added is a displacement part of a compound 51 // memory operand that uses PC-relative addressing. If it is, try to symbolize 52 // it without relocations. Return true on success, false otherwise. 53 auto processPCRelOperandNoRel = [&]() { 54 const int MemOp = BC.MIB->getMemoryOperandNo(Inst); 55 if (MemOp == -1) 56 return false; 57 58 const unsigned DispOp = MemOp + X86::AddrDisp; 59 if (Inst.getNumOperands() != DispOp) 60 return false; 61 62 const MCOperand &Base = Inst.getOperand(MemOp + X86::AddrBaseReg); 63 if (Base.getReg() != BC.MRI->getProgramCounter()) 64 return false; 65 66 const MCOperand &Scale = Inst.getOperand(MemOp + X86::AddrScaleAmt); 67 const MCOperand &Index = Inst.getOperand(MemOp + X86::AddrIndexReg); 68 if (Scale.getImm() != 0 && Index.getReg() != MCRegister::NoRegister) 69 return false; 70 71 const MCSymbol *TargetSymbol; 72 uint64_t TargetOffset; 73 std::tie(TargetSymbol, TargetOffset) = 74 BC.handleAddressRef(Value, Function, /*IsPCRel=*/true); 75 76 addOperand(TargetSymbol, TargetOffset); 77 78 return true; 79 }; 80 81 // Check for GOTPCRELX relocations first. Because these relocations allow the 82 // linker to modify the instruction, we have to check the offset range 83 // corresponding to the instruction, not the offset of the operand. 84 // Note that if there is GOTPCRELX relocation against the instruction, there 85 // will be no other relocation in this range, since GOTPCRELX applies only to 86 // certain instruction types. 87 const uint64_t InstOffset = InstAddress - Function.getAddress(); 88 const Relocation *Relocation = 89 Function.getRelocationInRange(InstOffset, InstOffset + InstSize); 90 if (Relocation && Relocation::isX86GOTPCRELX(Relocation->Type)) { 91 // If the operand is PC-relative, convert it without using the relocation 92 // information. For GOTPCRELX, it is safe to use the absolute address 93 // instead of extracting the addend from the relocation, as non-standard 94 // forms will be rejected by linker conversion process and the operand 95 // will always reference GOT which we don't rewrite. 96 if (processPCRelOperandNoRel()) 97 return true; 98 99 // The linker converted the PC-relative address to an absolute one. 100 // Symbolize this address. 101 BC.handleAddressRef(Value, Function, /*IsPCRel=*/false); 102 const BinaryData *Target = BC.getBinaryDataAtAddress(Value); 103 assert(Target && 104 "BinaryData should exist at converted GOTPCRELX destination"); 105 106 addOperand(Target->getSymbol(), /*Addend=*/0); 107 108 return true; 109 } 110 111 // Check for relocations against the operand. 112 if (!Relocation || Relocation->Offset != InstOffset + ImmOffset) 113 Relocation = Function.getRelocationAt(InstOffset + ImmOffset); 114 115 if (!Relocation) 116 return processPCRelOperandNoRel(); 117 118 uint64_t SymbolValue = Relocation->Value - Relocation->Addend; 119 if (Relocation->isPCRelative()) 120 SymbolValue += InstAddress + ImmOffset; 121 122 // Process reference to the symbol. 123 BC.handleAddressRef(SymbolValue, Function, Relocation->isPCRelative()); 124 125 uint64_t Addend = Relocation->Addend; 126 // Real addend for pc-relative targets is adjusted with a delta from 127 // the relocation placement to the next instruction. 128 if (Relocation->isPCRelative()) 129 Addend += InstOffset + InstSize - Relocation->Offset; 130 131 addOperand(Relocation->Symbol, Addend); 132 133 return true; 134 } 135 136 void X86MCSymbolizer::tryAddingPcLoadReferenceComment(raw_ostream &CStream, 137 int64_t Value, 138 uint64_t Address) {} 139 140 } // namespace bolt 141 } // namespace llvm 142