Skip to content

Commit e81445c

Browse files
committed
[BOLT][AArch64] Fix which PSign and PAuth variants are used (#120064)
- only the ones operating on LR should be marked with .cfi_cfi_negate_ra_state - added support for fused PtrAuth and Ret instructions, e.g. RETAA.
1 parent 8fe3244 commit e81445c

File tree

5 files changed

+53
-21
lines changed

5 files changed

+53
-21
lines changed

bolt/include/bolt/Core/MCPlusBuilder.h

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,21 @@ class MCPlusBuilder {
611611
return std::nullopt;
612612
}
613613

614+
virtual bool isPSignOnLR(const MCInst &Inst) const {
615+
llvm_unreachable("not implemented");
616+
return false;
617+
}
618+
619+
virtual bool isPAuthOnLR(const MCInst &Inst) const {
620+
llvm_unreachable("not implemented");
621+
return false;
622+
}
623+
624+
virtual bool isPAuthAndRet(const MCInst &Inst) const {
625+
llvm_unreachable("not implemented");
626+
return false;
627+
}
628+
614629
/// Returns the register used as a return address. Returns std::nullopt if
615630
/// not applicable, such as reading the return address from a system register
616631
/// or from the stack.
@@ -848,13 +863,6 @@ class MCPlusBuilder {
848863
llvm_unreachable("not implemented");
849864
return false;
850865
}
851-
virtual bool isPAuth(MCInst &Inst) const {
852-
llvm_unreachable("not implemented");
853-
}
854-
855-
virtual bool isPSign(MCInst &Inst) const {
856-
llvm_unreachable("not implemented");
857-
}
858866

859867
virtual bool isCleanRegXOR(const MCInst &Inst) const {
860868
llvm_unreachable("not implemented");

bolt/include/bolt/Passes/InsertNegateRAStatePass.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ class InsertNegateRAState : public BinaryFunctionPass {
3030

3131
private:
3232
/// Loops over all instructions and adds OpNegateRAState CFI
33-
/// after any pointer signing or authenticating instructions.
33+
/// after any pointer signing or authenticating instructions,
34+
/// which operate on the LR, except fused ptrauth + ret instructions
35+
/// (such as RETAA).
3436
/// Returns true, if any OpNegateRAState CFIs were added.
3537
bool addNegateRAStateAfterPacOrAuth(BinaryFunction &BF);
3638
/// Because states are tracked as MCAnnotations on individual instructions,

bolt/lib/Passes/InsertNegateRAStatePass.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,16 @@ void InsertNegateRAState::runOnFunction(BinaryFunction &BF) {
4646
bool FirstIter = true;
4747
MCInst PrevInst;
4848
BinaryBasicBlock *PrevBB = nullptr;
49+
// We need to iterate on BBs in the Layout order
50+
// not in the order they are stored in the BF class.
4951
auto *Begin = BF.getLayout().block_begin();
5052
auto *End = BF.getLayout().block_end();
5153
for (auto *BB = Begin; BB != End; BB++) {
5254

5355
// Support for function splitting:
54-
// if two consecutive BBs are going to end up in different functions,
55-
// we have to negate the RA State, so the new function starts with a Signed
56-
// state.
56+
// if two consecutive BBs with Signed state are going to end up in different
57+
// functions, we have to add a OpNegateRAState to the beginning of the newly
58+
// split function, so it starts with a Signed state.
5759
if (PrevBB != nullptr &&
5860
PrevBB->getFragmentNum() != (*BB)->getFragmentNum() &&
5961
BC.MIB->isRASigned(*((*BB)->begin()))) {
@@ -68,6 +70,8 @@ void InsertNegateRAState::runOnFunction(BinaryFunction &BF) {
6870
continue;
6971

7072
if (!FirstIter) {
73+
// Consecutive instructions with different RAState means we need to add
74+
// a OpNegateRAState.
7175
if ((BC.MIB->isRASigned(PrevInst) && BC.MIB->isRAUnsigned(Inst)) ||
7276
(BC.MIB->isRAUnsigned(PrevInst) && BC.MIB->isRASigned(Inst))) {
7377

@@ -90,7 +94,8 @@ bool InsertNegateRAState::addNegateRAStateAfterPacOrAuth(BinaryFunction &BF) {
9094
for (BinaryBasicBlock &BB : BF) {
9195
for (auto Iter = BB.begin(); Iter != BB.end(); ++Iter) {
9296
MCInst &Inst = *Iter;
93-
if (BC.MIB->isPSign(Inst) || BC.MIB->isPAuth(Inst)) {
97+
if (BC.MIB->isPSignOnLR(Inst) ||
98+
(BC.MIB->isPAuthOnLR(Inst) && !BC.MIB->isPAuthAndRet(Inst))) {
9499
Iter = BF.addCFIInstruction(
95100
&BB, Iter + 1, MCCFIInstruction::createNegateRAState(nullptr));
96101
FoundAny = true;

bolt/lib/Passes/MarkRAStates.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ void MarkRAStates::runOnFunction(BinaryFunction &BF) {
4646
for (BinaryBasicBlock &BB : BF) {
4747
for (auto It = BB.begin(); It != BB.end(); ++It) {
4848
MCInst &Inst = *It;
49-
if ((BC.MIB->isPSign(Inst) || BC.MIB->isPAuth(Inst)) &&
49+
if ((BC.MIB->isPSignOnLR(Inst) ||
50+
(BC.MIB->isPAuthOnLR(Inst) && !BC.MIB->isPAuthAndRet(Inst))) &&
5051
!BC.MIB->hasNegateRAState(Inst)) {
5152
// no .cfi_negate_ra_state attached to signing or authenticating instr
5253
// means, that this is a function with handwritten assembly, which might
@@ -71,7 +72,7 @@ void MarkRAStates::runOnFunction(BinaryFunction &BF) {
7172
if (BC.MIB->isCFI(Inst))
7273
continue;
7374

74-
if (BC.MIB->isPSign(Inst)) {
75+
if (BC.MIB->isPSignOnLR(Inst)) {
7576
if (RAState) {
7677
// RA signing instructions should only follow unsigned RA state.
7778
BC.outs() << "BOLT-INFO: inconsistent RAStates in function "
@@ -80,7 +81,7 @@ void MarkRAStates::runOnFunction(BinaryFunction &BF) {
8081
return;
8182
}
8283
BC.MIB->setRASigning(Inst);
83-
} else if (BC.MIB->isPAuth(Inst)) {
84+
} else if (BC.MIB->isPAuthOnLR(Inst)) {
8485
if (!RAState) {
8586
// RA authenticating instructions should only follow signed RA state.
8687
BC.outs() << "BOLT-INFO: inconsistent RAStates in function "

bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,28 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
231231
}
232232
}
233233

234+
bool isPSignOnLR(const MCInst &Inst) const override {
235+
std::optional<MCPhysReg> SignReg = getSignedReg(Inst);
236+
return SignReg && *SignReg == AArch64::LR;
237+
}
238+
239+
bool isPAuthOnLR(const MCInst &Inst) const override {
240+
// LDR(A|B) should not be covered.
241+
bool IsChecked;
242+
std::optional<MCPhysReg> AuthReg =
243+
getWrittenAuthenticatedReg(Inst, IsChecked);
244+
return !IsChecked && AuthReg && *AuthReg == AArch64::LR;
245+
}
246+
247+
bool isPAuthAndRet(const MCInst &Inst) const override {
248+
return Inst.getOpcode() == AArch64::RETAA ||
249+
Inst.getOpcode() == AArch64::RETAB ||
250+
Inst.getOpcode() == AArch64::RETAASPPCi ||
251+
Inst.getOpcode() == AArch64::RETABSPPCi ||
252+
Inst.getOpcode() == AArch64::RETAASPPCr ||
253+
Inst.getOpcode() == AArch64::RETABSPPCr;
254+
}
255+
234256
std::optional<MCPhysReg> getSignedReg(const MCInst &Inst) const override {
235257
switch (Inst.getOpcode()) {
236258
case AArch64::PACIA:
@@ -893,12 +915,6 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
893915
}
894916
return false;
895917
}
896-
bool isPAuth(MCInst &Inst) const override {
897-
return Inst.getOpcode() == AArch64::AUTIASP;
898-
}
899-
bool isPSign(MCInst &Inst) const override {
900-
return Inst.getOpcode() == AArch64::PACIASP;
901-
}
902918

903919
bool isRegToRegMove(const MCInst &Inst, MCPhysReg &From,
904920
MCPhysReg &To) const override {

0 commit comments

Comments
 (0)