1 //===- bolt/Passes/ValidateMemRefs.cpp ------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "bolt/Passes/ValidateMemRefs.h"
10 #include "bolt/Core/ParallelUtilities.h"
12 #define DEBUG_TYPE "bolt-memrefs"
15 extern llvm::cl::opt
<llvm::bolt::JumpTableSupportLevel
> JumpTables
;
18 namespace llvm::bolt
{
20 std::atomic
<std::uint64_t> ValidateMemRefs::ReplacedReferences
{0};
22 bool ValidateMemRefs::checkAndFixJTReference(BinaryFunction
&BF
, MCInst
&Inst
,
26 BinaryContext
&BC
= BF
.getBinaryContext();
27 auto L
= BC
.scopeLock();
28 BinaryData
*BD
= BC
.getBinaryDataByName(Sym
->getName());
32 JumpTable
*JT
= BC
.getJumpTableContainingAddress(BD
->getAddress());
36 const bool IsLegitAccess
= llvm::is_contained(JT
->Parents
, &BF
);
40 // Accessing a jump table in another function. This is not a
41 // legitimate jump table access, we need to replace the reference to
42 // the jump table label with a regular rodata reference. Get a
43 // non-JT reference by fetching the symbol 1 byte before the JT
45 MCSymbol
*NewSym
= BC
.getOrCreateGlobalSymbol(BD
->getAddress() - 1, "DATAat");
46 BC
.MIB
->setOperandToSymbolRef(Inst
, OperandNum
, NewSym
, Offset
+ 1, &*BC
.Ctx
,
48 LLVM_DEBUG(dbgs() << "BOLT-DEBUG: replaced reference @" << BF
.getPrintName()
49 << " from " << BD
->getName() << " to " << NewSym
->getName()
55 void ValidateMemRefs::runOnFunction(BinaryFunction
&BF
) {
56 MCPlusBuilder
*MIB
= BF
.getBinaryContext().MIB
.get();
58 for (BinaryBasicBlock
&BB
: BF
) {
59 for (MCInst
&Inst
: BB
) {
60 for (int I
= 0, E
= MCPlus::getNumPrimeOperands(Inst
); I
!= E
; ++I
) {
61 const MCOperand
&Operand
= Inst
.getOperand(I
);
62 if (!Operand
.isExpr())
65 const auto [Sym
, Offset
] = MIB
->getTargetSymbolInfo(Operand
.getExpr());
69 checkAndFixJTReference(BF
, Inst
, I
, Sym
, Offset
);
75 Error
ValidateMemRefs::runOnFunctions(BinaryContext
&BC
) {
77 return Error::success();
79 // Skip validation if not moving JT
80 if (opts::JumpTables
== JTS_NONE
|| opts::JumpTables
== JTS_BASIC
)
81 return Error::success();
83 ParallelUtilities::WorkFuncWithAllocTy ProcessFunction
=
84 [&](BinaryFunction
&BF
, MCPlusBuilder::AllocatorIdTy AllocId
) {
87 ParallelUtilities::PredicateTy SkipPredicate
= [&](const BinaryFunction
&BF
) {
90 LLVM_DEBUG(dbgs() << "BOLT-DEBUG: starting memrefs validation pass\n");
91 ParallelUtilities::runOnEachFunctionWithUniqueAllocId(
92 BC
, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR
, ProcessFunction
,
93 SkipPredicate
, "validate-mem-refs", /*ForceSequential=*/true);
94 LLVM_DEBUG(dbgs() << "BOLT-DEBUG: memrefs validation is concluded\n");
96 if (!ReplacedReferences
)
97 return Error::success();
99 BC
.outs() << "BOLT-INFO: validate-mem-refs updated " << ReplacedReferences
100 << " object references\n";
101 return Error::success();
104 } // namespace llvm::bolt