diff --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp --- a/llvm/lib/MC/MCWin64EH.cpp +++ b/llvm/lib/MC/MCWin64EH.cpp @@ -734,6 +734,7 @@ enum { Start, Start2, + Start3, IntRegs, FloatRegs, InputArgs, @@ -742,6 +743,7 @@ End } Location = Start; bool StandaloneLR = false, FPLRPair = false; + bool PAC = false; int StackOffset = 0; int Nops = 0; // Iterate over the prolog and check that all opcodes exactly match @@ -757,15 +759,21 @@ return false; Location = Start2; break; - case Win64EH::UOP_SaveR19R20X: + case Win64EH::UOP_PACSignReturnAddress: if (Location != Start2) return false; + PAC = true; + Location = Start3; + break; + case Win64EH::UOP_SaveR19R20X: + if (Location != Start2 && Location != Start3) + return false; Predecrement = Inst.Offset; RegI = 2; Location = IntRegs; break; case Win64EH::UOP_SaveRegX: - if (Location != Start2) + if (Location != Start2 && Location != Start3) return false; Predecrement = Inst.Offset; if (Inst.Register == 19) @@ -828,7 +836,7 @@ Location = InputArgs; break; case Win64EH::UOP_SaveFRegPX: - if (Location != Start2 || Inst.Register != 8) + if ((Location != Start2 && Location != Start3) || Inst.Register != 8) return false; Predecrement = Inst.Offset; RegF = 2; @@ -858,8 +866,9 @@ break; case Win64EH::UOP_AllocSmall: case Win64EH::UOP_AllocMedium: - if (Location != Start2 && Location != IntRegs && Location != FloatRegs && - Location != InputArgs && Location != StackAdjust) + if (Location != Start2 && Location != Start3 && Location != IntRegs && + Location != FloatRegs && Location != InputArgs && + Location != StackAdjust) return false; // Can have either a single decrement, or a pair of decrements with // 4080 and another decrement. @@ -874,8 +883,8 @@ case Win64EH::UOP_SaveFPLRX: // Not allowing FPLRX after StackAdjust; if a StackAdjust is used, it // should be followed by a FPLR instead. - if (Location != Start2 && Location != IntRegs && Location != FloatRegs && - Location != InputArgs) + if (Location != Start2 && Location != Start3 && Location != IntRegs && + Location != FloatRegs && Location != InputArgs) return false; StackOffset = Inst.Offset; Location = FrameRecord; @@ -903,6 +912,8 @@ return false; if (Nops != 0 && Nops != 4) return false; + if (PAC && !FPLRPair) + return false; int H = Nops == 4; // There's an inconsistency regarding packed unwind info with homed // parameters; according to the documentation, the epilog shouldn't have @@ -933,7 +944,7 @@ RegF--; // Convert from actual number of registers, to value stored assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier"); int Flag = 0x01; // Function segments not supported yet - int CR = FPLRPair ? 3 : StandaloneLR ? 1 : 0; + int CR = PAC ? 2 : FPLRPair ? 3 : StandaloneLR ? 1 : 0; info->PackedInfo |= Flag << 0; info->PackedInfo |= (FuncLength & 0x7FF) << 2; info->PackedInfo |= (RegF & 0x7) << 13; diff --git a/llvm/test/MC/AArch64/seh-packed-unwind.s b/llvm/test/MC/AArch64/seh-packed-unwind.s --- a/llvm/test/MC/AArch64/seh-packed-unwind.s +++ b/llvm/test/MC/AArch64/seh-packed-unwind.s @@ -243,6 +243,58 @@ // CHECK-NEXT: end // CHECK-NEXT: ] // CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func16 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 28 +// CHECK-NEXT: RegF: 0 +// CHECK-NEXT: RegI: 0 +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: CR: 2 +// CHECK-NEXT: FrameSize: 32 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: mov x29, sp +// CHECK-NEXT: stp x29, lr, [sp, #-32]! +// CHECK-NEXT: pacibsp +// CHECK-NEXT: end +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func17 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 40 +// CHECK-NEXT: RegF: 0 +// CHECK-NEXT: RegI: 2 +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: CR: 2 +// CHECK-NEXT: FrameSize: 48 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: mov x29, sp +// CHECK-NEXT: stp x29, lr, [sp, #-32]! +// CHECK-NEXT: stp x19, x20, [sp, #-16]! +// CHECK-NEXT: pacibsp +// CHECK-NEXT: end +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func18 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 56 +// CHECK-NEXT: RegF: 0 +// CHECK-NEXT: RegI: 2 +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: CR: 2 +// CHECK-NEXT: FrameSize: 4112 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: mov x29, sp +// CHECK-NEXT: stp x29, lr, [sp, #0] +// CHECK-NEXT: sub sp, sp, #16 +// CHECK-NEXT: sub sp, sp, #4080 +// CHECK-NEXT: stp x19, x20, [sp, #-16]! +// CHECK-NEXT: pacibsp +// CHECK-NEXT: end +// CHECK-NEXT: ] +// CHECK-NEXT: } // CHECK: RuntimeFunction { // CHECK-NEXT: Function: nonpacked1 // CHECK-NEXT: ExceptionRecord: @@ -307,6 +359,16 @@ // CHECK-NEXT: Function: nonpacked13 // CHECK-NEXT: ExceptionRecord: // CHECK-NEXT: ExceptionData { +// CHECK: EpiloguePacked: Yes +// CHECK: RuntimeFunction { +// CHECK-NEXT: Function: nonpacked14 +// CHECK-NEXT: ExceptionRecord: +// CHECK-NEXT: ExceptionData { +// CHECK: EpiloguePacked: Yes +// CHECK: RuntimeFunction { +// CHECK-NEXT: Function: nonpacked15 +// CHECK-NEXT: ExceptionRecord: +// CHECK-NEXT: ExceptionData { // CHECK: EpiloguePacked: Yes .text @@ -664,6 +726,83 @@ ret .seh_endproc +func16: + .seh_proc func16 + pacibsp + .seh_pac_sign_return_address + stp x29, lr, [sp, #-32]! + .seh_save_fplr_x 32 + mov x29, sp + .seh_set_fp + .seh_endprologue + nop + .seh_startepilogue + ldp x29, lr, [sp], #32 + .seh_save_fplr_x 32 + autibsp + .seh_pac_sign_return_address + .seh_endepilogue + ret + .seh_endproc + +func17: + .seh_proc func17 + pacibsp + .seh_pac_sign_return_address + stp x19, x20, [sp, #-16]! + .seh_save_r19r20_x 16 + stp x29, lr, [sp, #-32]! + .seh_save_fplr_x 32 + mov x29, sp + .seh_set_fp + .seh_endprologue + nop + .seh_startepilogue + mov sp, x29 + .seh_set_fp + ldp x29, lr, [sp], #32 + .seh_save_fplr_x 32 + ldp x19, x20, [sp], #16 + .seh_save_r19r20_x 16 + autibsp + .seh_pac_sign_return_address + .seh_endepilogue + ret + .seh_endproc + +func18: + .seh_proc func18 + pacibsp + .seh_pac_sign_return_address + stp x19, x20, [sp, #-16]! + .seh_save_r19r20_x 16 + sub sp, sp, #4080 + .seh_stackalloc 4080 + sub sp, sp, #16 + .seh_stackalloc 16 + stp x29, lr, [sp, #0] + .seh_save_fplr 0 + mov x29, sp + .seh_set_fp + .seh_endprologue + nop + .seh_startepilogue + mov sp, x29 + .seh_set_fp + ldp x29, lr, [sp, #0] + .seh_save_fplr 0 + add sp, sp, #16 + .seh_stackalloc 16 + add sp, sp, #4080 + .seh_stackalloc 4080 + ldp x19, x20, [sp], #16 + .seh_save_r19r20_x 16 + autibsp + .seh_pac_sign_return_address + .seh_endepilogue + ret + .seh_endproc + nonpacked1: .seh_proc nonpacked1 // Can't be packed; can't save integer registers after float registers. @@ -930,3 +1069,49 @@ .long 0 .text .seh_endproc + +nonpacked14: + .seh_proc nonpacked14 + // Can't be packed; a signed return address can only be expressed if + // we save both x29 and lr on the stack. + pacibsp + .seh_pac_sign_return_address + str lr, [sp, #-32]! + .seh_save_reg_x lr, 32 + .seh_endprologue + nop + .seh_startepilogue + ldr lr, [sp], #32 + .seh_save_reg_x lr, 32 + autibsp + .seh_pac_sign_return_address + .seh_endepilogue + ret + .seh_endproc + +nonpacked15: + .seh_proc nonpacked15 + // Can't be packed; a signed return address can only be expressed if + // we save both x29 and lr on the stack. + pacibsp + .seh_pac_sign_return_address + stp x19, x20, [sp, #-32]! + .seh_save_r19r20_x 32 + stp x21, lr, [sp, #16] + .seh_save_lrpair x21, 16 + sub sp, sp, #16 + .seh_stackalloc 16 + .seh_endprologue + nop + .seh_startepilogue + add sp, sp, #16 + .seh_stackalloc 16 + ldp x21, lr, [sp, #16] + .seh_save_lrpair x21, 16 + ldp x19, x20, [sp], #32 + .seh_save_r19r20_x 32 + autibsp + .seh_pac_sign_return_address + .seh_endepilogue + ret + .seh_endproc