Description
Hello!
This is about a bug affecting the msys2-docker-experimental
images, reported at msys2/msys2-docker#18 . I've now found this bug and think it should be fixed in the gendef
file.
I'm not sure whether this bug applies to Cygwin, too, but it's about this code in gendef
:
movl \$0x0d,%eax
xorl %ecx,%ecx
cpuid # get necessary space for xsave
movq %rbx,%rcx
addq \$0x48,%rbx # 0x18 for alignment, 0x30 for additional space
subq %rbx,%rsp
movl %ebx,0x24(%rsp)
xorq %rax,%rax
shrq \$3,%rcx
leaq 0x30(%rsp),%rdi
rep stosq
xgetbv # get XCR0 (ecx is 0 after rep)
movl %eax,0x28(%rsp)
movl %edx,0x2c(%rsp)
notl %ecx # set ecx non-zero
movl %ecx,0x20(%rsp)
xsave64 0x30(%rsp)
When running in Wine, I'm seeing segfaults caused by the final xsave64
instruction. These are because if the CPU's PKU/PKRU flag is enabled by Linux (disabling it by passing nopku
on the kernel command line prevents the bug), it is also enabled in wine binaries, and that will make the cpuid
instruction report a value of 2440 in rbx
and rcx
. This value is not a multiple of 64.
This results in a misaligned stack pointer when we hit the xsave64 instruction; xsave64 requires a 64-byte aligned storage area, and in an actual run, %rsp is 0x7ffffb648
. This means the store goes to 0x7ffffb678
, which isn't 64-byte aligned, causing a segfault.
However, even if the xsave64 instruction were to succeed, we'd crash a bit later because the stack pointer isn't aligned to the 16-byte boundary required by the ABI.
Unfortunately, I don't know how to rebuild msys2 to fix this. I can work around it by using Wine-gdb (winedbg --gdb bash.exe -c ...
is what I'm running) , though:
For me, the cpuid
instruction above is at 0x18019c645
, so the following instruction is at 0x18019c647
. After the cpuid
instruction, we inject a breakpoint which increases %rbx
by 56, making it 64-byte aligned again:
b *0x18019c647
Breakpoint 1 at 0x18019c647
Wine-gdb> command 1
command 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>p $rbx += 56
>c
>end
Wine-gdb> c
This allows the program to execute normally even if the CPU's PKU/PKRU feature flag is in use. This suffices to convince me the bug is as I've described; sorry if the description is a bit terse, I'm happy to answer questions!
The proposed fix is to add something to the effect of %rbx += 63; %rbx &= -64;
to gendef
after the cpuid
instruction but before the following mov
: this will increase the reported size of the xsave
area to the next 64-byte multiple, which will have the same effect as the GDB script above.