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
~X86MCSymbolizer()23 X86MCSymbolizer::~X86MCSymbolizer() {}
24
tryAddingSymbolicOperand(MCInst & Inst,raw_ostream & CStream,int64_t Value,uint64_t InstAddress,bool IsBranch,uint64_t ImmOffset,uint64_t ImmSize,uint64_t InstSize)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
tryAddingPcLoadReferenceComment(raw_ostream & CStream,int64_t Value,uint64_t Address)136 void X86MCSymbolizer::tryAddingPcLoadReferenceComment(raw_ostream &CStream,
137 int64_t Value,
138 uint64_t Address) {}
139
140 } // namespace bolt
141 } // namespace llvm
142