[PR] Fix LongJmp pass
Summary: This patch handles 2 problems with LongJmp pass: 1. The pass should be executed before FinalizeFunctions, since the pass may add new entry points for the function, and the BinaryFunction::addEntryPoint has an assert "CurrentState == State::CFG" 2. Replaced shortJmp implementation with position-independent code. Currently we could handle PIC binaries with max +-4Gb offsets, the longJmp uses absolute addreses and could could be used only in non-PIE binaries. Vladislav Khmelevsky, Advanced Software Technology Lab, Huawei (cherry picked from FBD31416925)
This commit is contained in:
parent
96bb090653
commit
a2214e8f0d
|
@ -510,6 +510,15 @@ void BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) {
|
|||
// memory profiling data.
|
||||
Manager.registerPass(std::make_unique<ReorderData>());
|
||||
|
||||
if (BC.isAArch64()) {
|
||||
Manager.registerPass(std::make_unique<ADRRelaxationPass>());
|
||||
|
||||
// Tighten branches according to offset differences between branch and
|
||||
// targets. No extra instructions after this pass, otherwise we may have
|
||||
// relocations out of range and crash during linking.
|
||||
Manager.registerPass(std::make_unique<LongJmpPass>(PrintLongJmp));
|
||||
}
|
||||
|
||||
// This pass should always run last.*
|
||||
Manager.registerPass(std::make_unique<FinalizeFunctions>(PrintFinalized));
|
||||
|
||||
|
@ -531,15 +540,6 @@ void BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) {
|
|||
if (BC.HasRelocations)
|
||||
Manager.registerPass(std::make_unique<PatchEntries>());
|
||||
|
||||
if (BC.isAArch64()) {
|
||||
Manager.registerPass(std::make_unique<ADRRelaxationPass>());
|
||||
|
||||
// Tighten branches according to offset differences between branch and
|
||||
// targets. No extra instructions after this pass, otherwise we may have
|
||||
// relocations out of range and crash during linking.
|
||||
Manager.registerPass(std::make_unique<LongJmpPass>(PrintLongJmp));
|
||||
}
|
||||
|
||||
// This pass turns tail calls into jumps which makes them invisible to
|
||||
// function reordering. It's unsafe to use any CFG or instruction analysis
|
||||
// after this point.
|
||||
|
|
|
@ -565,7 +565,7 @@ public:
|
|||
void addLineTableSequence(const DWARFDebugLine::LineTable *Table,
|
||||
uint32_t FirstRow, uint32_t LastRow,
|
||||
uint64_t EndOfSequenceAddress) {
|
||||
assert(!InputTable || InputTable == Table && "expected same table for CU");
|
||||
assert((!InputTable || InputTable == Table) && "expected same table for CU");
|
||||
InputTable = Table;
|
||||
|
||||
InputSequences.emplace_back(
|
||||
|
|
|
@ -1356,12 +1356,12 @@ public:
|
|||
}
|
||||
|
||||
virtual void createLongJmp(std::vector<MCInst> &Seq, const MCSymbol *Target,
|
||||
MCContext *Ctx) const {
|
||||
MCContext *Ctx, bool IsTailCall = false) {
|
||||
llvm_unreachable("not implemented");
|
||||
}
|
||||
|
||||
virtual void createShortJmp(std::vector<MCInst> &Seq, const MCSymbol *Target,
|
||||
MCContext *Ctx) const {
|
||||
MCContext *Ctx, bool IsTailCall = false) {
|
||||
llvm_unreachable("not implemented");
|
||||
}
|
||||
|
||||
|
@ -1451,6 +1451,11 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual void createLongTailCall(std::vector<MCInst> &Seq,
|
||||
const MCSymbol *Target, MCContext *Ctx) {
|
||||
llvm_unreachable("not implemented");
|
||||
}
|
||||
|
||||
/// Creates a trap instruction in Inst.
|
||||
///
|
||||
/// Returns true on success.
|
||||
|
|
|
@ -475,9 +475,12 @@ bool LongJmpPass::relaxStub(BinaryBasicBlock &StubBB) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Needs a long jmp
|
||||
if (Bits > RangeShortJmp)
|
||||
return false;
|
||||
// The long jmp uses absolute address on AArch64
|
||||
// So we could not use it for PIC binaries
|
||||
if (BC.isAArch64() && !BC.HasFixedLoadAddress) {
|
||||
errs() << "BOLT-ERROR: Unable to relax stub for PIC binary\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
LLVM_DEBUG(dbgs() << "Relaxing stub to long jump. PCRelTgtAddress = "
|
||||
<< Twine::utohexstr(PCRelTgtAddress)
|
||||
|
@ -577,6 +580,8 @@ bool LongJmpPass::relax(BinaryFunction &Func) {
|
|||
InsertionPoint == Frontier
|
||||
? FrontierAddress
|
||||
: DotAddress));
|
||||
|
||||
DotAddress += InsnSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,10 +57,9 @@ void PatchEntries::runOnFunctions(BinaryContext &BC) {
|
|||
// Calculate the size of the patch.
|
||||
static size_t PatchSize = 0;
|
||||
if (!PatchSize) {
|
||||
MCInst TailCallInst;
|
||||
BC.MIB->createTailCall(TailCallInst, BC.Ctx->createTempSymbol(),
|
||||
BC.Ctx.get());
|
||||
PatchSize = BC.computeInstructionSize(TailCallInst);
|
||||
std::vector<MCInst> Seq;
|
||||
BC.MIB->createLongTailCall(Seq, BC.Ctx->createTempSymbol(), BC.Ctx.get());
|
||||
PatchSize = BC.computeCodeSize(Seq.begin(), Seq.end());
|
||||
}
|
||||
|
||||
for (auto &BFI : BC.getBinaryFunctions()) {
|
||||
|
@ -125,9 +124,9 @@ void PatchEntries::runOnFunctions(BinaryContext &BC) {
|
|||
PatchFunction->setFileOffset(Patch.FileOffset);
|
||||
PatchFunction->setOriginSection(Patch.Section);
|
||||
|
||||
MCInst TailCallInst;
|
||||
BC.MIB->createTailCall(TailCallInst, Patch.Symbol, BC.Ctx.get());
|
||||
PatchFunction->addBasicBlock(0)->addInstruction(TailCallInst);
|
||||
std::vector<MCInst> Seq;
|
||||
BC.MIB->createLongTailCall(Seq, Patch.Symbol, BC.Ctx.get());
|
||||
PatchFunction->addBasicBlock(0)->addInstructions(Seq);
|
||||
|
||||
// Verify the size requirements.
|
||||
uint64_t HotSize, ColdSize;
|
||||
|
|
|
@ -800,7 +800,7 @@ public:
|
|||
}
|
||||
|
||||
int getShortJmpEncodingSize() const override {
|
||||
return 32;
|
||||
return 33;
|
||||
}
|
||||
|
||||
int getUncondBranchEncodingSize() const override {
|
||||
|
@ -817,6 +817,11 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
void createLongTailCall(std::vector<MCInst> &Seq, const MCSymbol *Target,
|
||||
MCContext *Ctx) override {
|
||||
createShortJmp(Seq, Target, Ctx, /*IsTailCall*/ true);
|
||||
}
|
||||
|
||||
bool convertJmpToTailCall(MCInst &Inst) override {
|
||||
setTailCall(Inst);
|
||||
return true;
|
||||
|
@ -908,7 +913,7 @@ public:
|
|||
}
|
||||
|
||||
void createLongJmp(std::vector<MCInst> &Seq, const MCSymbol *Target,
|
||||
MCContext *Ctx) const override {
|
||||
MCContext *Ctx, bool IsTailCall) override {
|
||||
// ip0 (r16) is reserved to the linker (refer to 5.3.1.1 of "Procedure Call
|
||||
// Standard for the ARM 64-bit Architecture (AArch64)".
|
||||
// The sequence of instructions we create here is the following:
|
||||
|
@ -959,40 +964,29 @@ public:
|
|||
Inst.clear();
|
||||
Inst.setOpcode(AArch64::BR);
|
||||
Inst.addOperand(MCOperand::createReg(AArch64::X16));
|
||||
if (IsTailCall)
|
||||
setTailCall(Inst);
|
||||
Seq.emplace_back(Inst);
|
||||
}
|
||||
|
||||
void createShortJmp(std::vector<MCInst> &Seq, const MCSymbol *Target,
|
||||
MCContext *Ctx) const override {
|
||||
MCContext *Ctx, bool IsTailCall) override {
|
||||
// ip0 (r16) is reserved to the linker (refer to 5.3.1.1 of "Procedure Call
|
||||
// Standard for the ARM 64-bit Architecture (AArch64)".
|
||||
// The sequence of instructions we create here is the following:
|
||||
// movz ip0, #:abs_g1_nc:<addr>
|
||||
// movk ip0, #:abs_g0_nc:<addr>
|
||||
// adrp ip0, imm
|
||||
// add ip0, ip0, imm
|
||||
// br ip0
|
||||
MCInst Inst;
|
||||
Inst.setOpcode(AArch64::MOVZXi);
|
||||
Inst.addOperand(MCOperand::createReg(AArch64::X16));
|
||||
Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create(
|
||||
MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
|
||||
AArch64MCExpr::VK_ABS_G1_NC, *Ctx)));
|
||||
Inst.addOperand(MCOperand::createImm(0x10));
|
||||
Seq.emplace_back(Inst);
|
||||
|
||||
Inst.clear();
|
||||
Inst.setOpcode(AArch64::MOVKXi);
|
||||
Inst.addOperand(MCOperand::createReg(AArch64::X16));
|
||||
Inst.addOperand(MCOperand::createReg(AArch64::X16));
|
||||
Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create(
|
||||
MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
|
||||
AArch64MCExpr::VK_ABS_G0_NC, *Ctx)));
|
||||
Inst.addOperand(MCOperand::createImm(0));
|
||||
Seq.emplace_back(Inst);
|
||||
|
||||
MCPhysReg Reg = AArch64::X16;
|
||||
std::vector<MCInst> Insts = materializeAddress(Target, Ctx, Reg);
|
||||
Insts.emplace_back();
|
||||
MCInst &Inst = Insts.back();
|
||||
Inst.clear();
|
||||
Inst.setOpcode(AArch64::BR);
|
||||
Inst.addOperand(MCOperand::createReg(AArch64::X16));
|
||||
Seq.emplace_back(Inst);
|
||||
Inst.addOperand(MCOperand::createReg(Reg));
|
||||
if (IsTailCall)
|
||||
setTailCall(Inst);
|
||||
Seq.swap(Insts);
|
||||
}
|
||||
|
||||
/// Matching pattern here is
|
||||
|
@ -1106,7 +1100,7 @@ public:
|
|||
|
||||
std::vector<MCInst> materializeAddress(const MCSymbol *Target, MCContext *Ctx,
|
||||
MCPhysReg RegName,
|
||||
int64_t Addend) const override {
|
||||
int64_t Addend = 0) const override {
|
||||
// Get page-aligned address and add page offset
|
||||
std::vector<MCInst> Insts(2);
|
||||
Insts[0].setOpcode(AArch64::ADRP);
|
||||
|
|
|
@ -3299,6 +3299,13 @@ public:
|
|||
return createDirectCall(Inst, Target, Ctx, /*IsTailCall*/ true);
|
||||
}
|
||||
|
||||
void createLongTailCall(std::vector<MCInst> &Seq, const MCSymbol *Target,
|
||||
MCContext *Ctx) override {
|
||||
Seq.clear();
|
||||
Seq.emplace_back();
|
||||
createDirectCall(Seq.back(), Target, Ctx, /*IsTailCall*/ true);
|
||||
}
|
||||
|
||||
bool createTrap(MCInst &Inst) const override {
|
||||
Inst.clear();
|
||||
Inst.setOpcode(X86::TRAP);
|
||||
|
@ -3407,12 +3414,14 @@ public:
|
|||
}
|
||||
|
||||
void createShortJmp(std::vector<MCInst> &Seq, const MCSymbol *Target,
|
||||
MCContext *Ctx) const override {
|
||||
MCContext *Ctx, bool IsTailCall) override {
|
||||
Seq.clear();
|
||||
MCInst Inst;
|
||||
Inst.setOpcode(X86::JMP_1);
|
||||
Inst.addOperand(MCOperand::createExpr(
|
||||
MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx)));
|
||||
if (IsTailCall)
|
||||
setTailCall(Inst);
|
||||
Seq.emplace_back(Inst);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue