#include "X86MCSymbolizer.h"
#include "MCTargetDesc/X86BaseInfo.h"
#include "bolt/Core/BinaryContext.h"
#include "bolt/Core/BinaryFunction.h"
#include "bolt/Core/MCPlusBuilder.h"
#include "bolt/Core/Relocation.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCRegisterInfo.h"
#define DEBUG_TYPE "bolt-symbolizer"
namespace llvm {
namespace bolt {
X86MCSymbolizer::~X86MCSymbolizer() {}
bool X86MCSymbolizer::tryAddingSymbolicOperand(
MCInst &Inst, raw_ostream &CStream, int64_t Value, uint64_t InstAddress,
bool IsBranch, uint64_t ImmOffset, uint64_t ImmSize, uint64_t InstSize) {
if (IsBranch)
return false;
if (ImmSize == 0)
return false;
BinaryContext &BC = Function.getBinaryContext();
MCContext *Ctx = BC.Ctx.get();
if (BC.MIB->isBranch(Inst) || BC.MIB->isCall(Inst))
return false;
auto addOperand = [&](const MCSymbol *Symbol, uint64_t Addend) {
const MCExpr *Expr = MCSymbolRefExpr::create(Symbol, *Ctx);
if (Addend)
Expr = MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Addend, *Ctx),
*Ctx);
Inst.addOperand(MCOperand::createExpr(Expr));
};
auto processPCRelOperandNoRel = [&]() {
const int MemOp = BC.MIB->getMemoryOperandNo(Inst);
if (MemOp == -1)
return false;
const unsigned DispOp = MemOp + X86::AddrDisp;
if (Inst.getNumOperands() != DispOp)
return false;
const MCOperand &Base = Inst.getOperand(MemOp + X86::AddrBaseReg);
if (Base.getReg() != BC.MRI->getProgramCounter())
return false;
const MCOperand &Scale = Inst.getOperand(MemOp + X86::AddrScaleAmt);
const MCOperand &Index = Inst.getOperand(MemOp + X86::AddrIndexReg);
if (Scale.getImm() != 0 && Index.getReg() != MCRegister::NoRegister)
return false;
const MCSymbol *TargetSymbol;
uint64_t TargetOffset;
if (!CreateNewSymbols) {
if (BinaryData *BD = BC.getBinaryDataContainingAddress(Value)) {
TargetSymbol = BD->getSymbol();
TargetOffset = Value - BD->getAddress();
} else {
return false;
}
} else {
std::tie(TargetSymbol, TargetOffset) =
BC.handleAddressRef(Value, Function, true);
}
addOperand(TargetSymbol, TargetOffset);
return true;
};
const uint64_t InstOffset = InstAddress - Function.getAddress();
const Relocation *Relocation =
Function.getRelocationInRange(InstOffset, InstOffset + InstSize);
if (Relocation && Relocation::isX86GOTPCRELX(Relocation->Type)) {
if (processPCRelOperandNoRel())
return true;
if (CreateNewSymbols)
BC.handleAddressRef(Value, Function, false);
const BinaryData *Target = BC.getBinaryDataAtAddress(Value);
if (!Target) {
assert(!CreateNewSymbols &&
"BinaryData should exist at converted GOTPCRELX destination");
return false;
}
addOperand(Target->getSymbol(), 0);
return true;
}
if (!Relocation || Relocation->Offset != InstOffset + ImmOffset)
Relocation = Function.getRelocationAt(InstOffset + ImmOffset);
if (!Relocation)
return processPCRelOperandNoRel();
if (Relocation::isX86GOTPC64(Relocation->Type)) {
auto PairOrErr = handleGOTPC64(*Relocation, InstAddress);
if (auto E = PairOrErr.takeError()) {
Function.setSimple(false);
BC.logBOLTErrorsAndQuitOnFatal(std::move(E));
return false;
}
auto [Sym, Addend] = *PairOrErr;
addOperand(Sym, Addend);
return true;
}
uint64_t SymbolValue = Relocation->Value - Relocation->Addend;
if (Relocation->isPCRelative())
SymbolValue += InstAddress + ImmOffset;
if (CreateNewSymbols)
BC.handleAddressRef(SymbolValue, Function, Relocation->isPCRelative());
uint64_t Addend = Relocation->Addend;
if (Relocation->isPCRelative())
Addend += InstOffset + InstSize - Relocation->Offset;
addOperand(Relocation->Symbol, Addend);
return true;
}
Expected<std::pair<MCSymbol *, uint64_t>>
X86MCSymbolizer::handleGOTPC64(const Relocation &R, uint64_t InstrAddr) {
BinaryContext &BC = Function.getBinaryContext();
const BinaryData *GOTSymBD = BC.getGOTSymbol();
if (!GOTSymBD || !GOTSymBD->getAddress()) {
return createNonFatalBOLTError(
"R_X86_GOTPC64 relocation is present but we did not detect "
"a valid _GLOBAL_OFFSET_TABLE_ in symbol table\n");
}
const int64_t Addend = R.Value + InstrAddr - GOTSymBD->getAddress();
return std::make_pair(BC.Ctx->getOrCreateSymbol("_GLOBAL_OFFSET_TABLE_"),
Addend);
}
void X86MCSymbolizer::tryAddingPcLoadReferenceComment(raw_ostream &CStream,
int64_t Value,
uint64_t Address) {}
}
}