Skip to content

Commit bdf2bc1

Browse files
committed
[AArch64][PAC] Combine signing with address materialization
In pauthtest ABI, it is common to store a pointer signed with address diversity to a heap-allocated object (namely, storing a signed pointer to VTable as part of new object construction). This patch tries to prevent introducing a signing oracle by combining pointer materialization and its (re)signing into a single pseudo instruction which is not expanded until AsmPrinter, if possible. One of the typical patterns is materializing an unsigned pointer with `MOVaddr` pseudo and then signing it with `PAC[ID][AB]` instruction, which can be moved far away from `MOVaddr` by one of the passes in the machine pipeline. As the storage address is not a `Constant` value, one cannot simply emit a `ptrauth` constant in the frontend, which would be selected into `MOVaddrPAC` pseudo. Another pattern is fetching a pointer to VTable from a signed GOT entry using `LOADgotAUTH` pseudo, authenticating and checking it, and then re-signing after adding an offset. This commit adds an instruction insertion hook for `PAC[ID][AB]` which detects the above patterns and replaces it either with `MOVaddrPAC` or `LOADgotPAC` instruction.
1 parent fc7f866 commit bdf2bc1

File tree

6 files changed

+131
-4
lines changed

6 files changed

+131
-4
lines changed

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3058,6 +3058,78 @@ AArch64TargetLowering::EmitGetSMESaveSize(MachineInstr &MI,
30583058
MI.getOperand(0).getReg())
30593059
.addReg(AArch64::XZR);
30603060
BB->remove_instr(&MI);
3061+
3062+
return BB;
3063+
}
3064+
3065+
MachineBasicBlock *
3066+
AArch64TargetLowering::tryRewritingPAC(MachineInstr &MI,
3067+
MachineBasicBlock *BB) const {
3068+
const TargetInstrInfo *TII = Subtarget->getInstrInfo();
3069+
MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
3070+
const DebugLoc &DL = MI.getDebugLoc();
3071+
3072+
MachineInstr *AddrInstr = nullptr;
3073+
int64_t Offset = 0;
3074+
// Try to find the address-setting instruction, accumulating the offset
3075+
// along the way. If any unknown pattern is found, keep everything as-is.
3076+
MachineOperand *CurOp = &MI.getOperand(1);
3077+
while (CurOp) {
3078+
MachineOperand *Def = MRI.getOneDef(CurOp->getReg());
3079+
if (!Def)
3080+
return BB;
3081+
MachineInstr *DefMI = Def->getParent();
3082+
assert(DefMI != nullptr);
3083+
3084+
switch (DefMI->getOpcode()) {
3085+
case AArch64::COPY:
3086+
CurOp = &DefMI->getOperand(1);
3087+
break;
3088+
case AArch64::ADDXri:
3089+
if (DefMI->getOperand(3).getImm() != 0) // shifts are not handled
3090+
return BB;
3091+
CurOp = &DefMI->getOperand(1);
3092+
Offset += DefMI->getOperand(2).getImm();
3093+
break;
3094+
case AArch64::MOVaddr:
3095+
case AArch64::LOADgotAUTH:
3096+
AddrInstr = DefMI;
3097+
CurOp = nullptr;
3098+
break;
3099+
default:
3100+
return BB;
3101+
}
3102+
}
3103+
3104+
unsigned NewOpcode = AddrInstr->getOpcode() == AArch64::LOADgotAUTH
3105+
? AArch64::LOADgotPAC
3106+
: AArch64::MOVaddrPAC;
3107+
MachineOperand &AddrOp = AddrInstr->getOperand(1);
3108+
unsigned TargetFlags = AddrOp.getTargetFlags() & ~AArch64II::MO_PAGE;
3109+
Offset += AddrOp.getOffset();
3110+
3111+
// MOVaddrPAC and LOADgotPAC pseudos are expanded so that they use X16/X17
3112+
// internally, thus their restrictions on the register class of $AddrDisc
3113+
// operand are stricter than those of real PAC* instructions.
3114+
// If the original instruction accepts a discriminator operand, make sure
3115+
// it is moved out of X16/X17.
3116+
Register DiscReg = AArch64::XZR;
3117+
if (!isPACWithZeroDisc(MI.getOpcode())) {
3118+
DiscReg = MRI.createVirtualRegister(&AArch64::GPR64noipRegClass);
3119+
BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), DiscReg)
3120+
.addReg(MI.getOperand(2).getReg());
3121+
}
3122+
3123+
BuildMI(*BB, MI, DL, TII->get(NewOpcode))
3124+
.addGlobalAddress(AddrOp.getGlobal(), Offset, TargetFlags)
3125+
.addImm(getKeyForPACOpcode(MI.getOpcode()))
3126+
.addReg(DiscReg)
3127+
.addImm(0);
3128+
3129+
BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), MI.getOperand(0).getReg())
3130+
.addReg(AArch64::X16);
3131+
3132+
MI.removeFromParent();
30613133
return BB;
30623134
}
30633135

@@ -3159,6 +3231,16 @@ MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
31593231
return EmitZTInstr(MI, BB, AArch64::ZERO_T, /*Op0IsDef=*/true);
31603232
case AArch64::MOVT_TIZ_PSEUDO:
31613233
return EmitZTInstr(MI, BB, AArch64::MOVT_TIZ, /*Op0IsDef=*/true);
3234+
3235+
case AArch64::PACDA:
3236+
case AArch64::PACDB:
3237+
case AArch64::PACIA:
3238+
case AArch64::PACIB:
3239+
case AArch64::PACDZA:
3240+
case AArch64::PACDZB:
3241+
case AArch64::PACIZA:
3242+
case AArch64::PACIZB:
3243+
return tryRewritingPAC(MI, BB);
31623244
}
31633245
}
31643246

llvm/lib/Target/AArch64/AArch64ISelLowering.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ class AArch64TargetLowering : public TargetLowering {
181181
MachineBasicBlock *BB) const;
182182
MachineBasicBlock *EmitGetSMESaveSize(MachineInstr &MI,
183183
MachineBasicBlock *BB) const;
184+
MachineBasicBlock *tryRewritingPAC(MachineInstr &MI,
185+
MachineBasicBlock *BB) const;
184186

185187
MachineBasicBlock *
186188
EmitInstrWithCustomInserter(MachineInstr &MI,

llvm/lib/Target/AArch64/AArch64InstrInfo.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,39 @@ static inline unsigned getPACOpcodeForKey(AArch64PACKey::ID K, bool Zero) {
790790
llvm_unreachable("Unhandled AArch64PACKey::ID enum");
791791
}
792792

793+
static inline AArch64PACKey::ID getKeyForPACOpcode(unsigned Opcode) {
794+
switch (Opcode) {
795+
case AArch64::PACDA:
796+
case AArch64::PACDZA:
797+
return AArch64PACKey::DA;
798+
case AArch64::PACDB:
799+
case AArch64::PACDZB:
800+
return AArch64PACKey::DB;
801+
case AArch64::PACIA:
802+
case AArch64::PACIZA:
803+
return AArch64PACKey::IA;
804+
case AArch64::PACIB:
805+
case AArch64::PACIZB:
806+
return AArch64PACKey::IB;
807+
}
808+
llvm_unreachable("Unhandled PAC opcode");
809+
}
810+
811+
static inline bool isPACWithZeroDisc(unsigned Opcode) {
812+
switch (Opcode) {
813+
case AArch64::PACDA:
814+
case AArch64::PACDB:
815+
case AArch64::PACIA:
816+
case AArch64::PACIB:
817+
return false;
818+
case AArch64::PACDZA:
819+
case AArch64::PACDZB:
820+
case AArch64::PACIZA:
821+
case AArch64::PACIZB:
822+
return true;
823+
}
824+
llvm_unreachable("Unhandled PAC opcode");
825+
}
793826
// struct TSFlags {
794827
#define TSFLAG_ELEMENT_SIZE_TYPE(X) (X) // 3-bits
795828
#define TSFLAG_DESTRUCTIVE_INST_TYPE(X) ((X) << 3) // 4-bits

llvm/lib/Target/AArch64/AArch64InstrInfo.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2018,7 +2018,9 @@ let Predicates = [HasPAuth] in {
20182018
def DZB : SignAuthZero<prefix_z, 0b11, !strconcat(asm, "dzb"), op>;
20192019
}
20202020

2021+
let usesCustomInserter = true in
20212022
defm PAC : SignAuth<0b000, 0b010, "pac", int_ptrauth_sign>;
2023+
20222024
defm AUT : SignAuth<0b001, 0b011, "aut", null_frag>;
20232025

20242026
def XPACI : ClearAuth<0, "xpaci">;

llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ define void @store_signed_const_local(ptr %dest) {
9696
; ISEL: %0:gpr64common = COPY $x0
9797
; ISEL-NEXT: %10:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8
9898
; ISEL-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234
99-
; ISEL-NEXT: %4:gpr64 = PACDA %10, %2
99+
; ISEL-NEXT: %15:gpr64noip = COPY %2
100+
; ISEL-NEXT: MOVaddrPAC @const_table_local + 8, 2, %15, 0, implicit-def $x16, implicit-def $x17
101+
; ISEL-NEXT: %4:gpr64 = COPY $x16
100102
; ISEL-NEXT: %14:gpr64 = COPY %4
101103
; ISEL-NEXT: STRXui %14, %0, 0 :: (store (p0) into %ir.dest)
102104
; ISEL-NEXT: RET_ReallyLR
@@ -115,7 +117,9 @@ define void @store_signed_const_got(ptr %dest) {
115117
; ISEL-ELF-NEXT: %7:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got
116118
; ISEL-ELF-NEXT: %6:gpr64common = ADDXri %7, 8, 0
117119
; ISEL-ELF-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234
118-
; ISEL-ELF-NEXT: %4:gpr64 = PACDA %6, %2
120+
; ISEL-ELF-NEXT: %12:gpr64noip = COPY %2
121+
; ISEL-ELF-NEXT: LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %12, 0, implicit-def $x16, implicit-def $x17, implicit-def $nzcv
122+
; ISEL-ELF-NEXT: %4:gpr64 = COPY $x16
119123
; ISEL-ELF-NEXT: %10:gpr64 = COPY %4
120124
; ISEL-ELF-NEXT: STRXui %10, %0, 0 :: (store (p0) into %ir.dest)
121125
; ISEL-ELF-NEXT: RET_ReallyLR

llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,9 @@ define void @store_signed_const_local(ptr %dest) {
8585
; ISEL: %0:gpr64common = COPY $x0
8686
; ISEL-NEXT: %1:gpr64common = PAUTH_BLEND %0, 1234
8787
; ISEL-NEXT: %2:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8
88-
; ISEL-NEXT: %3:gpr64 = PACDA %2, killed %1
88+
; ISEL-NEXT: %4:gpr64noip = COPY %1
89+
; ISEL-NEXT: MOVaddrPAC @const_table_local + 8, 2, %4, 0, implicit-def $x16, implicit-def $x17
90+
; ISEL-NEXT: %3:gpr64 = COPY $x16
8991
; ISEL-NEXT: STRXui killed %3, %0, 0 :: (store (s64) into %ir.dest)
9092
; ISEL-NEXT: RET_ReallyLR
9193
%dest.i = ptrtoint ptr %dest to i64
@@ -103,7 +105,9 @@ define void @store_signed_const_got(ptr %dest) {
103105
; ISEL-ELF-NEXT: %1:gpr64common = PAUTH_BLEND %0, 1234
104106
; ISEL-ELF-NEXT: %2:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got, implicit-def dead $x16, implicit-def dead $x17, implicit-def dead $nzcv
105107
; ISEL-ELF-NEXT: %3:gpr64common = ADDXri killed %2, 8, 0
106-
; ISEL-ELF-NEXT: %4:gpr64 = PACDA %3, killed %1
108+
; ISEL-ELF-NEXT: %5:gpr64noip = COPY %1
109+
; ISEL-ELF-NEXT: LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %5, 0, implicit-def $x16, implicit-def $x17, implicit-def $nzcv
110+
; ISEL-ELF-NEXT: %4:gpr64 = COPY $x16
107111
; ISEL-ELF-NEXT: STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest)
108112
; ISEL-ELF-NEXT: RET_ReallyLR
109113
%dest.i = ptrtoint ptr %dest to i64

0 commit comments

Comments
 (0)