From 6a9a67d9420282b3528aa29fdcff4ff9e3661621 Mon Sep 17 00:00:00 2001 From: Nico Hartmann Date: Wed, 12 Feb 2020 15:07:36 +0000 Subject: [PATCH] Revert "[arm64] Protect return addresses stored on stack" This reverts commit 137bfe47c9af56dcf8466e2736579616e51b86df. Reason for revert: https://ci.chromium.org/p/v8/builders/ci/V8%20Arm%20-%20debug/13072 Original change's description: > [arm64] Protect return addresses stored on stack > > This change uses the Arm v8.3 pointer authentication instructions in > order to protect return addresses stored on the stack. The generated > code signs the return address before storing on the stack and > authenticates it after loading it. This also changes the stack frame > iterator in order to authenticate stored return addresses and re-sign > them when needed, as well as the deoptimizer in order to sign saved > return addresses when creating new frames. This offers a level of > protection against ROP attacks. > > This functionality is enabled with the v8_control_flow_integrity flag > that this CL introduces. > > The code size effect of this change is small for Octane (up to 2% in > some cases but mostly much lower) and negligible for larger benchmarks, > however code size measurements are rather noisy. The performance impact > on current cores (where the instructions are NOPs) is single digit, > around 1-2% for ARES-6 and Octane, and tends to be smaller for big > cores than for little cores. > > Bug: v8:10026 > Change-Id: I0081f3938c56e2f24d8227e4640032749f4f8368 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1373782 > Commit-Queue: Georgia Kouveli > Reviewed-by: Ross McIlroy > Reviewed-by: Georg Neis > Cr-Commit-Position: refs/heads/master@{#66239} TBR=rmcilroy@chromium.org,mstarzinger@chromium.org,neis@chromium.org,georgia.kouveli@arm.com Change-Id: I57d5928949b0d403774550b9bf7dc0b08ce4e703 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: v8:10026 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2051952 Reviewed-by: Nico Hartmann Commit-Queue: Nico Hartmann Cr-Commit-Position: refs/heads/master@{#66242} --- BUILD.gn | 24 -- src/builtins/arm64/builtins-arm64.cc | 12 +- src/codegen/arm64/macro-assembler-arm64-inl.h | 160 ----------- src/codegen/arm64/macro-assembler-arm64.cc | 270 +++++++++++------- src/codegen/arm64/macro-assembler-arm64.h | 59 +--- .../backend/arm64/code-generator-arm64.cc | 23 +- .../arm64/unwinding-info-writer-arm64.cc | 3 - src/debug/arm64/debug-arm64.cc | 2 +- src/deoptimizer/arm/deoptimizer-arm.cc | 2 - src/deoptimizer/arm64/deoptimizer-arm64.cc | 18 -- src/deoptimizer/deoptimizer.cc | 13 +- src/deoptimizer/deoptimizer.h | 2 +- src/deoptimizer/ia32/deoptimizer-ia32.cc | 2 - src/deoptimizer/mips/deoptimizer-mips.cc | 2 - src/deoptimizer/mips64/deoptimizer-mips64.cc | 2 - src/deoptimizer/ppc/deoptimizer-ppc.cc | 2 - src/deoptimizer/s390/deoptimizer-s390.cc | 2 - src/deoptimizer/x64/deoptimizer-x64.cc | 10 +- src/diagnostics/unwinder.cc | 11 +- .../arm64/pointer-authentication-arm64.h | 164 ----------- src/execution/frames-inl.h | 11 - src/execution/frames.cc | 17 +- src/execution/frames.h | 9 +- src/execution/pointer-authentication-dummy.h | 56 ---- src/execution/pointer-authentication.h | 65 ----- .../arm64/regexp-macro-assembler-arm64.cc | 9 +- src/regexp/regexp-macro-assembler.cc | 12 +- test/cctest/cctest.h | 62 ---- test/cctest/test-assembler-arm64.cc | 18 +- test/cctest/test-sampler-api.cc | 63 ++++ test/cctest/test-unwinder-code-pages.cc | 74 ----- test/cctest/test-unwinder.cc | 100 +------ 32 files changed, 307 insertions(+), 972 deletions(-) delete mode 100644 src/execution/arm64/pointer-authentication-arm64.h delete mode 100644 src/execution/pointer-authentication-dummy.h delete mode 100644 src/execution/pointer-authentication.h diff --git a/BUILD.gn b/BUILD.gn index a0ffefb4da..9999cc008d 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -214,10 +214,6 @@ declare_args() { # Disable all snapshot compression. v8_enable_snapshot_compression = true - - # Enable control-flow integrity features, such as pointer authentication for - # ARM64. - v8_control_flow_integrity = false } # Derived defaults. @@ -277,9 +273,6 @@ assert(!v8_disable_write_barriers || v8_enable_single_generation, assert(v8_current_cpu != "x86" || !v8_untrusted_code_mitigations, "Untrusted code mitigations are unsupported on ia32") -assert(v8_current_cpu == "arm64" || !v8_control_flow_integrity, - "Control-flow integrity is only supported on arm64") - assert( !v8_enable_pointer_compression || !v8_enable_shared_ro_heap, "Pointer compression is not supported with shared read-only heap enabled") @@ -514,9 +507,6 @@ config("features") { if (v8_enable_snapshot_compression) { defines += [ "V8_SNAPSHOT_COMPRESSION" ] } - if (v8_control_flow_integrity) { - defines += [ "V8_ENABLE_CONTROL_FLOW_INTEGRITY" ] - } } config("toolchain") { @@ -559,12 +549,6 @@ config("toolchain") { } if (v8_current_cpu == "arm64") { defines += [ "V8_TARGET_ARCH_ARM64" ] - if (v8_control_flow_integrity) { - # TODO(v8:10026): Enable this in src/build. - if (current_cpu == "arm64") { - cflags += [ "-mbranch-protection=pac-ret" ] - } - } } # Mips64el/mipsel simulators. @@ -2259,7 +2243,6 @@ v8_source_set("v8_base_without_compiler") { "src/execution/microtask-queue.h", "src/execution/off-thread-isolate.cc", "src/execution/off-thread-isolate.h", - "src/execution/pointer-authentication.h", "src/execution/protectors-inl.h", "src/execution/protectors.cc", "src/execution/protectors.h", @@ -3041,10 +3024,6 @@ v8_source_set("v8_base_without_compiler") { "src/zone/zone.h", ] - if (!v8_control_flow_integrity) { - sources += [ "src/execution/pointer-authentication-dummy.h" ] - } - if (v8_enable_third_party_heap) { sources += v8_third_party_heap_files } @@ -3202,9 +3181,6 @@ v8_source_set("v8_base_without_compiler") { "src/regexp/arm64/regexp-macro-assembler-arm64.h", "src/wasm/baseline/arm64/liftoff-assembler-arm64.h", ] - if (v8_control_flow_integrity) { - sources += [ "src/execution/arm64/pointer-authentication-arm64.h" ] - } if (is_win) { sources += [ "src/diagnostics/unwinding-info-win64.cc", diff --git a/src/builtins/arm64/builtins-arm64.cc b/src/builtins/arm64/builtins-arm64.cc index 39d159f968..ddcf3af4b6 100644 --- a/src/builtins/arm64/builtins-arm64.cc +++ b/src/builtins/arm64/builtins-arm64.cc @@ -1187,7 +1187,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { // the frame (that is done below). __ Bind(&push_stack_frame); FrameScope frame_scope(masm, StackFrame::MANUAL); - __ Push(lr, fp, cp, closure); + __ Push(lr, fp, cp, closure); __ Add(fp, sp, StandardFrameConstants::kFixedFrameSizeFromFp); // Reset code age. @@ -1672,7 +1672,7 @@ void Generate_ContinueToBuiltinHelper(MacroAssembler* masm, // Restore fp, lr. __ Mov(sp, fp); - __ Pop(fp, lr); + __ Pop(fp, lr); __ LoadEntryFromBuiltinIndex(builtin); __ Jump(builtin); @@ -2053,7 +2053,7 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { namespace { void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { - __ Push(lr, fp); + __ Push(lr, fp); __ Mov(x11, StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)); __ Push(x11, x1); // x1: function __ SmiTag(x11, x0); // x0: number of arguments. @@ -2069,7 +2069,7 @@ void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { // then drop the parameters and the receiver. __ Ldr(x10, MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); __ Mov(sp, fp); - __ Pop(fp, lr); + __ Pop(fp, lr); // Drop actual parameters and receiver. __ SmiUntag(x10); @@ -3675,9 +3675,9 @@ void Builtins::Generate_DirectCEntry(MacroAssembler* masm) { // DirectCEntry places the return address on the stack (updated by the GC), // making the call GC safe. The irregexp backend relies on this. - __ Poke(lr, 0); // Store the return address. + __ Poke(lr, 0); // Store the return address. __ Blr(x10); // Call the C++ function. - __ Peek(lr, 0); // Return to calling code. + __ Peek(lr, 0); // Return to calling code. __ AssertFPCRState(); __ Ret(); } diff --git a/src/codegen/arm64/macro-assembler-arm64-inl.h b/src/codegen/arm64/macro-assembler-arm64-inl.h index 962533d78e..0128ec069c 100644 --- a/src/codegen/arm64/macro-assembler-arm64-inl.h +++ b/src/codegen/arm64/macro-assembler-arm64-inl.h @@ -1075,166 +1075,6 @@ void MacroAssembler::JumpIfNotSmi(Register value, Label* not_smi_label) { void TurboAssembler::jmp(Label* L) { B(L); } -template -void TurboAssembler::Push(const CPURegister& src0, const CPURegister& src1, - const CPURegister& src2, const CPURegister& src3) { - DCHECK(AreSameSizeAndType(src0, src1, src2, src3)); - DCHECK_IMPLIES((lr_mode == kSignLR), ((src0 == lr) || (src1 == lr) || - (src2 == lr) || (src3 == lr))); - DCHECK_IMPLIES((lr_mode == kDontStoreLR), ((src0 != lr) && (src1 != lr) && - (src2 != lr) && (src3 != lr))); - -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - if (lr_mode == kSignLR) { - Paciasp(); - } -#endif - - int count = 1 + src1.is_valid() + src2.is_valid() + src3.is_valid(); - int size = src0.SizeInBytes(); - DCHECK_EQ(0, (size * count) % 16); - - PushHelper(count, size, src0, src1, src2, src3); -} - -template -void TurboAssembler::Push(const Register& src0, const VRegister& src1) { - DCHECK_IMPLIES((lr_mode == kSignLR), ((src0 == lr) || (src1 == lr))); - DCHECK_IMPLIES((lr_mode == kDontStoreLR), ((src0 != lr) && (src1 != lr))); -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - if (lr_mode == kSignLR) { - Paciasp(); - } -#endif - - int size = src0.SizeInBytes() + src1.SizeInBytes(); - DCHECK_EQ(0, size % 16); - - // Reserve room for src0 and push src1. - str(src1, MemOperand(sp, -size, PreIndex)); - // Fill the gap with src0. - str(src0, MemOperand(sp, src1.SizeInBytes())); -} - -template -void TurboAssembler::Pop(const CPURegister& dst0, const CPURegister& dst1, - const CPURegister& dst2, const CPURegister& dst3) { - // It is not valid to pop into the same register more than once in one - // instruction, not even into the zero register. - DCHECK(!AreAliased(dst0, dst1, dst2, dst3)); - DCHECK(AreSameSizeAndType(dst0, dst1, dst2, dst3)); - DCHECK(dst0.is_valid()); - - int count = 1 + dst1.is_valid() + dst2.is_valid() + dst3.is_valid(); - int size = dst0.SizeInBytes(); - DCHECK_EQ(0, (size * count) % 16); - - PopHelper(count, size, dst0, dst1, dst2, dst3); - - DCHECK_IMPLIES((lr_mode == kAuthLR), ((dst0 == lr) || (dst1 == lr) || - (dst2 == lr) || (dst3 == lr))); - DCHECK_IMPLIES((lr_mode == kDontLoadLR), ((dst0 != lr) && (dst1 != lr)) && - (dst2 != lr) && (dst3 != lr)); - -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - if (lr_mode == kAuthLR) { - Autiasp(); - } -#endif -} - -template -void TurboAssembler::Poke(const CPURegister& src, const Operand& offset) { - DCHECK_IMPLIES((lr_mode == kSignLR), (src == lr)); - DCHECK_IMPLIES((lr_mode == kDontStoreLR), (src != lr)); -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - if (lr_mode == kSignLR) { - Paciasp(); - } -#endif - - if (offset.IsImmediate()) { - DCHECK_GE(offset.ImmediateValue(), 0); - } else if (emit_debug_code()) { - Cmp(xzr, offset); - Check(le, AbortReason::kStackAccessBelowStackPointer); - } - - Str(src, MemOperand(sp, offset)); -} - -template -void TurboAssembler::Peek(const CPURegister& dst, const Operand& offset) { - if (offset.IsImmediate()) { - DCHECK_GE(offset.ImmediateValue(), 0); - } else if (emit_debug_code()) { - Cmp(xzr, offset); - Check(le, AbortReason::kStackAccessBelowStackPointer); - } - - Ldr(dst, MemOperand(sp, offset)); - - DCHECK_IMPLIES((lr_mode == kAuthLR), (dst == lr)); - DCHECK_IMPLIES((lr_mode == kDontLoadLR), (dst != lr)); -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - if (lr_mode == kAuthLR) { - Autiasp(); - } -#endif -} - -template -void TurboAssembler::PushCPURegList(CPURegList registers) { - DCHECK_IMPLIES((lr_mode == kDontStoreLR), !registers.IncludesAliasOf(lr)); -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - if (lr_mode == kSignLR && registers.IncludesAliasOf(lr)) { - Paciasp(); - } -#endif - - int size = registers.RegisterSizeInBytes(); - DCHECK_EQ(0, (size * registers.Count()) % 16); - - // Push up to four registers at a time. - while (!registers.IsEmpty()) { - int count_before = registers.Count(); - const CPURegister& src0 = registers.PopHighestIndex(); - const CPURegister& src1 = registers.PopHighestIndex(); - const CPURegister& src2 = registers.PopHighestIndex(); - const CPURegister& src3 = registers.PopHighestIndex(); - int count = count_before - registers.Count(); - PushHelper(count, size, src0, src1, src2, src3); - } -} - -template -void TurboAssembler::PopCPURegList(CPURegList registers) { - int size = registers.RegisterSizeInBytes(); - DCHECK_EQ(0, (size * registers.Count()) % 16); - -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - bool contains_lr = registers.IncludesAliasOf(lr); - DCHECK_IMPLIES((lr_mode == kDontLoadLR), !contains_lr); -#endif - - // Pop up to four registers at a time. - while (!registers.IsEmpty()) { - int count_before = registers.Count(); - const CPURegister& dst0 = registers.PopLowestIndex(); - const CPURegister& dst1 = registers.PopLowestIndex(); - const CPURegister& dst2 = registers.PopLowestIndex(); - const CPURegister& dst3 = registers.PopLowestIndex(); - int count = count_before - registers.Count(); - PopHelper(count, size, dst0, dst1, dst2, dst3); - } - -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - if (lr_mode == kAuthLR && contains_lr) { - Autiasp(); - } -#endif -} - void TurboAssembler::Push(Handle handle) { UseScratchRegisterScope temps(this); Register tmp = temps.AcquireX(); diff --git a/src/codegen/arm64/macro-assembler-arm64.cc b/src/codegen/arm64/macro-assembler-arm64.cc index 6099f6b34e..874aec285d 100644 --- a/src/codegen/arm64/macro-assembler-arm64.cc +++ b/src/codegen/arm64/macro-assembler-arm64.cc @@ -60,7 +60,7 @@ int TurboAssembler::PushCallerSaved(SaveFPRegsMode fp_mode, list.Remove(exclusion); list.Align(); - PushCPURegList(list); + PushCPURegList(list); int bytes = list.Count() * kXRegSizeInBits / 8; @@ -84,7 +84,7 @@ int TurboAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion) { list.Remove(exclusion); list.Align(); - PopCPURegList(list); + PopCPURegList(list); bytes += list.Count() * kXRegSizeInBits / 8; return bytes; @@ -1045,6 +1045,17 @@ void TurboAssembler::Abs(const Register& rd, const Register& rm, // Abstracted stack operations. +void TurboAssembler::Push(const CPURegister& src0, const CPURegister& src1, + const CPURegister& src2, const CPURegister& src3) { + DCHECK(AreSameSizeAndType(src0, src1, src2, src3)); + + int count = 1 + src1.is_valid() + src2.is_valid() + src3.is_valid(); + int size = src0.SizeInBytes(); + DCHECK_EQ(0, (size * count) % 16); + + PushHelper(count, size, src0, src1, src2, src3); +} + void TurboAssembler::Push(const CPURegister& src0, const CPURegister& src1, const CPURegister& src2, const CPURegister& src3, const CPURegister& src4, const CPURegister& src5, @@ -1059,6 +1070,21 @@ void TurboAssembler::Push(const CPURegister& src0, const CPURegister& src1, PushHelper(count - 4, size, src4, src5, src6, src7); } +void TurboAssembler::Pop(const CPURegister& dst0, const CPURegister& dst1, + const CPURegister& dst2, const CPURegister& dst3) { + // It is not valid to pop into the same register more than once in one + // instruction, not even into the zero register. + DCHECK(!AreAliased(dst0, dst1, dst2, dst3)); + DCHECK(AreSameSizeAndType(dst0, dst1, dst2, dst3)); + DCHECK(dst0.is_valid()); + + int count = 1 + dst1.is_valid() + dst2.is_valid() + dst3.is_valid(); + int size = dst0.SizeInBytes(); + DCHECK_EQ(0, (size * count) % 16); + + PopHelper(count, size, dst0, dst1, dst2, dst3); +} + void TurboAssembler::Pop(const CPURegister& dst0, const CPURegister& dst1, const CPURegister& dst2, const CPURegister& dst3, const CPURegister& dst4, const CPURegister& dst5, @@ -1077,6 +1103,48 @@ void TurboAssembler::Pop(const CPURegister& dst0, const CPURegister& dst1, PopHelper(count - 4, size, dst4, dst5, dst6, dst7); } +void TurboAssembler::Push(const Register& src0, const VRegister& src1) { + int size = src0.SizeInBytes() + src1.SizeInBytes(); + DCHECK_EQ(0, size % 16); + + // Reserve room for src0 and push src1. + str(src1, MemOperand(sp, -size, PreIndex)); + // Fill the gap with src0. + str(src0, MemOperand(sp, src1.SizeInBytes())); +} + +void TurboAssembler::PushCPURegList(CPURegList registers) { + int size = registers.RegisterSizeInBytes(); + DCHECK_EQ(0, (size * registers.Count()) % 16); + + // Push up to four registers at a time. + while (!registers.IsEmpty()) { + int count_before = registers.Count(); + const CPURegister& src0 = registers.PopHighestIndex(); + const CPURegister& src1 = registers.PopHighestIndex(); + const CPURegister& src2 = registers.PopHighestIndex(); + const CPURegister& src3 = registers.PopHighestIndex(); + int count = count_before - registers.Count(); + PushHelper(count, size, src0, src1, src2, src3); + } +} + +void TurboAssembler::PopCPURegList(CPURegList registers) { + int size = registers.RegisterSizeInBytes(); + DCHECK_EQ(0, (size * registers.Count()) % 16); + + // Pop up to four registers at a time. + while (!registers.IsEmpty()) { + int count_before = registers.Count(); + const CPURegister& dst0 = registers.PopLowestIndex(); + const CPURegister& dst1 = registers.PopLowestIndex(); + const CPURegister& dst2 = registers.PopLowestIndex(); + const CPURegister& dst3 = registers.PopLowestIndex(); + int count = count_before - registers.Count(); + PopHelper(count, size, dst0, dst1, dst2, dst3); + } +} + void MacroAssembler::PushMultipleTimes(CPURegister src, Register count) { UseScratchRegisterScope temps(this); Register temp = temps.AcquireSameSizeAs(count); @@ -1181,6 +1249,28 @@ void TurboAssembler::PopHelper(int count, int size, const CPURegister& dst0, } } +void TurboAssembler::Poke(const CPURegister& src, const Operand& offset) { + if (offset.IsImmediate()) { + DCHECK_GE(offset.ImmediateValue(), 0); + } else if (emit_debug_code()) { + Cmp(xzr, offset); + Check(le, AbortReason::kStackAccessBelowStackPointer); + } + + Str(src, MemOperand(sp, offset)); +} + +void TurboAssembler::Peek(const CPURegister& dst, const Operand& offset) { + if (offset.IsImmediate()) { + DCHECK_GE(offset.ImmediateValue(), 0); + } else if (emit_debug_code()) { + Cmp(xzr, offset); + Check(le, AbortReason::kStackAccessBelowStackPointer); + } + + Ldr(dst, MemOperand(sp, offset)); +} + void TurboAssembler::PokePair(const CPURegister& src1, const CPURegister& src2, int offset) { DCHECK(AreSameSizeAndType(src1, src2)); @@ -1196,61 +1286,50 @@ void MacroAssembler::PeekPair(const CPURegister& dst1, const CPURegister& dst2, } void MacroAssembler::PushCalleeSavedRegisters() { -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - Paciasp(); -#endif + // Ensure that the macro-assembler doesn't use any scratch registers. + InstructionAccurateScope scope(this); - { - // Ensure that the macro-assembler doesn't use any scratch registers. - InstructionAccurateScope scope(this); + MemOperand tos(sp, -2 * static_cast(kXRegSize), PreIndex); - MemOperand tos(sp, -2 * static_cast(kXRegSize), PreIndex); + stp(d14, d15, tos); + stp(d12, d13, tos); + stp(d10, d11, tos); + stp(d8, d9, tos); - stp(d14, d15, tos); - stp(d12, d13, tos); - stp(d10, d11, tos); - stp(d8, d9, tos); + STATIC_ASSERT( + EntryFrameConstants::kCalleeSavedRegisterBytesPushedBeforeFpLrPair == + 8 * kSystemPointerSize); - STATIC_ASSERT( - EntryFrameConstants::kCalleeSavedRegisterBytesPushedBeforeFpLrPair == - 8 * kSystemPointerSize); - stp(x29, x30, tos); // fp, lr + stp(x29, x30, tos); // fp, lr - STATIC_ASSERT( - EntryFrameConstants::kCalleeSavedRegisterBytesPushedAfterFpLrPair == - 10 * kSystemPointerSize); + STATIC_ASSERT( + EntryFrameConstants::kCalleeSavedRegisterBytesPushedAfterFpLrPair == + 10 * kSystemPointerSize); - stp(x27, x28, tos); - stp(x25, x26, tos); - stp(x23, x24, tos); - stp(x21, x22, tos); - stp(x19, x20, tos); - } + stp(x27, x28, tos); + stp(x25, x26, tos); + stp(x23, x24, tos); + stp(x21, x22, tos); + stp(x19, x20, tos); } void MacroAssembler::PopCalleeSavedRegisters() { - { - // Ensure that the macro-assembler doesn't use any scratch registers. - InstructionAccurateScope scope(this); + // Ensure that the macro-assembler doesn't use any scratch registers. + InstructionAccurateScope scope(this); - MemOperand tos(sp, 2 * kXRegSize, PostIndex); + MemOperand tos(sp, 2 * kXRegSize, PostIndex); - ldp(x19, x20, tos); - ldp(x21, x22, tos); - ldp(x23, x24, tos); - ldp(x25, x26, tos); - ldp(x27, x28, tos); - ldp(x29, x30, tos); + ldp(x19, x20, tos); + ldp(x21, x22, tos); + ldp(x23, x24, tos); + ldp(x25, x26, tos); + ldp(x27, x28, tos); + ldp(x29, x30, tos); - ldp(d8, d9, tos); - ldp(d10, d11, tos); - ldp(d12, d13, tos); - ldp(d14, d15, tos); - } - -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - Autiasp(); -#endif + ldp(d8, d9, tos); + ldp(d10, d11, tos); + ldp(d12, d13, tos); + ldp(d14, d15, tos); } void TurboAssembler::AssertSpAligned() { @@ -1938,22 +2017,18 @@ void TurboAssembler::StoreReturnAddressAndCall(Register target) { // GC, since the callee function will return to it. UseScratchRegisterScope temps(this); - temps.Exclude(x16, x17); + Register scratch1 = temps.AcquireX(); Label return_location; - Adr(x17, &return_location); -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - Add(x16, sp, kSystemPointerSize); - Pacia1716(); -#endif - Poke(x17, 0); + Adr(scratch1, &return_location); + Poke(scratch1, 0); if (emit_debug_code()) { - // Verify that the slot below fp[kSPOffset]-8 points to the signed return - // location. - Ldr(x16, MemOperand(fp, ExitFrameConstants::kSPOffset)); - Ldr(x16, MemOperand(x16, -static_cast(kXRegSize))); - Cmp(x16, x17); + // Verify that the slot below fp[kSPOffset]-8 points to the return location. + Register scratch2 = temps.AcquireX(); + Ldr(scratch2, MemOperand(fp, ExitFrameConstants::kSPOffset)); + Ldr(scratch2, MemOperand(scratch2, -static_cast(kXRegSize))); + Cmp(scratch2, scratch1); Check(eq, AbortReason::kReturnAddressNotFoundInFrame); } @@ -2021,7 +2096,8 @@ void TurboAssembler::PrepareForTailCall(Register callee_args_count, // Restore caller's frame pointer and return address now as they will be // overwritten by the copying loop. - RestoreFPAndLR(); + Ldr(lr, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); + Ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); // Now copy callee arguments to the caller frame going backwards to avoid // callee arguments corruption (source and destination areas could overlap). @@ -2233,7 +2309,7 @@ void TurboAssembler::TruncateDoubleToI(Isolate* isolate, Zone* zone, TryConvertDoubleToInt64(result, double_input, &done); // If we fell through then inline version didn't succeed - call stub instead. - Push(lr, double_input); + Push(lr, double_input); // DoubleToI preserves any registers it needs to clobber. if (stub_mode == StubCallMode::kCallWasmRuntimeStub) { @@ -2246,8 +2322,7 @@ void TurboAssembler::TruncateDoubleToI(Isolate* isolate, Zone* zone, Ldr(result, MemOperand(sp, 0)); DCHECK_EQ(xzr.SizeInBytes(), double_input.SizeInBytes()); - // Pop into xzr here to drop the double input on the stack: - Pop(xzr, lr); + Pop(xzr, lr); // xzr to drop the double input on the stack. Bind(&done); // Keep our invariant that the upper 32 bits are zero. @@ -2255,7 +2330,7 @@ void TurboAssembler::TruncateDoubleToI(Isolate* isolate, Zone* zone, } void TurboAssembler::Prologue() { - Push(lr, fp, cp, x1); + Push(lr, fp, cp, x1); Add(fp, sp, StandardFrameConstants::kFixedFrameSizeFromFp); } @@ -2266,7 +2341,7 @@ void TurboAssembler::EnterFrame(StackFrame::Type type) { Register type_reg = temps.AcquireX(); Mov(type_reg, StackFrame::TypeToMarker(type)); // type_reg pushed twice for alignment. - Push(lr, fp, type_reg, type_reg); + Push(lr, fp, type_reg, type_reg); const int kFrameSize = TypedFrameConstants::kFixedFrameSizeFromFp + kSystemPointerSize; Add(fp, sp, kFrameSize); @@ -2279,7 +2354,7 @@ void TurboAssembler::EnterFrame(StackFrame::Type type) { type == StackFrame::WASM_EXIT) { Register type_reg = temps.AcquireX(); Mov(type_reg, StackFrame::TypeToMarker(type)); - Push(lr, fp); + Push(lr, fp); Mov(fp, sp); Push(type_reg, padreg); // sp[3] : lr @@ -2293,7 +2368,7 @@ void TurboAssembler::EnterFrame(StackFrame::Type type) { // Users of this frame type push a context pointer after the type field, // so do it here to keep the stack pointer aligned. - Push(lr, fp, type_reg, cp); + Push(lr, fp, type_reg, cp); // The context pointer isn't part of the fixed frame, so add an extra slot // to account for it. @@ -2310,7 +2385,7 @@ void TurboAssembler::LeaveFrame(StackFrame::Type type) { // Drop the execution stack down to the frame pointer and restore // the caller frame pointer and return address. Mov(sp, fp); - Pop(fp, lr); + Pop(fp, lr); } void MacroAssembler::ExitFramePreserveFPRegs() { @@ -2340,7 +2415,7 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, const Register& scratch, frame_type == StackFrame::BUILTIN_EXIT); // Set up the new stack frame. - Push(lr, fp); + Push(lr, fp); Mov(fp, sp); Mov(scratch, StackFrame::TypeToMarker(frame_type)); Push(scratch, xzr); @@ -2423,7 +2498,7 @@ void MacroAssembler::LeaveExitFrame(bool restore_doubles, // fp -> fp[0]: CallerFP (old fp) // fp[...]: The rest of the frame. Mov(sp, fp); - Pop(fp, lr); + Pop(fp, lr); } void MacroAssembler::LoadGlobalProxy(Register dst) { @@ -2676,19 +2751,25 @@ void MacroAssembler::RecordWriteField(Register object, int offset, void TurboAssembler::SaveRegisters(RegList registers) { DCHECK_GT(NumRegs(registers), 0); - CPURegList regs(CPURegister::kRegister, kXRegSizeInBits, registers); - // If we were saving LR, we might need to sign it. - DCHECK(!regs.IncludesAliasOf(lr)); - regs.Align(); + CPURegList regs(lr); + for (int i = 0; i < Register::kNumRegisters; ++i) { + if ((registers >> i) & 1u) { + regs.Combine(Register::XRegFromCode(i)); + } + } + PushCPURegList(regs); } void TurboAssembler::RestoreRegisters(RegList registers) { DCHECK_GT(NumRegs(registers), 0); - CPURegList regs(CPURegister::kRegister, kXRegSizeInBits, registers); - // If we were saving LR, we might need to sign it. - DCHECK(!regs.IncludesAliasOf(lr)); - regs.Align(); + CPURegList regs(lr); + for (int i = 0; i < Register::kNumRegisters; ++i) { + if ((registers >> i) & 1u) { + regs.Combine(Register::XRegFromCode(i)); + } + } + PopCPURegList(regs); } @@ -2843,11 +2924,11 @@ void MacroAssembler::RecordWrite(Register object, Operand offset, // Record the actual write. if (lr_status == kLRHasNotBeenSaved) { - Push(padreg, lr); + Push(padreg, lr); } CallRecordWriteStub(object, offset, remembered_set_action, fp_mode); if (lr_status == kLRHasNotBeenSaved) { - Pop(lr, padreg); + Pop(lr, padreg); } Bind(&done); @@ -3102,7 +3183,7 @@ void TurboAssembler::Printf(const char* format, CPURegister arg0, // Preserve all caller-saved registers as well as NZCV. // PushCPURegList asserts that the size of each list is a multiple of 16 // bytes. - PushCPURegList(saved_registers); + PushCPURegList(saved_registers); PushCPURegList(kCallerSavedV); // We can use caller-saved registers as scratch values (except for argN). @@ -3155,7 +3236,7 @@ void TurboAssembler::Printf(const char* format, CPURegister arg0, } PopCPURegList(kCallerSavedV); - PopCPURegList(saved_registers); + PopCPURegList(saved_registers); TmpList()->set_list(old_tmp_list); FPTmpList()->set_list(old_fp_tmp_list); @@ -3193,35 +3274,6 @@ void TurboAssembler::ResetSpeculationPoisonRegister() { Mov(kSpeculationPoisonRegister, -1); } -void TurboAssembler::RestoreFPAndLR() { - static_assert(StandardFrameConstants::kCallerFPOffset + kSystemPointerSize == - StandardFrameConstants::kCallerPCOffset, - "Offsets must be consecutive for ldp!"); -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - // Make sure we can use x16 and x17. - UseScratchRegisterScope temps(this); - temps.Exclude(x16, x17); - // We can load the return address directly into x17. - Add(x16, fp, StandardFrameConstants::kCallerSPOffset); - Ldp(fp, x17, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); - Autia1716(); - Mov(lr, x17); -#else - Ldp(fp, lr, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); -#endif -} - -void TurboAssembler::StoreReturnAddressInWasmExitFrame(Label* return_location) { - UseScratchRegisterScope temps(this); - temps.Exclude(x16, x17); - Adr(x17, return_location); -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - Add(x16, fp, WasmExitFrameConstants::kCallingPCOffset + kSystemPointerSize); - Pacia1716(); -#endif - Str(x17, MemOperand(fp, WasmExitFrameConstants::kCallingPCOffset)); -} - } // namespace internal } // namespace v8 diff --git a/src/codegen/arm64/macro-assembler-arm64.h b/src/codegen/arm64/macro-assembler-arm64.h index 965ec20ccd..735536c6cd 100644 --- a/src/codegen/arm64/macro-assembler-arm64.h +++ b/src/codegen/arm64/macro-assembler-arm64.h @@ -783,33 +783,20 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase { // The stack pointer must be aligned to 16 bytes on entry and the total size // of the specified registers must also be a multiple of 16 bytes. // - // Other than the registers passed into Pop, the stack pointer, (possibly) - // the system stack pointer and (possibly) the link register, these methods - // do not modify any other registers. - // - // Some of the methods take an optional LoadLRMode or StoreLRMode template - // argument, which specifies whether we need to sign the link register at the - // start of the operation, or authenticate it at the end of the operation, - // when control flow integrity measures are enabled. - // When the mode is kDontLoadLR or kDontStoreLR, LR must not be passed as an - // argument to the operation. - enum LoadLRMode { kAuthLR, kDontAuthLR, kDontLoadLR }; - enum StoreLRMode { kSignLR, kDontSignLR, kDontStoreLR }; - template + // Other than the registers passed into Pop, the stack pointer and (possibly) + // the system stack pointer, these methods do not modify any other registers. void Push(const CPURegister& src0, const CPURegister& src1 = NoReg, const CPURegister& src2 = NoReg, const CPURegister& src3 = NoReg); void Push(const CPURegister& src0, const CPURegister& src1, const CPURegister& src2, const CPURegister& src3, const CPURegister& src4, const CPURegister& src5 = NoReg, const CPURegister& src6 = NoReg, const CPURegister& src7 = NoReg); - template void Pop(const CPURegister& dst0, const CPURegister& dst1 = NoReg, const CPURegister& dst2 = NoReg, const CPURegister& dst3 = NoReg); void Pop(const CPURegister& dst0, const CPURegister& dst1, const CPURegister& dst2, const CPURegister& dst3, const CPURegister& dst4, const CPURegister& dst5 = NoReg, const CPURegister& dst6 = NoReg, const CPURegister& dst7 = NoReg); - template void Push(const Register& src0, const VRegister& src1); // This is a convenience method for pushing a single Handle. @@ -851,15 +838,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase { // kSRegSizeInBits are supported. // // Otherwise, (Push|Pop)(CPU|X|W|D|S)RegList is preferred. - // - // The methods take an optional LoadLRMode or StoreLRMode template argument. - // When control flow integrity measures are enabled and the link register is - // included in 'registers', passing kSignLR to PushCPURegList will sign the - // link register before pushing the list, and passing kAuthLR to - // PopCPURegList will authenticate it after popping the list. - template void PushCPURegList(CPURegList registers); - template void PopCPURegList(CPURegList registers); // Calculate how much stack space (in bytes) are required to store caller @@ -1063,18 +1042,10 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase { // Poke 'src' onto the stack. The offset is in bytes. The stack pointer must // be 16 byte aligned. - // When the optional template argument is kSignLR and control flow integrity - // measures are enabled, we sign the link register before poking it onto the - // stack. 'src' must be lr in this case. - template void Poke(const CPURegister& src, const Operand& offset); // Peek at a value on the stack, and put it in 'dst'. The offset is in bytes. // The stack pointer must be aligned to 16 bytes. - // When the optional template argument is kAuthLR and control flow integrity - // measures are enabled, we authenticate the link register after peeking the - // value. 'dst' must be lr in this case. - template void Peek(const CPURegister& dst, const Operand& offset); // Poke 'src1' and 'src2' onto the stack. The values written will be adjacent @@ -1326,12 +1297,6 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase { void DecompressAnyTagged(const Register& destination, const MemOperand& field_operand); - // Restore FP and LR from the values stored in the current frame. This will - // authenticate the LR when pointer authentication is enabled. - void RestoreFPAndLR(); - - void StoreReturnAddressInWasmExitFrame(Label* return_location); - protected: // The actual Push and Pop implementations. These don't generate any code // other than that required for the push or pop. This allows @@ -1660,27 +1625,21 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { tbx(vd, vn, vn2, vn3, vn4, vm); } - // For the 'lr_mode' template argument of the following methods, see - // PushCPURegList/PopCPURegList. - template inline void PushSizeRegList( RegList registers, unsigned reg_size, CPURegister::RegisterType type = CPURegister::kRegister) { - PushCPURegList(CPURegList(type, reg_size, registers)); + PushCPURegList(CPURegList(type, reg_size, registers)); } - template inline void PopSizeRegList( RegList registers, unsigned reg_size, CPURegister::RegisterType type = CPURegister::kRegister) { - PopCPURegList(CPURegList(type, reg_size, registers)); + PopCPURegList(CPURegList(type, reg_size, registers)); } - template inline void PushXRegList(RegList regs) { - PushSizeRegList(regs, kXRegSizeInBits); + PushSizeRegList(regs, kXRegSizeInBits); } - template inline void PopXRegList(RegList regs) { - PopSizeRegList(regs, kXRegSizeInBits); + PopSizeRegList(regs, kXRegSizeInBits); } inline void PushWRegList(RegList regs) { PushSizeRegList(regs, kWRegSizeInBits); @@ -1722,9 +1681,6 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { // Floating-point registers are pushed before general-purpose registers, and // thus get higher addresses. // - // When control flow integrity measures are enabled, this method signs the - // link register before pushing it. - // // Note that registers are not checked for invalid values. Use this method // only if you know that the GC won't try to examine the values on the stack. void PushCalleeSavedRegisters(); @@ -1735,9 +1691,6 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { // thus come from higher addresses. // Floating-point registers are popped after general-purpose registers, and // thus come from higher addresses. - // - // When control flow integrity measures are enabled, this method - // authenticates the link register after popping it. void PopCalleeSavedRegisters(); // Helpers ------------------------------------------------------------------ diff --git a/src/compiler/backend/arm64/code-generator-arm64.cc b/src/compiler/backend/arm64/code-generator-arm64.cc index 46a36128d1..c95bf988ec 100644 --- a/src/compiler/backend/arm64/code-generator-arm64.cc +++ b/src/compiler/backend/arm64/code-generator-arm64.cc @@ -291,7 +291,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs; if (must_save_lr_) { // We need to save and restore lr if the frame was elided. - __ Push(lr, padreg); + __ Push(lr, padreg); unwinding_info_writer_->MarkLinkRegisterOnTopOfStack(__ pc_offset(), sp); } if (mode_ == RecordWriteMode::kValueIsEphemeronKey) { @@ -307,7 +307,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { save_fp_mode); } if (must_save_lr_) { - __ Pop(padreg, lr); + __ Pop(padreg, lr); unwinding_info_writer_->MarkPopLinkRegisterFromTopOfStack(__ pc_offset()); } } @@ -496,14 +496,18 @@ void EmitMaybePoisonedFPLoad(CodeGenerator* codegen, InstructionCode opcode, void CodeGenerator::AssembleDeconstructFrame() { __ Mov(sp, fp); - __ Pop(fp, lr); + __ Pop(fp, lr); unwinding_info_writer_.MarkFrameDeconstructed(__ pc_offset()); } void CodeGenerator::AssemblePrepareTailCall() { if (frame_access_state()->has_frame()) { - __ RestoreFPAndLR(); + static_assert( + StandardFrameConstants::kCallerFPOffset + kSystemPointerSize == + StandardFrameConstants::kCallerPCOffset, + "Offsets must be consecutive for ldp!"); + __ Ldp(fp, lr, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); } frame_access_state()->SetFrameAccessToSP(); } @@ -775,7 +779,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( Label return_location; if (linkage()->GetIncomingDescriptor()->IsWasmCapiFunction()) { // Put the return address in a stack slot. - __ StoreReturnAddressInWasmExitFrame(&return_location); + Register scratch = x8; + __ Adr(scratch, &return_location); + __ Str(scratch, + MemOperand(fp, WasmExitFrameConstants::kCallingPCOffset)); } if (instr->InputAt(0)->IsImmediate()) { @@ -2805,7 +2812,7 @@ void CodeGenerator::AssembleConstructFrame() { if (call_descriptor->IsJSFunctionCall()) { __ Prologue(); } else { - __ Push(lr, fp); + __ Push(lr, fp); __ Mov(fp, sp); } unwinding_info_writer_.MarkFrameConstructed(__ pc_offset()); @@ -2955,7 +2962,7 @@ void CodeGenerator::AssembleConstructFrame() { // TODO(palfia): TF save list is not in sync with // CPURegList::GetCalleeSaved(): x30 is missing. // DCHECK(saves.list() == CPURegList::GetCalleeSaved().list()); - __ PushCPURegList(saves); + __ PushCPURegList(saves); if (returns != 0) { __ Claim(returns); @@ -2974,7 +2981,7 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) { // Restore registers. CPURegList saves = CPURegList(CPURegister::kRegister, kXRegSizeInBits, call_descriptor->CalleeSavedRegisters()); - __ PopCPURegList(saves); + __ PopCPURegList(saves); // Restore fp registers. CPURegList saves_fp = CPURegList(CPURegister::kVRegister, kDRegSizeInBits, diff --git a/src/compiler/backend/arm64/unwinding-info-writer-arm64.cc b/src/compiler/backend/arm64/unwinding-info-writer-arm64.cc index c8a570af53..3747019c7d 100644 --- a/src/compiler/backend/arm64/unwinding-info-writer-arm64.cc +++ b/src/compiler/backend/arm64/unwinding-info-writer-arm64.cc @@ -9,9 +9,6 @@ namespace v8 { namespace internal { namespace compiler { -// TODO(v8:10026): When using CFI, we need to generate unwinding info to tell -// the unwinder that return addresses are signed. - void UnwindingInfoWriter::BeginInstructionBlock(int pc_offset, const InstructionBlock* block) { if (!enabled()) return; diff --git a/src/debug/arm64/debug-arm64.cc b/src/debug/arm64/debug-arm64.cc index 251856e284..96cd8a7b74 100644 --- a/src/debug/arm64/debug-arm64.cc +++ b/src/debug/arm64/debug-arm64.cc @@ -38,7 +38,7 @@ void DebugCodegen::GenerateFrameDropperTrampoline(MacroAssembler* masm) { __ Ldr(x1, MemOperand(fp, StandardFrameConstants::kFunctionOffset)); __ Mov(sp, fp); - __ Pop(fp, lr); + __ Pop(fp, lr); // Frame, Return address. __ LoadTaggedPointerField( x0, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset)); diff --git a/src/deoptimizer/arm/deoptimizer-arm.cc b/src/deoptimizer/arm/deoptimizer-arm.cc index 5ca6807b1e..becdc93a4c 100644 --- a/src/deoptimizer/arm/deoptimizer-arm.cc +++ b/src/deoptimizer/arm/deoptimizer-arm.cc @@ -262,8 +262,6 @@ void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { UNREACHABLE(); } -void FrameDescription::SetPc(intptr_t pc) { pc_ = pc; } - #undef __ } // namespace internal diff --git a/src/deoptimizer/arm64/deoptimizer-arm64.cc b/src/deoptimizer/arm64/deoptimizer-arm64.cc index 1a13377077..300e65ab00 100644 --- a/src/deoptimizer/arm64/deoptimizer-arm64.cc +++ b/src/deoptimizer/arm64/deoptimizer-arm64.cc @@ -9,7 +9,6 @@ #include "src/codegen/safepoint-table.h" #include "src/deoptimizer/deoptimizer.h" #include "src/execution/frame-constants.h" -#include "src/execution/pointer-authentication.h" namespace v8 { namespace internal { @@ -289,9 +288,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm, __ Ldr(continuation, MemOperand(last_output_frame, FrameDescription::continuation_offset())); __ Ldr(lr, MemOperand(last_output_frame, FrameDescription::pc_offset())); -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - __ Autiasp(); -#endif __ Br(continuation); } @@ -301,14 +297,6 @@ Float32 RegisterValues::GetFloatRegister(unsigned n) const { } void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) { - // TODO(v8:10026): check that the pointer is still in the list of allowed - // builtins. - Address new_context = - static_cast
(GetTop()) + offset + kPCOnStackSize; - uint64_t old_context = GetTop() + GetFrameSize(); - PointerAuthentication::ReplaceContext(reinterpret_cast(&value), - old_context, new_context); - SetFrameSlot(offset, value); } @@ -321,12 +309,6 @@ void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { UNREACHABLE(); } -void FrameDescription::SetPc(intptr_t pc) { - // TODO(v8:10026): we should only accept a specific list of allowed builtins - // here. - pc_ = PointerAuthentication::SignPCWithSP(pc, GetTop()); -} - #undef __ } // namespace internal diff --git a/src/deoptimizer/deoptimizer.cc b/src/deoptimizer/deoptimizer.cc index 2e29ac9dfd..56431d4eea 100644 --- a/src/deoptimizer/deoptimizer.cc +++ b/src/deoptimizer/deoptimizer.cc @@ -14,7 +14,6 @@ #include "src/codegen/register-configuration.h" #include "src/diagnostics/disasm.h" #include "src/execution/frames-inl.h" -#include "src/execution/pointer-authentication.h" #include "src/execution/v8threads.h" #include "src/handles/global-handles.h" #include "src/heap/heap-inl.h" @@ -253,10 +252,7 @@ class ActivationsFinder : public ThreadVisitor { int trampoline_pc = safepoint.trampoline_pc(); DCHECK_IMPLIES(code == topmost_, safe_to_deopt_); // Replace the current pc on the stack with the trampoline. - // TODO(v8:10026): avoid replacing a signed pointer. - Address* pc_addr = it.frame()->pc_address(); - Address new_pc = code.raw_instruction_start() + trampoline_pc; - PointerAuthentication::ReplacePC(pc_addr, new_pc, kSystemPointerSize); + it.frame()->set_pc(code.raw_instruction_start() + trampoline_pc); } } } @@ -694,13 +690,6 @@ void Deoptimizer::DoComputeOutputFrames() { caller_fp_ = Memory(fp_address); caller_pc_ = Memory(fp_address + CommonFrameConstants::kCallerPCOffset); - // Sign caller_pc_ with caller_frame_top_ to be consistent with everything - // else here. - uint64_t sp = stack_fp_ + StandardFrameConstants::kCallerSPOffset; - // TODO(v8:10026): avoid replacing a signed pointer. - PointerAuthentication::ReplaceContext( - reinterpret_cast(&caller_pc_), sp, caller_frame_top_); - input_frame_context_ = Memory( fp_address + CommonFrameConstants::kContextOrFrameTypeOffset); diff --git a/src/deoptimizer/deoptimizer.h b/src/deoptimizer/deoptimizer.h index 58c65562d9..beb2a9aa50 100644 --- a/src/deoptimizer/deoptimizer.h +++ b/src/deoptimizer/deoptimizer.h @@ -712,7 +712,7 @@ class FrameDescription { void SetTop(intptr_t top) { top_ = top; } intptr_t GetPc() const { return pc_; } - void SetPc(intptr_t pc); + void SetPc(intptr_t pc) { pc_ = pc; } intptr_t GetFp() const { return fp_; } void SetFp(intptr_t fp) { fp_ = fp; } diff --git a/src/deoptimizer/ia32/deoptimizer-ia32.cc b/src/deoptimizer/ia32/deoptimizer-ia32.cc index fe14a3b646..2fd424a667 100644 --- a/src/deoptimizer/ia32/deoptimizer-ia32.cc +++ b/src/deoptimizer/ia32/deoptimizer-ia32.cc @@ -217,8 +217,6 @@ void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { UNREACHABLE(); } -void FrameDescription::SetPc(intptr_t pc) { pc_ = pc; } - #undef __ } // namespace internal diff --git a/src/deoptimizer/mips/deoptimizer-mips.cc b/src/deoptimizer/mips/deoptimizer-mips.cc index a7c374089a..bf82e2631b 100644 --- a/src/deoptimizer/mips/deoptimizer-mips.cc +++ b/src/deoptimizer/mips/deoptimizer-mips.cc @@ -236,8 +236,6 @@ void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { UNREACHABLE(); } -void FrameDescription::SetPc(intptr_t pc) { pc_ = pc; } - #undef __ } // namespace internal diff --git a/src/deoptimizer/mips64/deoptimizer-mips64.cc b/src/deoptimizer/mips64/deoptimizer-mips64.cc index 127c0f92e5..a1138d202f 100644 --- a/src/deoptimizer/mips64/deoptimizer-mips64.cc +++ b/src/deoptimizer/mips64/deoptimizer-mips64.cc @@ -236,8 +236,6 @@ void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { UNREACHABLE(); } -void FrameDescription::SetPc(intptr_t pc) { pc_ = pc; } - #undef __ } // namespace internal diff --git a/src/deoptimizer/ppc/deoptimizer-ppc.cc b/src/deoptimizer/ppc/deoptimizer-ppc.cc index 8e872e0f9c..1d05968806 100644 --- a/src/deoptimizer/ppc/deoptimizer-ppc.cc +++ b/src/deoptimizer/ppc/deoptimizer-ppc.cc @@ -258,8 +258,6 @@ void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { SetFrameSlot(offset, value); } -void FrameDescription::SetPc(intptr_t pc) { pc_ = pc; } - #undef __ } // namespace internal } // namespace v8 diff --git a/src/deoptimizer/s390/deoptimizer-s390.cc b/src/deoptimizer/s390/deoptimizer-s390.cc index 9833457145..63ea22f71a 100644 --- a/src/deoptimizer/s390/deoptimizer-s390.cc +++ b/src/deoptimizer/s390/deoptimizer-s390.cc @@ -254,8 +254,6 @@ void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { UNREACHABLE(); } -void FrameDescription::SetPc(intptr_t pc) { pc_ = pc; } - #undef __ } // namespace internal diff --git a/src/deoptimizer/x64/deoptimizer-x64.cc b/src/deoptimizer/x64/deoptimizer-x64.cc index e41bf88959..724062c506 100644 --- a/src/deoptimizer/x64/deoptimizer-x64.cc +++ b/src/deoptimizer/x64/deoptimizer-x64.cc @@ -221,10 +221,18 @@ Float32 RegisterValues::GetFloatRegister(unsigned n) const { } void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) { + if (kPCOnStackSize == 2 * kSystemPointerSize) { + // Zero out the high-32 bit of PC for x32 port. + SetFrameSlot(offset + kSystemPointerSize, 0); + } SetFrameSlot(offset, value); } void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) { + if (kFPOnStackSize == 2 * kSystemPointerSize) { + // Zero out the high-32 bit of FP for x32 port. + SetFrameSlot(offset + kSystemPointerSize, 0); + } SetFrameSlot(offset, value); } @@ -233,8 +241,6 @@ void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { UNREACHABLE(); } -void FrameDescription::SetPc(intptr_t pc) { pc_ = pc; } - #undef __ } // namespace internal diff --git a/src/diagnostics/unwinder.cc b/src/diagnostics/unwinder.cc index c08fe20330..64adf17b82 100644 --- a/src/diagnostics/unwinder.cc +++ b/src/diagnostics/unwinder.cc @@ -7,7 +7,6 @@ #include "include/v8.h" #include "src/common/globals.h" #include "src/execution/frame-constants.h" -#include "src/execution/pointer-authentication.h" namespace v8 { @@ -88,9 +87,8 @@ void* GetReturnAddressFromFP(void* fp, void* pc, caller_pc_offset = i::EntryFrameConstants::kDirectCallerPCOffset; } #endif - i::Address ret_addr = - Load(reinterpret_cast(fp) + caller_pc_offset); - return reinterpret_cast(i::PointerAuthentication::StripPAC(ret_addr)); + return reinterpret_cast( + Load(reinterpret_cast(fp) + caller_pc_offset)); } void* GetReturnAddressFromFP(void* fp, void* pc, @@ -101,9 +99,8 @@ void* GetReturnAddressFromFP(void* fp, void* pc, caller_pc_offset = i::EntryFrameConstants::kDirectCallerPCOffset; } #endif - i::Address ret_addr = - Load(reinterpret_cast(fp) + caller_pc_offset); - return reinterpret_cast(i::PointerAuthentication::StripPAC(ret_addr)); + return reinterpret_cast( + Load(reinterpret_cast(fp) + caller_pc_offset)); } void* GetCallerFPFromFP(void* fp, void* pc, diff --git a/src/execution/arm64/pointer-authentication-arm64.h b/src/execution/arm64/pointer-authentication-arm64.h deleted file mode 100644 index c54a59f29c..0000000000 --- a/src/execution/arm64/pointer-authentication-arm64.h +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2019 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_EXECUTION_ARM64_POINTER_AUTHENTICATION_ARM64_H_ -#define V8_EXECUTION_ARM64_POINTER_AUTHENTICATION_ARM64_H_ - -#include "src/execution/pointer-authentication.h" - -#include "src/common/globals.h" -#include "src/execution/arm64/simulator-arm64.h" - -// TODO(v8:10026): Replace hints with instruction aliases, when supported. -#define AUTIA1716 "hint #12" -#define PACIA1716 "hint #8" -#define XPACLRI "hint #7" - -namespace v8 { -namespace internal { - -// The following functions execute on the host and therefore need a different -// path based on whether we are simulating arm64 or not. - -// clang-format fails to detect this file as C++, turn it off. -// clang-format off - -// Authenticate the address stored in {pc_address}. {offset_from_sp} is the -// offset between {pc_address} and the pointer used as a context for signing. -V8_INLINE Address PointerAuthentication::AuthenticatePC( - Address* pc_address, unsigned offset_from_sp) { - uint64_t sp = reinterpret_cast(pc_address) + offset_from_sp; - uint64_t pc = reinterpret_cast(*pc_address); -#ifdef USE_SIMULATOR - pc = Simulator::AuthPAC(pc, sp, Simulator::kPACKeyIA, - Simulator::kInstructionPointer); -#else - asm volatile( - " mov x17, %[pc]\n" - " mov x16, %[stack_ptr]\n" - " " AUTIA1716 "\n" - " ldr xzr, [x17]\n" - " mov %[pc], x17\n" - : [pc] "+r"(pc) - : [stack_ptr] "r"(sp) - : "x16", "x17"); -#endif - return pc; -} - -// Strip Pointer Authentication Code (PAC) from {pc} and return the raw value. -V8_INLINE Address PointerAuthentication::StripPAC(Address pc) { -#ifdef USE_SIMULATOR - return Simulator::StripPAC(pc, Simulator::kInstructionPointer); -#else - asm volatile( - " mov x16, lr\n" - " mov lr, %[pc]\n" - " " XPACLRI "\n" - " mov %[pc], lr\n" - " mov lr, x16\n" - : [pc] "+r"(pc) - : - : "x16", "lr"); - return pc; -#endif -} - -// Sign {pc} using {sp}. -V8_INLINE Address PointerAuthentication::SignPCWithSP(Address pc, Address sp) { -#ifdef USE_SIMULATOR - return Simulator::AddPAC(pc, sp, Simulator::kPACKeyIA, - Simulator::kInstructionPointer); -#else - asm volatile( - " mov x17, %[pc]\n" - " mov x16, %[sp]\n" - " " PACIA1716 "\n" - " mov %[pc], x17\n" - : [pc] "+r"(pc) - : [sp] "r"(sp) - : "x16", "x17"); - return pc; -#endif -} - -// Authenticate the address stored in {pc_address} and replace it with -// {new_pc}, after signing it. {offset_from_sp} is the offset between -// {pc_address} and the pointer used as a context for signing. -V8_INLINE void PointerAuthentication::ReplacePC(Address* pc_address, - Address new_pc, - int offset_from_sp) { - uint64_t sp = reinterpret_cast(pc_address) + offset_from_sp; - uint64_t old_pc = reinterpret_cast(*pc_address); -#ifdef USE_SIMULATOR - uint64_t auth_old_pc = Simulator::AuthPAC(old_pc, sp, Simulator::kPACKeyIA, - Simulator::kInstructionPointer); - uint64_t raw_old_pc = - Simulator::StripPAC(old_pc, Simulator::kInstructionPointer); - // Verify that the old address is authenticated. - CHECK_EQ(auth_old_pc, raw_old_pc); - new_pc = Simulator::AddPAC(new_pc, sp, Simulator::kPACKeyIA, - Simulator::kInstructionPointer); -#else - // Only store newly signed address after we have verified that the old - // address is authenticated. - asm volatile( - " mov x17, %[new_pc]\n" - " mov x16, %[sp]\n" - " " PACIA1716 "\n" - " mov %[new_pc], x17\n" - " mov x17, %[old_pc]\n" - " " AUTIA1716 "\n" - " ldr xzr, [x17]\n" - : [new_pc] "+&r"(new_pc) - : [sp] "r"(sp), [old_pc] "r"(old_pc) - : "x16", "x17"); -#endif - *pc_address = new_pc; -} - -// Authenticate the address stored in {pc_address} based on {old_context} and -// replace it with the same address signed with {new_context} instead. -V8_INLINE void PointerAuthentication::ReplaceContext(Address* pc_address, - Address old_context, - Address new_context) { - uint64_t old_signed_pc = static_cast(*pc_address); - uint64_t new_pc; -#ifdef USE_SIMULATOR - uint64_t auth_pc = - Simulator::AuthPAC(old_signed_pc, old_context, Simulator::kPACKeyIA, - Simulator::kInstructionPointer); - uint64_t raw_pc = - Simulator::StripPAC(auth_pc, Simulator::kInstructionPointer); - // Verify that the old address is authenticated. - CHECK_EQ(raw_pc, auth_pc); - new_pc = Simulator::AddPAC(raw_pc, new_context, Simulator::kPACKeyIA, - Simulator::kInstructionPointer); -#else - // Only store newly signed address after we have verified that the old - // address is authenticated. - asm volatile( - " mov x17, %[old_pc]\n" - " mov x16, %[old_ctx]\n" - " " AUTIA1716 "\n" - " mov x16, %[new_ctx]\n" - " " PACIA1716 "\n" - " mov %[new_pc], x17\n" - " mov x17, %[old_pc]\n" - " mov x16, %[old_ctx]\n" - " " AUTIA1716 "\n" - " ldr xzr, [x17]\n" - : [new_pc] "=&r"(new_pc) - : [old_pc] "r"(old_signed_pc), [old_ctx] "r"(old_context), - [new_ctx] "r"(new_context) - : "x16", "x17"); -#endif - *pc_address = new_pc; -} - -// clang-format on - -} // namespace internal -} // namespace v8 -#endif // V8_EXECUTION_ARM64_POINTER_AUTHENTICATION_ARM64_H_ diff --git a/src/execution/frames-inl.h b/src/execution/frames-inl.h index 0c095a307c..f1b979b7be 100644 --- a/src/execution/frames-inl.h +++ b/src/execution/frames-inl.h @@ -9,7 +9,6 @@ #include "src/execution/frame-constants.h" #include "src/execution/frames.h" #include "src/execution/isolate.h" -#include "src/execution/pointer-authentication.h" #include "src/objects/objects-inl.h" namespace v8 { @@ -70,16 +69,6 @@ inline StackHandler* StackFrame::top_handler() const { return iterator_->handler(); } -inline Address StackFrame::callee_pc() const { - return state_.callee_pc_address ? ReadPC(state_.callee_pc_address) - : kNullAddress; -} - -inline Address StackFrame::pc() const { return ReadPC(pc_address()); } - -inline Address StackFrame::ReadPC(Address* pc_address) { - return PointerAuthentication::AuthenticatePC(pc_address, kSystemPointerSize); -} inline Address* StackFrame::ResolveReturnAddressLocation(Address* pc_address) { if (return_address_location_resolver_ == nullptr) { diff --git a/src/execution/frames.cc b/src/execution/frames.cc index 98bcdbbc2f..996f8c9595 100644 --- a/src/execution/frames.cc +++ b/src/execution/frames.cc @@ -491,18 +491,16 @@ Code StackFrame::LookupCode() const { void StackFrame::IteratePc(RootVisitor* v, Address* pc_address, Address* constant_pool_address, Code holder) { - Address old_pc = ReadPC(pc_address); + Address pc = *pc_address; DCHECK(ReadOnlyHeap::Contains(holder) || - holder.GetHeap()->GcSafeCodeContains(holder, old_pc)); - unsigned pc_offset = - static_cast(old_pc - holder.InstructionStart()); + holder.GetHeap()->GcSafeCodeContains(holder, pc)); + unsigned pc_offset = static_cast(pc - holder.InstructionStart()); Object code = holder; v->VisitRootPointer(Root::kTop, nullptr, FullObjectSlot(&code)); if (code == holder) return; holder = Code::unchecked_cast(code); - Address pc = holder.InstructionStart() + pc_offset; - // TODO(v8:10026): avoid replacing a signed pointer. - PointerAuthentication::ReplacePC(pc_address, pc, kSystemPointerSize); + pc = holder.InstructionStart() + pc_offset; + *pc_address = pc; if (FLAG_enable_embedded_constant_pool && constant_pool_address) { *constant_pool_address = holder.constant_pool(); } @@ -523,7 +521,6 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator, kSystemPointerSize); intptr_t marker = Memory( state->fp + CommonFrameConstants::kContextOrFrameTypeOffset); - Address pc = StackFrame::ReadPC(state->pc_address); if (!iterator->can_access_heap_objects_) { // TODO(titzer): "can_access_heap_objects" is kind of bogus. It really // means that we are being called from the profiler, which can interrupt @@ -538,13 +535,15 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator, if (!StackFrame::IsTypeMarker(marker)) { if (maybe_function.IsSmi()) { return NATIVE; - } else if (IsInterpreterFramePc(iterator->isolate(), pc, state)) { + } else if (IsInterpreterFramePc(iterator->isolate(), *(state->pc_address), + state)) { return INTERPRETED; } else { return OPTIMIZED; } } } else { + Address pc = *(state->pc_address); // If the {pc} does not point into WebAssembly code we can rely on the // returned {wasm_code} to be null and fall back to {GetContainingCode}. wasm::WasmCodeRefScope code_ref_scope; diff --git a/src/execution/frames.h b/src/execution/frames.h index 2eb8c8dfaa..3ffdee4b05 100644 --- a/src/execution/frames.h +++ b/src/execution/frames.h @@ -215,7 +215,9 @@ class StackFrame { // Accessors. Address sp() const { return state_.sp; } Address fp() const { return state_.fp; } - inline Address callee_pc() const; + Address callee_pc() const { + return state_.callee_pc_address ? *state_.callee_pc_address : kNullAddress; + } Address caller_sp() const { return GetCallerStackPointer(); } // If this frame is optimized and was dynamically aligned return its old @@ -223,7 +225,8 @@ class StackFrame { // up one word and become unaligned. Address UnpaddedFP() const; - inline Address pc() const; + Address pc() const { return *pc_address(); } + void set_pc(Address pc) { *pc_address() = pc; } Address constant_pool() const { return *constant_pool_address(); } void set_constant_pool(Address constant_pool) { @@ -262,8 +265,6 @@ class StackFrame { static void SetReturnAddressLocationResolver( ReturnAddressLocationResolver resolver); - static inline Address ReadPC(Address* pc_address); - // Resolves pc_address through the resolution address function if one is set. static inline Address* ResolveReturnAddressLocation(Address* pc_address); diff --git a/src/execution/pointer-authentication-dummy.h b/src/execution/pointer-authentication-dummy.h deleted file mode 100644 index 32a10dc0dd..0000000000 --- a/src/execution/pointer-authentication-dummy.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_EXECUTION_POINTER_AUTHENTICATION_DUMMY_H_ -#define V8_EXECUTION_POINTER_AUTHENTICATION_DUMMY_H_ - -#include "src/execution/pointer-authentication.h" - -#include "include/v8.h" -#include "src/base/macros.h" -#include "src/common/globals.h" - -namespace v8 { -namespace internal { - -// Dummy implementation of the PointerAuthentication class methods, to be used -// when CFI is not enabled. - -// Load return address from {pc_address} and return it. -V8_INLINE Address PointerAuthentication::AuthenticatePC( - Address* pc_address, unsigned offset_from_sp) { - USE(offset_from_sp); - return *pc_address; -} - -// Return {pc} unmodified. -V8_INLINE Address PointerAuthentication::StripPAC(Address pc) { return pc; } - -// Return {pc} unmodified. -V8_INLINE Address PointerAuthentication::SignPCWithSP(Address pc, Address sp) { - USE(sp); - return pc; -} - -// Store {new_pc} to {pc_address} without signing. -V8_INLINE void PointerAuthentication::ReplacePC(Address* pc_address, - Address new_pc, - int offset_from_sp) { - USE(offset_from_sp); - *pc_address = new_pc; -} - -// Do nothing. -V8_INLINE void PointerAuthentication::ReplaceContext(Address* pc_address, - Address old_context, - Address new_context) { - USE(pc_address); - USE(old_context); - USE(new_context); -} - -} // namespace internal -} // namespace v8 - -#endif // V8_EXECUTION_POINTER_AUTHENTICATION_DUMMY_H_ diff --git a/src/execution/pointer-authentication.h b/src/execution/pointer-authentication.h deleted file mode 100644 index f2d63773f4..0000000000 --- a/src/execution/pointer-authentication.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2019 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_EXECUTION_POINTER_AUTHENTICATION_H_ -#define V8_EXECUTION_POINTER_AUTHENTICATION_H_ - -#include "include/v8.h" -#include "src/base/macros.h" -#include "src/common/globals.h" - -namespace v8 { -namespace internal { - -class PointerAuthentication : public AllStatic { - public: - // When CFI is enabled, authenticate the address stored in {pc_address} and - // return the authenticated address. {offset_from_sp} is the offset between - // {pc_address} and the pointer used as a context for signing. - // When CFI is not enabled, simply load return address from {pc_address} and - // return it. - V8_INLINE static Address AuthenticatePC(Address* pc_address, - unsigned offset_from_sp); - - // When CFI is enabled, strip Pointer Authentication Code (PAC) from {pc} and - // return the raw value. - // When CFI is not enabled, return {pc} unmodified. - V8_INLINE static Address StripPAC(Address pc); - - // When CFI is enabled, sign {pc} using {sp} and return the signed value. - // When CFI is not enabled, return {pc} unmodified. - V8_INLINE static Address SignPCWithSP(Address pc, Address sp); - - // When CFI is enabled, authenticate the address stored in {pc_address} and - // replace it with {new_pc}, after signing it. {offset_from_sp} is the offset - // between {pc_address} and the pointer used as a context for signing. - // When CFI is not enabled, store {new_pc} to {pc_address} without signing. - V8_INLINE static void ReplacePC(Address* pc_address, Address new_pc, - int offset_from_sp); - - // When CFI is enabled, authenticate the address stored in {pc_address} based - // on {old_context} and replace it with the same address signed with - // {new_context} instead. - // When CFI is not enabled, do nothing. - V8_INLINE static void ReplaceContext(Address* pc_address, Address old_context, - Address new_context); -}; - -} // namespace internal -} // namespace v8 - -#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY - -#ifndef V8_TARGET_ARCH_ARM64 -#error "V8_ENABLE_CONTROL_FLOW_INTEGRITY should imply V8_TARGET_ARCH_ARM64" -#endif -#include "src/execution/arm64/pointer-authentication-arm64.h" - -#else - -#include "src/execution/pointer-authentication-dummy.h" - -#endif - -#endif // V8_EXECUTION_POINTER_AUTHENTICATION_H_ diff --git a/src/regexp/arm64/regexp-macro-assembler-arm64.cc b/src/regexp/arm64/regexp-macro-assembler-arm64.cc index ba5d51d660..56658819b1 100644 --- a/src/regexp/arm64/regexp-macro-assembler-arm64.cc +++ b/src/regexp/arm64/regexp-macro-assembler-arm64.cc @@ -740,8 +740,7 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { DCHECK_EQ(11, kCalleeSaved.Count()); registers_to_retain.Combine(lr); - DCHECK(registers_to_retain.IncludesAliasOf(lr)); - __ PushCPURegList(registers_to_retain); + __ PushCPURegList(registers_to_retain); __ PushCPURegList(argument_registers); // Set frame pointer in place. @@ -1036,7 +1035,7 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { __ Mov(sp, fp); // Restore registers. - __ PopCPURegList(registers_to_retain); + __ PopCPURegList(registers_to_retain); __ Ret(); @@ -1586,14 +1585,14 @@ void RegExpMacroAssemblerARM64::CallIf(Label* to, Condition condition) { void RegExpMacroAssemblerARM64::RestoreLinkRegister() { - __ Pop(padreg, lr); + __ Pop(lr, xzr); __ Add(lr, lr, Operand(masm_->CodeObject())); } void RegExpMacroAssemblerARM64::SaveLinkRegister() { __ Sub(lr, lr, Operand(masm_->CodeObject())); - __ Push(lr, padreg); + __ Push(xzr, lr); } diff --git a/src/regexp/regexp-macro-assembler.cc b/src/regexp/regexp-macro-assembler.cc index 7fd55495ec..30a9955dc3 100644 --- a/src/regexp/regexp-macro-assembler.cc +++ b/src/regexp/regexp-macro-assembler.cc @@ -6,7 +6,6 @@ #include "src/codegen/assembler.h" #include "src/execution/isolate-inl.h" -#include "src/execution/pointer-authentication.h" #include "src/execution/simulator.h" #include "src/regexp/regexp-stack.h" #include "src/strings/unicode-inl.h" @@ -150,10 +149,9 @@ int NativeRegExpMacroAssembler::CheckStackGuardState( Address* return_address, Code re_code, Address* subject, const byte** input_start, const byte** input_end) { DisallowHeapAllocation no_gc; - Address old_pc = PointerAuthentication::AuthenticatePC(return_address, 0); - DCHECK_LE(re_code.raw_instruction_start(), old_pc); - DCHECK_LE(old_pc, re_code.raw_instruction_end()); + DCHECK(re_code.raw_instruction_start() <= *return_address); + DCHECK(*return_address <= re_code.raw_instruction_end()); StackLimitCheck check(isolate); bool js_has_overflowed = check.JsHasOverflowed(); @@ -195,11 +193,9 @@ int NativeRegExpMacroAssembler::CheckStackGuardState( } if (*code_handle != re_code) { // Return address no longer valid - // Overwrite the return address on the stack. intptr_t delta = code_handle->address() - re_code.address(); - Address new_pc = old_pc + delta; - // TODO(v8:10026): avoid replacing a signed pointer. - PointerAuthentication::ReplacePC(return_address, new_pc, 0); + // Overwrite the return address on the stack. + *return_address += delta; } // If we continue, we need to update the subject string addresses. diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h index 4db0dea049..8a5a5a6d31 100644 --- a/test/cctest/cctest.h +++ b/test/cctest/cctest.h @@ -36,7 +36,6 @@ #include "src/codegen/register-configuration.h" #include "src/debug/debug-interface.h" #include "src/execution/isolate.h" -#include "src/execution/simulator.h" #include "src/flags/flags.h" #include "src/heap/factory.h" #include "src/init/v8.h" @@ -736,65 +735,4 @@ class TestPlatform : public v8::Platform { DISALLOW_COPY_AND_ASSIGN(TestPlatform); }; -#if defined(USE_SIMULATOR) -class SimulatorHelper { - public: - inline bool Init(v8::Isolate* isolate) { - simulator_ = reinterpret_cast(isolate) - ->thread_local_top() - ->simulator_; - // Check if there is active simulator. - return simulator_ != nullptr; - } - - inline void FillRegisters(v8::RegisterState* state) { -#if V8_TARGET_ARCH_ARM - state->pc = reinterpret_cast(simulator_->get_pc()); - state->sp = reinterpret_cast( - simulator_->get_register(v8::internal::Simulator::sp)); - state->fp = reinterpret_cast( - simulator_->get_register(v8::internal::Simulator::r11)); - state->lr = reinterpret_cast( - simulator_->get_register(v8::internal::Simulator::lr)); -#elif V8_TARGET_ARCH_ARM64 - if (simulator_->sp() == 0 || simulator_->fp() == 0) { - // It's possible that the simulator is interrupted while it is updating - // the sp or fp register. ARM64 simulator does this in two steps: - // first setting it to zero and then setting it to a new value. - // Bailout if sp/fp doesn't contain the new value. - return; - } - state->pc = reinterpret_cast(simulator_->pc()); - state->sp = reinterpret_cast(simulator_->sp()); - state->fp = reinterpret_cast(simulator_->fp()); - state->lr = reinterpret_cast(simulator_->lr()); -#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 - state->pc = reinterpret_cast(simulator_->get_pc()); - state->sp = reinterpret_cast( - simulator_->get_register(v8::internal::Simulator::sp)); - state->fp = reinterpret_cast( - simulator_->get_register(v8::internal::Simulator::fp)); -#elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64 - state->pc = reinterpret_cast(simulator_->get_pc()); - state->sp = reinterpret_cast( - simulator_->get_register(v8::internal::Simulator::sp)); - state->fp = reinterpret_cast( - simulator_->get_register(v8::internal::Simulator::fp)); - state->lr = reinterpret_cast(simulator_->get_lr()); -#elif V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X - state->pc = reinterpret_cast(simulator_->get_pc()); - state->sp = reinterpret_cast( - simulator_->get_register(v8::internal::Simulator::sp)); - state->fp = reinterpret_cast( - simulator_->get_register(v8::internal::Simulator::fp)); - state->lr = reinterpret_cast( - simulator_->get_register(v8::internal::Simulator::ra)); -#endif - } - - private: - v8::internal::Simulator* simulator_; -}; -#endif // USE_SIMULATOR - #endif // ifndef CCTEST_H_ diff --git a/test/cctest/test-assembler-arm64.cc b/test/cctest/test-assembler-arm64.cc index 52107c6c5a..0665f7a1f7 100644 --- a/test/cctest/test-assembler-arm64.cc +++ b/test/cctest/test-assembler-arm64.cc @@ -12227,8 +12227,7 @@ static void PushPopSimpleHelper(int reg_count, int reg_size, case PushPopByFour: // Push high-numbered registers first (to the highest addresses). for (i = reg_count; i >= 4; i -= 4) { - __ Push(r[i - 1], r[i - 2], r[i - 3], - r[i - 4]); + __ Push(r[i-1], r[i-2], r[i-3], r[i-4]); } // Finish off the leftovers. switch (i) { @@ -12241,7 +12240,7 @@ static void PushPopSimpleHelper(int reg_count, int reg_size, } break; case PushPopRegList: - __ PushSizeRegList(list, reg_size); + __ PushSizeRegList(list, reg_size); break; } @@ -12252,8 +12251,7 @@ static void PushPopSimpleHelper(int reg_count, int reg_size, case PushPopByFour: // Pop low-numbered registers first (from the lowest addresses). for (i = 0; i <= (reg_count-4); i += 4) { - __ Pop(r[i], r[i + 1], r[i + 2], - r[i + 3]); + __ Pop(r[i], r[i+1], r[i+2], r[i+3]); } // Finish off the leftovers. switch (reg_count - i) { @@ -12266,7 +12264,7 @@ static void PushPopSimpleHelper(int reg_count, int reg_size, } break; case PushPopRegList: - __ PopSizeRegList(list, reg_size); + __ PopSizeRegList(list, reg_size); break; } } @@ -12599,8 +12597,8 @@ TEST(push_pop) { __ PopXRegList(0); // Don't push/pop x18 (platform register) or xzr (for alignment) RegList all_regs = 0xFFFFFFFF & ~(x18.bit() | x31.bit()); - __ PushXRegList(all_regs); - __ PopXRegList(all_regs); + __ PushXRegList(all_regs); + __ PopXRegList(all_regs); __ Drop(12); END(); @@ -14599,13 +14597,13 @@ TEST(near_call_no_relocation) { __ Bind(&test); __ Mov(x0, 0x0); - __ Push(lr, xzr); + __ Push(lr, xzr); { Assembler::BlockConstPoolScope scope(&masm); int offset = (function.pos() - __ pc_offset()) / kInstrSize; __ near_call(offset, RelocInfo::NONE); } - __ Pop(xzr, lr); + __ Pop(xzr, lr); END(); RUN(); diff --git a/test/cctest/test-sampler-api.cc b/test/cctest/test-sampler-api.cc index 7197101d41..3c8f352551 100644 --- a/test/cctest/test-sampler-api.cc +++ b/test/cctest/test-sampler-api.cc @@ -7,6 +7,7 @@ #include #include #include "include/v8.h" +#include "src/execution/simulator.h" #include "src/flags/flags.h" #include "test/cctest/cctest.h" @@ -30,6 +31,68 @@ class Sample { }; +#if defined(USE_SIMULATOR) +class SimulatorHelper { + public: + inline bool Init(v8::Isolate* isolate) { + simulator_ = reinterpret_cast(isolate) + ->thread_local_top() + ->simulator_; + // Check if there is active simulator. + return simulator_ != nullptr; + } + + inline void FillRegisters(v8::RegisterState* state) { +#if V8_TARGET_ARCH_ARM + state->pc = reinterpret_cast(simulator_->get_pc()); + state->sp = reinterpret_cast( + simulator_->get_register(v8::internal::Simulator::sp)); + state->fp = reinterpret_cast( + simulator_->get_register(v8::internal::Simulator::r11)); + state->lr = reinterpret_cast( + simulator_->get_register(v8::internal::Simulator::lr)); +#elif V8_TARGET_ARCH_ARM64 + if (simulator_->sp() == 0 || simulator_->fp() == 0) { + // It's possible that the simulator is interrupted while it is updating + // the sp or fp register. ARM64 simulator does this in two steps: + // first setting it to zero and then setting it to a new value. + // Bailout if sp/fp doesn't contain the new value. + return; + } + state->pc = reinterpret_cast(simulator_->pc()); + state->sp = reinterpret_cast(simulator_->sp()); + state->fp = reinterpret_cast(simulator_->fp()); + state->lr = reinterpret_cast(simulator_->lr()); +#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 + state->pc = reinterpret_cast(simulator_->get_pc()); + state->sp = reinterpret_cast( + simulator_->get_register(v8::internal::Simulator::sp)); + state->fp = reinterpret_cast( + simulator_->get_register(v8::internal::Simulator::fp)); +#elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64 + state->pc = reinterpret_cast(simulator_->get_pc()); + state->sp = reinterpret_cast( + simulator_->get_register(v8::internal::Simulator::sp)); + state->fp = reinterpret_cast( + simulator_->get_register(v8::internal::Simulator::fp)); + state->lr = reinterpret_cast(simulator_->get_lr()); +#elif V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X + state->pc = reinterpret_cast(simulator_->get_pc()); + state->sp = reinterpret_cast( + simulator_->get_register(v8::internal::Simulator::sp)); + state->fp = reinterpret_cast( + simulator_->get_register(v8::internal::Simulator::fp)); + state->lr = reinterpret_cast( + simulator_->get_register(v8::internal::Simulator::ra)); +#endif + } + + private: + v8::internal::Simulator* simulator_; +}; +#endif // USE_SIMULATOR + + class SamplingTestHelper { public: struct CodeEventEntry { diff --git a/test/cctest/test-unwinder-code-pages.cc b/test/cctest/test-unwinder-code-pages.cc index fc023e4145..6177be6de8 100644 --- a/test/cctest/test-unwinder-code-pages.cc +++ b/test/cctest/test-unwinder-code-pages.cc @@ -591,80 +591,6 @@ TEST(PCIsInV8_LargeCodeObject_CodePagesAPI) { CHECK(v8::Unwinder::PCIsInV8(pages_length, code_pages, pc)); } -#ifdef USE_SIMULATOR -// TODO(v8:10026): Make this also work without the simulator. The part that -// needs modifications is getting the RegisterState. -class UnwinderTestHelper { - public: - explicit UnwinderTestHelper(const std::string& test_function) - : isolate_(CcTest::isolate()) { - CHECK(!instance_); - instance_ = this; - v8::HandleScope scope(isolate_); - v8::Local global = v8::ObjectTemplate::New(isolate_); - global->Set(v8_str("TryUnwind"), - v8::FunctionTemplate::New(isolate_, TryUnwind)); - LocalContext env(isolate_, nullptr, global); - CompileRun(v8_str(test_function.c_str())); - } - - ~UnwinderTestHelper() { instance_ = nullptr; } - - private: - static void TryUnwind(const v8::FunctionCallbackInfo& args) { - instance_->DoTryUnwind(); - } - - void DoTryUnwind() { - // Set up RegisterState. - v8::RegisterState register_state; - SimulatorHelper simulator_helper; - if (!simulator_helper.Init(isolate_)) return; - simulator_helper.FillRegisters(®ister_state); - // At this point, the PC will point to a Redirection object, which is not - // in V8 as far as the unwinder is concerned. To make this work, point to - // the return address, which is in V8, instead. - register_state.pc = register_state.lr; - - JSEntryStubs entry_stubs = isolate_->GetJSEntryStubs(); - MemoryRange code_pages[v8::Isolate::kMinCodePagesBufferSize]; - size_t pages_length = - isolate_->CopyCodePages(arraysize(code_pages), code_pages); - CHECK_LE(pages_length, arraysize(code_pages)); - - void* stack_base = reinterpret_cast(0xffffffffffffffffL); - bool unwound = v8::Unwinder::TryUnwindV8Frames( - entry_stubs, pages_length, code_pages, ®ister_state, stack_base); - // Check that we have successfully unwound past js_entry_sp. - CHECK(unwound); - CHECK_GT(register_state.sp, - reinterpret_cast(CcTest::i_isolate()->js_entry_sp())); - } - - v8::Isolate* isolate_; - - static UnwinderTestHelper* instance_; -}; - -UnwinderTestHelper* UnwinderTestHelper::instance_; - -TEST(Unwind_TwoNestedFunctions_CodePagesAPI) { - i::FLAG_allow_natives_syntax = true; - const char* test_script = - "function test_unwinder_api_inner() {" - " TryUnwind();" - " return 0;" - "}" - "function test_unwinder_api_outer() {" - " return test_unwinder_api_inner();" - "}" - "%NeverOptimizeFunction(test_unwinder_api_inner);" - "%NeverOptimizeFunction(test_unwinder_api_outer);" - "test_unwinder_api_outer();"; - - UnwinderTestHelper helper(test_script); -} -#endif } // namespace test_unwinder_code_pages } // namespace internal } // namespace v8 diff --git a/test/cctest/test-unwinder.cc b/test/cctest/test-unwinder.cc index 59c8708767..ffe46f4ca2 100644 --- a/test/cctest/test-unwinder.cc +++ b/test/cctest/test-unwinder.cc @@ -7,7 +7,6 @@ #include "src/api/api-inl.h" #include "src/builtins/builtins.h" #include "src/execution/isolate.h" -#include "src/execution/pointer-authentication.h" #include "src/heap/spaces.h" #include "src/objects/code-inl.h" #include "test/cctest/cctest.h" @@ -39,11 +38,6 @@ TEST(Unwind_BadState_Fail) { CHECK_NULL(register_state.pc); } -void StorePc(uintptr_t stack[], int index, uintptr_t pc) { - Address sp = reinterpret_cast
(&stack[index]) + kSystemPointerSize; - stack[index] = PointerAuthentication::SignPCWithSP(pc, sp); -} - TEST(Unwind_BuiltinPCInMiddle_Success) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); @@ -55,7 +49,7 @@ TEST(Unwind_BuiltinPCInMiddle_Success) { uintptr_t stack[3]; void* stack_base = stack + arraysize(stack); stack[0] = reinterpret_cast(stack + 2); // saved FP (rbp). - StorePc(stack, 1, 202); // Return address into C++ code. + stack[1] = 202; // Return address into C++ code. stack[2] = 303; // The SP points here in the caller's frame. register_state.sp = stack; @@ -99,9 +93,9 @@ TEST(Unwind_BuiltinPCAtStart_Success) { stack[0] = 101; // Return address into JS code. It doesn't matter that this is not actually in // JSEntry, because we only check that for the top frame. - StorePc(stack, 1, reinterpret_cast(code + 10)); + stack[1] = reinterpret_cast(code + 10); stack[2] = reinterpret_cast(stack + 5); // saved FP (rbp). - StorePc(stack, 3, 303); // Return address into C++ code. + stack[3] = 303; // Return address into C++ code. stack[4] = 404; stack[5] = 505; @@ -151,7 +145,7 @@ TEST(Unwind_CodeObjectPCInMiddle_Success) { uintptr_t stack[3]; void* stack_base = stack + arraysize(stack); stack[0] = reinterpret_cast(stack + 2); // saved FP (rbp). - StorePc(stack, 1, 202); // Return address into C++ code. + stack[1] = 202; // Return address into C++ code. stack[2] = 303; // The SP points here in the caller's frame. register_state.sp = stack; @@ -219,7 +213,7 @@ TEST(Unwind_JSEntryBeforeFrame_Fail) { stack[3] = 131; stack[4] = 141; stack[5] = 151; - StorePc(stack, 6, 100); // Return address into C++ code. + stack[6] = 100; // Return address into C++ code. stack[7] = 303; // The SP points here in the caller's frame. stack[8] = 404; stack[9] = 505; @@ -273,7 +267,7 @@ TEST(Unwind_OneJSFrame_Success) { stack[3] = 131; stack[4] = 141; stack[5] = reinterpret_cast(stack + 9); // saved FP (rbp). - StorePc(stack, 6, 100); // Return address into C++ code. + stack[6] = 100; // Return address into C++ code. stack[7] = 303; // The SP points here in the caller's frame. stack[8] = 404; stack[9] = 505; @@ -317,10 +311,10 @@ TEST(Unwind_TwoJSFrames_Success) { stack[1] = 111; stack[2] = reinterpret_cast(stack + 5); // saved FP (rbp). // The fake return address is in the JS code range. - StorePc(stack, 3, reinterpret_cast(code + 10)); + stack[3] = reinterpret_cast(code + 10); stack[4] = 141; stack[5] = reinterpret_cast(stack + 9); // saved FP (rbp). - StorePc(stack, 6, 100); // Return address into C++ code. + stack[6] = 100; // Return address into C++ code. stack[7] = 303; // The SP points here in the caller's frame. stack[8] = 404; stack[9] = 505; @@ -377,7 +371,7 @@ TEST(Unwind_StackBounds_Basic) { uintptr_t stack[3]; stack[0] = reinterpret_cast(stack + 2); // saved FP (rbp). - StorePc(stack, 1, 202); // Return address into C++ code. + stack[1] = 202; // Return address into C++ code. stack[2] = 303; // The SP points here in the caller's frame. register_state.sp = stack; @@ -420,12 +414,12 @@ TEST(Unwind_StackBounds_WithUnwinding) { stack[3] = 131; stack[4] = 141; stack[5] = reinterpret_cast(stack + 9); // saved FP (rbp). - StorePc(stack, 6, reinterpret_cast(code + 20)); // JS code. + stack[6] = reinterpret_cast(code + 20); // JS code. stack[7] = 303; // The SP points here in the caller's frame. stack[8] = 404; stack[9] = reinterpret_cast(stack) + (12 * sizeof(uintptr_t)); // saved FP (OOB). - StorePc(stack, 10, reinterpret_cast(code + 20)); // JS code. + stack[10] = reinterpret_cast(code + 20); // JS code. register_state.sp = stack; register_state.fp = stack + 5; @@ -441,7 +435,7 @@ TEST(Unwind_StackBounds_WithUnwinding) { // Change the return address so that it is not in range. We will not range // check the stack[9] FP value because we have finished unwinding and the // contents of rbp does not necessarily have to be the FP in this case. - StorePc(stack, 10, 202); + stack[10] = 202; unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, ®ister_state, stack_base); CHECK(unwound); @@ -555,76 +549,6 @@ TEST(PCIsInV8_LargeCodeObject) { CHECK(v8::Unwinder::PCIsInV8(unwind_state, pc)); } -#ifdef USE_SIMULATOR -// TODO(v8:10026): Make this also work without the simulator. The part that -// needs modifications is getting the RegisterState. -class UnwinderTestHelper { - public: - explicit UnwinderTestHelper(const std::string& test_function) - : isolate_(CcTest::isolate()) { - CHECK(!instance_); - instance_ = this; - v8::HandleScope scope(isolate_); - v8::Local global = v8::ObjectTemplate::New(isolate_); - global->Set(v8_str("TryUnwind"), - v8::FunctionTemplate::New(isolate_, TryUnwind)); - LocalContext env(isolate_, nullptr, global); - CompileRun(v8_str(test_function.c_str())); - } - - ~UnwinderTestHelper() { instance_ = nullptr; } - - private: - static void TryUnwind(const v8::FunctionCallbackInfo& args) { - instance_->DoTryUnwind(); - } - - void DoTryUnwind() { - // Set up RegisterState. - v8::RegisterState register_state; - SimulatorHelper simulator_helper; - if (!simulator_helper.Init(isolate_)) return; - simulator_helper.FillRegisters(®ister_state); - // At this point, the PC will point to a Redirection object, which is not - // in V8 as far as the unwinder is concerned. To make this work, point to - // the return address, which is in V8, instead. - register_state.pc = register_state.lr; - - UnwindState unwind_state = isolate_->GetUnwindState(); - void* stack_base = reinterpret_cast(0xffffffffffffffffL); - bool unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, - ®ister_state, stack_base); - // Check that we have successfully unwound past js_entry_sp. - CHECK(unwound); - CHECK_GT(register_state.sp, - reinterpret_cast(CcTest::i_isolate()->js_entry_sp())); - } - - v8::Isolate* isolate_; - - static UnwinderTestHelper* instance_; -}; - -UnwinderTestHelper* UnwinderTestHelper::instance_; - -TEST(Unwind_TwoNestedFunctions) { - i::FLAG_allow_natives_syntax = true; - const char* test_script = - "function test_unwinder_api_inner() {" - " TryUnwind();" - " return 0;" - "}" - "function test_unwinder_api_outer() {" - " return test_unwinder_api_inner();" - "}" - "%NeverOptimizeFunction(test_unwinder_api_inner);" - "%NeverOptimizeFunction(test_unwinder_api_outer);" - "test_unwinder_api_outer();"; - - UnwinderTestHelper helper(test_script); -} -#endif - #if __clang__ #pragma clang diagnostic pop #endif