rubinius/rubinius — pull request #1751 by ryoqun (2012-05-27 02:18:42+00:00)
Title: Correct misaligned Fiber stack frames on x86-64

Currently stack frames used by fibers are incorrectly aligned on x86-64.

According to 3.2.2 The Stack Frame in
System V Application Binary Interface AMD64 Architecture Processor Supplement
(http://x86-64.org/documentation/abi.pdf), stack frames shall be aligned on a
16 byte boundary:

The end of the input argument area shall be aligned on a 16 (32, if
__m256 is passed on stack) byte boundary. In other words, the value
(%rsp + 8) is always a multiple of 16 (32) when control is transferred
to the function entry point.

But fiber stack frames currently aren't aligned as such. When compiled by GCC,
there is no problem. However, when compiled by Clang, this causes SEGV, due to
the movaps instruction in generated code used on the assumption of 16-byte
aligned stack frames.

To align correctly, this commit adjusts the initial stack frame created by
ourselves to be 16-byte aligned. Subsequent stack frames are correctly managed
by generated code from compilers.

A sample of Segmentation fault:

Program received signal SIGSEGV, Segmentation fault.
0x00000000005c9c87 in rubinius::BytecodeVerification::verify(rubinius::State*) ()
(gdb) disassemble
0x00000000005c9c83 <+611>: pxor %xmm0,%xmm0
=> 0x00000000005c9c87 <+615>: movaps %xmm0,-0x40(%rbp)
0x00000000005c9c8b <+619>: lea -0x40(%rbp),%r15
(gdb) info registers rbp
rbp 0x7ffff7eff4b8 0x7ffff7eff4b8

Difference of stack frame alignment

Before:

(gdb) disassemble
Dump of assembler code for function rubinius::fiber_wrap_main():
=> 0x00000000005e17c0 <+0>: mov %r13,%rdi
0x00000000005e17c3 <+3>: jmpq *%r12
0x00000000005e17c6 <+6>: retq
End of assembler dump.
(gdb) info registers rsp
rsp 0x7ffff7f80000 0x7ffff7f80000
(gdb) info frame
Stack level 0, frame at 0x7ffff7f80008:
rip = 0x5e17c0 in rubinius::fiber_wrap_main (vm/fiber_data.cpp:14); saved rip 0xdeadcafedeadcafe
called by frame at 0x7ffff7f80010
source language c++.
Arglist at 0x7ffff7f7fff8, args:
Locals at 0x7ffff7f7fff8, Previous frame's sp is 0x7ffff7f80008
Saved registers:
rip at 0x7ffff7f80000

After:

(gdb) disassemble
Dump of assembler code for function rubinius::fiber_wrap_main():
=> 0x00000000005e17c0 <+0>: mov %r13,%rdi
0x00000000005e17c3 <+3>: jmpq *%r12
0x00000000005e17c6 <+6>: retq
(gdb) info registers rsp
rsp 0x7ffff7f7fff8 0x7ffff7f7fff8
(gdb) info frame
Stack level 0, frame at 0x7ffff7f80000:
rip = 0x5e17c0 in rubinius::fiber_wrap_main (vm/fiber_data.cpp:14); saved rip 0xdeadcafedeadcafe
called by frame at 0x7ffff7f80008
source language c++.
Arglist at 0x7ffff7f7fff0, args:
Locals at 0x7ffff7f7fff0, Previous frame's sp is 0x7ffff7f80000
Saved registers:
rip at 0x7ffff7f7fff8