OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "ppapi/tests/test_nacl_irt_stack_alignment.h" |
| 6 |
| 7 #include "ppapi/c/pp_var.h" |
| 8 #include "ppapi/c/ppb_var.h" |
| 9 #include "ppapi/cpp/instance.h" |
| 10 #include "ppapi/cpp/module.h" |
| 11 #include "ppapi/cpp/var.h" |
| 12 #include "ppapi/tests/testing_instance.h" |
| 13 |
| 14 // This whole test is really only meant for x86-32 NaCl (not PNaCl). |
| 15 // |
| 16 // This is a regression test for the IRT code being sensitive to stack |
| 17 // alignment. The de jure ABI is that the stack should be aligned to |
| 18 // 16 bytes at call sites. However, the de facto ABI is that the IRT |
| 19 // worked in the past when called with misaligned stack. NaCl code is |
| 20 // now compiled to expect the proper 16-byte alignment, but the IRT |
| 21 // code must remain compatible with old binaries that failed to do so. |
| 22 |
| 23 #if defined(__i386__) |
| 24 |
| 25 REGISTER_TEST_CASE(NaClIRTStackAlignment); |
| 26 |
| 27 bool TestNaClIRTStackAlignment::Init() { |
| 28 var_interface_ = static_cast<const PPB_Var*>( |
| 29 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE)); |
| 30 return var_interface_ && CheckTestingInterface(); |
| 31 } |
| 32 |
| 33 void TestNaClIRTStackAlignment::RunTests(const std::string& filter) { |
| 34 RUN_TEST(MisalignedCallVarAddRef, filter); |
| 35 } |
| 36 |
| 37 // This calls the given function with the stack explicitly misaligned. |
| 38 // If the function (in the IRT) was compiled wrongly, it will crash. |
| 39 void MisalignedCall(void (*func)(PP_Var), const PP_Var* arg) |
| 40 asm("MisalignedCall") __attribute__((regparm(2))); |
| 41 |
| 42 // regparm(2) means: First argument in %eax, second argument in %edx. |
| 43 // Writing this with an inline asm would require explaining all the |
| 44 // call-clobbers register behavior in the asm clobber list, which is a |
| 45 // lot with all the SSE and FPU state. It's far simpler just to make |
| 46 // it a function call the compiler knows is a function call, and then |
| 47 // write the function itself in pure assembly. |
| 48 asm("MisalignedCall:\n" |
| 49 // Use an SSE register to copy the 16 bytes of memory. |
| 50 // Note this instruction does not care about alignment. |
| 51 // The pointer is not necessarily aligned to 16 bytes. |
| 52 "movups (%edx), %xmm0\n" |
| 53 // Set up a frame so we can recover the stack pointer after alignment. |
| 54 "push %ebp\n" |
| 55 "mov %esp, %ebp\n" |
| 56 // Align the stack properly to 16 bytes. |
| 57 "andl $-16, %esp\n" |
| 58 // Now make space for the 16 bytes of argument data, |
| 59 // plus another 4 bytes so the stack pointer is misaligned. |
| 60 "subl $20, %esp\n" |
| 61 // Copy the argument onto the (misaligned) top of stack. |
| 62 "movups %xmm0, (%esp)\n" |
| 63 // Now call into the IRT, and hilarity ensues. |
| 64 "naclcall %eax\n" |
| 65 // Standard epilogue. |
| 66 "mov %ebp, %esp\n" |
| 67 "pop %ebp\n" |
| 68 "naclret"); |
| 69 |
| 70 std::string TestNaClIRTStackAlignment::TestMisalignedCallVarAddRef() { |
| 71 PP_Var var; |
| 72 var.type = PP_VARTYPE_INT32; |
| 73 var.padding = 0; |
| 74 var.value.as_int = 23; |
| 75 |
| 76 ASSERT_EQ(sizeof(var), static_cast<size_t>(16)); |
| 77 |
| 78 // This will crash if the test fails. |
| 79 MisalignedCall(var_interface_->AddRef, &var); |
| 80 MisalignedCall(var_interface_->Release, &var); |
| 81 |
| 82 PASS(); |
| 83 } |
| 84 |
| 85 #endif // defined(__i386__) |
OLD | NEW |