| //===- bolt/Passes/ValidateMemRefs.cpp ------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "bolt/Passes/ValidateMemRefs.h" | |
| #include "bolt/Core/ParallelUtilities.h" | |
| #define DEBUG_TYPE "bolt-memrefs" | |
| namespace opts { | |
| extern llvm::cl::opt<llvm::bolt::JumpTableSupportLevel> JumpTables; | |
| } | |
| namespace llvm::bolt { | |
| std::atomic<std::uint64_t> ValidateMemRefs::ReplacedReferences{0}; | |
| bool ValidateMemRefs::checkAndFixJTReference(BinaryFunction &BF, MCInst &Inst, | |
| uint32_t OperandNum, | |
| const MCSymbol *Sym, | |
| uint64_t Offset) { | |
| BinaryContext &BC = BF.getBinaryContext(); | |
| auto L = BC.scopeLock(); | |
| BinaryData *BD = BC.getBinaryDataByName(Sym->getName()); | |
| if (!BD) | |
| return false; | |
| JumpTable *JT = BC.getJumpTableContainingAddress(BD->getAddress()); | |
| if (!JT) | |
| return false; | |
| const bool IsLegitAccess = llvm::is_contained(JT->Parents, &BF); | |
| if (IsLegitAccess) | |
| return true; | |
| // Accessing a jump table in another function. This is not a | |
| // legitimate jump table access, we need to replace the reference to | |
| // the jump table label with a regular rodata reference. Get a | |
| // non-JT reference by fetching the symbol 1 byte before the JT | |
| // label. | |
| MCSymbol *NewSym = BC.getOrCreateGlobalSymbol(BD->getAddress() - 1, "DATAat"); | |
| BC.MIB->setOperandToSymbolRef(Inst, OperandNum, NewSym, Offset + 1, &*BC.Ctx, | |
| 0); | |
| LLVM_DEBUG(dbgs() << "BOLT-DEBUG: replaced reference @" << BF.getPrintName() | |
| << " from " << BD->getName() << " to " << NewSym->getName() | |
| << " + 1\n"); | |
| ++ReplacedReferences; | |
| return true; | |
| } | |
| void ValidateMemRefs::runOnFunction(BinaryFunction &BF) { | |
| MCPlusBuilder *MIB = BF.getBinaryContext().MIB.get(); | |
| for (BinaryBasicBlock &BB : BF) { | |
| for (MCInst &Inst : BB) { | |
| for (int I = 0, E = MCPlus::getNumPrimeOperands(Inst); I != E; ++I) { | |
| const MCOperand &Operand = Inst.getOperand(I); | |
| if (!Operand.isExpr()) | |
| continue; | |
| const auto [Sym, Offset] = MIB->getTargetSymbolInfo(Operand.getExpr()); | |
| if (!Sym) | |
| continue; | |
| checkAndFixJTReference(BF, Inst, I, Sym, Offset); | |
| } | |
| } | |
| } | |
| } | |
| Error ValidateMemRefs::runOnFunctions(BinaryContext &BC) { | |
| if (!BC.isX86()) | |
| return Error::success(); | |
| // Skip validation if not moving JT | |
| if (opts::JumpTables == JTS_NONE || opts::JumpTables == JTS_BASIC) | |
| return Error::success(); | |
| ParallelUtilities::WorkFuncWithAllocTy ProcessFunction = | |
| [&](BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocId) { | |
| runOnFunction(BF); | |
| }; | |
| ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) { | |
| return !BF.hasCFG(); | |
| }; | |
| LLVM_DEBUG(dbgs() << "BOLT-DEBUG: starting memrefs validation pass\n"); | |
| ParallelUtilities::runOnEachFunctionWithUniqueAllocId( | |
| BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, ProcessFunction, | |
| SkipPredicate, "validate-mem-refs", /*ForceSequential=*/true); | |
| LLVM_DEBUG(dbgs() << "BOLT-DEBUG: memrefs validation is concluded\n"); | |
| if (!ReplacedReferences) | |
| return Error::success(); | |
| BC.outs() << "BOLT-INFO: validate-mem-refs updated " << ReplacedReferences | |
| << " object references\n"; | |
| return Error::success(); | |
| } | |
| } // namespace llvm::bolt |