From f6cce43255ac801e13d24f334d5c564c8e25ab07 Mon Sep 17 00:00:00 2001 From: "sgjesse@chromium.org" Date: Thu, 15 Apr 2010 12:41:30 +0000 Subject: [PATCH] Add stack alignment check to ia32 and x64 The stack is now checked for proper alignment before calling into C code when the flag --debug-code is turned on. Review URL: http://codereview.chromium.org/1637015 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4428 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/ia32/codegen-ia32.cc | 10 ++++++++++ src/ia32/macro-assembler-ia32.cc | 20 ++++++++++++++++++++ src/ia32/macro-assembler-ia32.h | 3 +++ src/platform-linux.cc | 2 +- src/x64/codegen-x64.cc | 10 +++++++++- src/x64/macro-assembler-x64.cc | 20 ++++++++++++++++++++ src/x64/macro-assembler-x64.h | 3 +++ 7 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 94437a9..c3fe096 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -11740,7 +11740,17 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, // Result returned in eax, or eax+edx if result_size_ is 2. + // Check stack alignment. + if (FLAG_debug_code) { + __ CheckStackAlignment(); + } + if (do_gc) { + // Pass failure code returned from last attempt as first argument to + // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the + // stack alignment is known to be correct. This function takes one argument + // which is passed on the stack, and we know that the stack has been + // prepared to pass at least one argument. __ mov(Operand(esp, 0 * kPointerSize), eax); // Result. __ call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY); } diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index 66f5638..2d7be9d 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -1535,6 +1535,21 @@ void MacroAssembler::Check(Condition cc, const char* msg) { } +void MacroAssembler::CheckStackAlignment() { + int frame_alignment = OS::ActivationFrameAlignment(); + int frame_alignment_mask = frame_alignment - 1; + if (frame_alignment > kPointerSize) { + ASSERT(IsPowerOf2(frame_alignment)); + Label alignment_as_expected; + test(esp, Immediate(frame_alignment_mask)); + j(zero, &alignment_as_expected); + // Abort if stack is not aligned. + int3(); + bind(&alignment_as_expected); + } +} + + void MacroAssembler::Abort(const char* msg) { // We want to pass the msg string like a smi to avoid GC // problems, however msg is not guaranteed to be aligned @@ -1634,6 +1649,11 @@ void MacroAssembler::CallCFunction(ExternalReference function, void MacroAssembler::CallCFunction(Register function, int num_arguments) { + // Check stack alignment. + if (FLAG_debug_code) { + CheckStackAlignment(); + } + call(Operand(function)); if (OS::ActivationFrameAlignment() != 0) { mov(esp, Operand(esp, num_arguments * kPointerSize)); diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h index caa96da..b11a697 100644 --- a/src/ia32/macro-assembler-ia32.h +++ b/src/ia32/macro-assembler-ia32.h @@ -463,6 +463,9 @@ class MacroAssembler: public Assembler { // Print a message to stdout and abort execution. void Abort(const char* msg); + // Check that the stack is aligned. + void CheckStackAlignment(); + // Verify restrictions about code generated in stubs. void set_generating_stub(bool value) { generating_stub_ = value; } bool generating_stub() { return generating_stub_; } diff --git a/src/platform-linux.cc b/src/platform-linux.cc index ea1830f..b28597d 100644 --- a/src/platform-linux.cc +++ b/src/platform-linux.cc @@ -159,7 +159,7 @@ int OS::ActivationFrameAlignment() { #elif V8_TARGET_ARCH_MIPS return 8; #endif - // With gcc 4.4 the tree vectorization optimiser can generate code + // With gcc 4.4 the tree vectorization optimizer can generate code // that requires 16 byte alignment such as movdqa on x86. return 16; } diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index 73a220e..778b194 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -8249,8 +8249,16 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, // Complex results must be written to address passed as first argument. // AMD64 calling convention: a struct of two pointers in rax+rdx + // Check stack alignment. + if (FLAG_debug_code) { + __ CheckStackAlignment(); + } + if (do_gc) { - // Pass failure code returned from last attempt as first argument to GC. + // Pass failure code returned from last attempt as first argument to + // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the + // stack is known to be aligned. This function takes one argument which is + // passed in register. #ifdef _WIN64 __ movq(rcx, rax); #else // ! defined(_WIN64) diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 61cfaa2..3e8dec6 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -291,6 +291,21 @@ void MacroAssembler::Check(Condition cc, const char* msg) { } +void MacroAssembler::CheckStackAlignment() { + int frame_alignment = OS::ActivationFrameAlignment(); + int frame_alignment_mask = frame_alignment - 1; + if (frame_alignment > kPointerSize) { + ASSERT(IsPowerOf2(frame_alignment)); + Label alignment_as_expected; + testq(rsp, Immediate(frame_alignment_mask)); + j(zero, &alignment_as_expected); + // Abort if stack is not aligned. + int3(); + bind(&alignment_as_expected); + } +} + + void MacroAssembler::NegativeZeroTest(Register result, Register op, Label* then_label) { @@ -2628,6 +2643,11 @@ void MacroAssembler::CallCFunction(ExternalReference function, void MacroAssembler::CallCFunction(Register function, int num_arguments) { + // Check stack alignment. + if (FLAG_debug_code) { + CheckStackAlignment(); + } + call(function); ASSERT(OS::ActivationFrameAlignment() != 0); ASSERT(num_arguments >= 0); diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index dabb764..10110d3 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -737,6 +737,9 @@ class MacroAssembler: public Assembler { // Print a message to stdout and abort execution. void Abort(const char* msg); + // Check that the stack is aligned. + void CheckStackAlignment(); + // Verify restrictions about code generated in stubs. void set_generating_stub(bool value) { generating_stub_ = value; } bool generating_stub() { return generating_stub_; } -- 2.7.4