// Copyright (c) 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ppapi/tests/test_nacl_irt_stack_alignment.h" #include #include "ppapi/c/pp_var.h" #include "ppapi/c/ppb_var.h" #include "ppapi/cpp/instance.h" #include "ppapi/cpp/module.h" #include "ppapi/cpp/var.h" #include "ppapi/tests/testing_instance.h" // This whole test is really only meant for x86-32 NaCl (not PNaCl). // // This is a regression test for the IRT code being sensitive to stack // alignment. The de jure ABI is that the stack should be aligned to // 16 bytes at call sites. However, the de facto ABI is that the IRT // worked in the past when called with misaligned stack. NaCl code is // now compiled to expect the proper 16-byte alignment, but the IRT // code must remain compatible with old binaries that failed to do so. #if defined(__i386__) REGISTER_TEST_CASE(NaClIRTStackAlignment); bool TestNaClIRTStackAlignment::Init() { var_interface_ = static_cast( pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE)); return var_interface_ && CheckTestingInterface(); } void TestNaClIRTStackAlignment::RunTests(const std::string& filter) { RUN_TEST(MisalignedCallVarAddRef, filter); } // This calls the given function with the stack explicitly misaligned. // If the function (in the IRT) was compiled wrongly, it will crash. void MisalignedCall(void (*func)(PP_Var), const PP_Var* arg) asm("MisalignedCall") __attribute__((regparm(2))); // regparm(2) means: First argument in %eax, second argument in %edx. // Writing this with an inline asm would require explaining all the // call-clobbers register behavior in the asm clobber list, which is a // lot with all the SSE and FPU state. It's far simpler just to make // it a function call the compiler knows is a function call, and then // write the function itself in pure assembly. asm("MisalignedCall:\n" // Use an SSE register to copy the 16 bytes of memory. // Note this instruction does not care about alignment. // The pointer is not necessarily aligned to 16 bytes. "movups (%edx), %xmm0\n" // Set up a frame so we can recover the stack pointer after alignment. "push %ebp\n" "mov %esp, %ebp\n" // Align the stack properly to 16 bytes. "andl $-16, %esp\n" // Now make space for the 16 bytes of argument data, // plus another 4 bytes so the stack pointer is misaligned. "subl $20, %esp\n" // Copy the argument onto the (misaligned) top of stack. "movups %xmm0, (%esp)\n" // Now call into the IRT, and hilarity ensues. "naclcall %eax\n" // Standard epilogue. "mov %ebp, %esp\n" "pop %ebp\n" "naclret"); std::string TestNaClIRTStackAlignment::TestMisalignedCallVarAddRef() { PP_Var var; var.type = PP_VARTYPE_INT32; var.padding = 0; var.value.as_int = 23; ASSERT_EQ(sizeof(var), static_cast(16)); // This will crash if the test fails. MisalignedCall(var_interface_->AddRef, &var); MisalignedCall(var_interface_->Release, &var); PASS(); } #endif // defined(__i386__)