diff mbox

[07/20] w64: Fix definition of setjmp

Message ID 1334499233-6344-8-git-send-email-sw@weilnetz.de
State Superseded
Headers show

Commit Message

Stefan Weil April 15, 2012, 2:13 p.m. UTC
The default definition of setjmp which is implemented in MinGW-w64
cannot be used with programs like QEMU which call longjmp from
code without structured exception handling (SEH).

This code therefore disables stack unwinding.

We could also implement SEH for QEMU's generated JIT code, but
that is much more difficult. Stack unwinding would also cost
execution time.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
---
 qemu-os-win32.h |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

Comments

Blue Swirl April 15, 2012, 5:02 p.m. UTC | #1
On Sun, Apr 15, 2012 at 14:13, Stefan Weil <sw@weilnetz.de> wrote:
> The default definition of setjmp which is implemented in MinGW-w64
> cannot be used with programs like QEMU which call longjmp from
> code without structured exception handling (SEH).

We're currently compiling QEMU with -no-seh, is that correct for Mingw64?

>
> This code therefore disables stack unwinding.
>
> We could also implement SEH for QEMU's generated JIT code, but
> that is much more difficult. Stack unwinding would also cost
> execution time.
>
> Signed-off-by: Stefan Weil <sw@weilnetz.de>
> ---
>  qemu-os-win32.h |    9 +++++++++
>  1 files changed, 9 insertions(+), 0 deletions(-)
>
> diff --git a/qemu-os-win32.h b/qemu-os-win32.h
> index b6533c0..753679b 100644
> --- a/qemu-os-win32.h
> +++ b/qemu-os-win32.h
> @@ -56,6 +56,15 @@
>  # define EWOULDBLOCK  WSAEWOULDBLOCK
>  #endif
>
> +#if defined(_WIN64)
> +/* On w64, setjmp is implemented by _setjmp which needs a second parameter.
> + * If this parameter is NULL, longjump does no stack unwinding.
> + * That is what we need for QEMU. Passing the value of register rsp (default)
> + * lets longjmp try a stack unwinding which will crash with generated code. */
> +# undef setjmp
> +# define setjmp(env) _setjmp(env, NULL)
> +#endif
> +
>  /* Declaration of ffs() is missing in MinGW's strings.h. */
>  int ffs(int i);
>
> --
> 1.7.0.4
>
Stefan Weil April 15, 2012, 5:09 p.m. UTC | #2
Am 15.04.2012 19:02, schrieb Blue Swirl:
> On Sun, Apr 15, 2012 at 14:13, Stefan Weil <sw@weilnetz.de> wrote:
>> The default definition of setjmp which is implemented in MinGW-w64
>> cannot be used with programs like QEMU which call longjmp from
>> code without structured exception handling (SEH).
>
> We're currently compiling QEMU with -no-seh, is that correct for Mingw64?


Yes, that's correct. This code in configure is used for w32 and for w64:

# Use ASLR, no-SEH and DEP if available
if test "$mingw32" = "yes" ; then
     for flag in --dynamicbase --no-seh --nxcompat; do
         if $ld --help 2>/dev/null | grep ".$flag" >/dev/null 
2>/dev/null ; then
             LDFLAGS="-Wl,$flag $LDFLAGS"
         fi
     done
fi

See resulting file:

bin/debug/w64/config-host.mak:LDFLAGS=-Wl,--nxcompat -Wl,--no-seh 
-Wl,--dynamicbase -Wl,--warn-common -m64 -g

Regards,
Stefan W.
Blue Swirl April 15, 2012, 5:18 p.m. UTC | #3
On Sun, Apr 15, 2012 at 17:09, Stefan Weil <sw@weilnetz.de> wrote:
> Am 15.04.2012 19:02, schrieb Blue Swirl:
>
>> On Sun, Apr 15, 2012 at 14:13, Stefan Weil <sw@weilnetz.de> wrote:
>>>
>>> The default definition of setjmp which is implemented in MinGW-w64
>>> cannot be used with programs like QEMU which call longjmp from
>>> code without structured exception handling (SEH).
>>
>>
>> We're currently compiling QEMU with -no-seh, is that correct for Mingw64?
>
>
>
> Yes, that's correct. This code in configure is used for w32 and for w64:
>
> # Use ASLR, no-SEH and DEP if available
> if test "$mingw32" = "yes" ; then
>    for flag in --dynamicbase --no-seh --nxcompat; do
>        if $ld --help 2>/dev/null | grep ".$flag" >/dev/null 2>/dev/null ;
> then
>            LDFLAGS="-Wl,$flag $LDFLAGS"
>        fi
>    done
> fi
>
> See resulting file:
>
> bin/debug/w64/config-host.mak:LDFLAGS=-Wl,--nxcompat -Wl,--no-seh
> -Wl,--dynamicbase -Wl,--warn-common -m64 -g

Yes, but I meant that since Mingw64 uses SEH, does -Wl,--no-seh
conflict with Mingw64 SEH usage somehow? If yes, should we disable
no-seh for Mingw64 and could we also use plain setjmp() then?

>
> Regards,
> Stefan W.
>
Stefan Weil April 15, 2012, 5:47 p.m. UTC | #4
Am 15.04.2012 19:18, schrieb Blue Swirl:
> On Sun, Apr 15, 2012 at 17:09, Stefan Weil <sw@weilnetz.de> wrote:
>> Am 15.04.2012 19:02, schrieb Blue Swirl:
>>
>>> On Sun, Apr 15, 2012 at 14:13, Stefan Weil <sw@weilnetz.de> wrote:
>>>>
>>>> The default definition of setjmp which is implemented in MinGW-w64
>>>> cannot be used with programs like QEMU which call longjmp from
>>>> code without structured exception handling (SEH).
>>>
>>>
>>> We're currently compiling QEMU with -no-seh, is that correct for 
>>> Mingw64?
>>
>>
>>
>> Yes, that's correct. This code in configure is used for w32 and for w64:
>>
>> # Use ASLR, no-SEH and DEP if available
>> if test "$mingw32" = "yes" ; then
>>    for flag in --dynamicbase --no-seh --nxcompat; do
>>        if $ld --help 2>/dev/null | grep ".$flag" >/dev/null 2>/dev/null ;
>> then
>>            LDFLAGS="-Wl,$flag $LDFLAGS"
>>        fi
>>    done
>> fi
>>
>> See resulting file:
>>
>> bin/debug/w64/config-host.mak:LDFLAGS=-Wl,--nxcompat -Wl,--no-seh
>> -Wl,--dynamicbase -Wl,--warn-common -m64 -g
>
> Yes, but I meant that since Mingw64 uses SEH, does -Wl,--no-seh
> conflict with Mingw64 SEH usage somehow? If yes, should we disable
> no-seh for Mingw64 and could we also use plain setjmp() then?

Using --no-seh conflicts with the default which was set by MS
to use SEH on w64.

I don't know whether SEH makes any difference for C applications
like QEMU. Typically C code does not need stack unwinding,
therefore I don't think that SEH is really needed. I think that
MS wanted to improve the support of languages like C++ and .NET
which need SEH in their standard.

SEH increases the size of the exe file. If we only remove
--no-seh for w64, QEMU's JIT code will still not support
SEH, so I expect that longjmp will still crash when trying
to unwind the stack.

When QEMU is compiled to use TCI, that's no problem, and
stack unwinding works although we still compile using --no-seh
(I had a w64 version with TCI long before it worked with tcg/i386).
Blue Swirl April 15, 2012, 6:02 p.m. UTC | #5
On Sun, Apr 15, 2012 at 17:47, Stefan Weil <sw@weilnetz.de> wrote:
> Am 15.04.2012 19:18, schrieb Blue Swirl:
>
>> On Sun, Apr 15, 2012 at 17:09, Stefan Weil <sw@weilnetz.de> wrote:
>>>
>>> Am 15.04.2012 19:02, schrieb Blue Swirl:
>>>
>>>> On Sun, Apr 15, 2012 at 14:13, Stefan Weil <sw@weilnetz.de> wrote:
>>>>>
>>>>>
>>>>> The default definition of setjmp which is implemented in MinGW-w64
>>>>> cannot be used with programs like QEMU which call longjmp from
>>>>> code without structured exception handling (SEH).
>>>>
>>>>
>>>>
>>>> We're currently compiling QEMU with -no-seh, is that correct for
>>>> Mingw64?
>>>
>>>
>>>
>>>
>>> Yes, that's correct. This code in configure is used for w32 and for w64:
>>>
>>> # Use ASLR, no-SEH and DEP if available
>>> if test "$mingw32" = "yes" ; then
>>>   for flag in --dynamicbase --no-seh --nxcompat; do
>>>       if $ld --help 2>/dev/null | grep ".$flag" >/dev/null 2>/dev/null ;
>>> then
>>>           LDFLAGS="-Wl,$flag $LDFLAGS"
>>>       fi
>>>   done
>>> fi
>>>
>>> See resulting file:
>>>
>>> bin/debug/w64/config-host.mak:LDFLAGS=-Wl,--nxcompat -Wl,--no-seh
>>> -Wl,--dynamicbase -Wl,--warn-common -m64 -g
>>
>>
>> Yes, but I meant that since Mingw64 uses SEH, does -Wl,--no-seh
>> conflict with Mingw64 SEH usage somehow? If yes, should we disable
>> no-seh for Mingw64 and could we also use plain setjmp() then?
>
>
> Using --no-seh conflicts with the default which was set by MS
> to use SEH on w64.
>
> I don't know whether SEH makes any difference for C applications
> like QEMU. Typically C code does not need stack unwinding,
> therefore I don't think that SEH is really needed. I think that
> MS wanted to improve the support of languages like C++ and .NET
> which need SEH in their standard.
>
> SEH increases the size of the exe file. If we only remove
> --no-seh for w64, QEMU's JIT code will still not support
> SEH, so I expect that longjmp will still crash when trying
> to unwind the stack.

Thanks for the explanation. Would similar hack as was done with GDB
for ELF help, so one day stack unwinding would work for generated
code?

> When QEMU is compiled to use TCI, that's no problem, and
> stack unwinding works although we still compile using --no-seh
> (I had a w64 version with TCI long before it worked with tcg/i386).

OK. BTW, have you tried to compile QEMU with MS compiler, would we
need a lot of changes to support that?
Stefan Weil April 15, 2012, 6:23 p.m. UTC | #6
Am 15.04.2012 20:02, schrieb Blue Swirl:
> On Sun, Apr 15, 2012 at 17:47, Stefan Weil <sw@weilnetz.de> wrote:
>> Am 15.04.2012 19:18, schrieb Blue Swirl:
>>
>>> On Sun, Apr 15, 2012 at 17:09, Stefan Weil <sw@weilnetz.de> wrote:
>>>>
>>>> Am 15.04.2012 19:02, schrieb Blue Swirl:
>>>>
>>>>> On Sun, Apr 15, 2012 at 14:13, Stefan Weil <sw@weilnetz.de> wrote:
>>>>>>
>>>>>>
>>>>>> The default definition of setjmp which is implemented in MinGW-w64
>>>>>> cannot be used with programs like QEMU which call longjmp from
>>>>>> code without structured exception handling (SEH).
>>>>>
>>>>>
>>>>>
>>>>> We're currently compiling QEMU with -no-seh, is that correct for
>>>>> Mingw64?
>>>>
>>>>
>>>>
>>>>
>>>> Yes, that's correct. This code in configure is used for w32 and for 
>>>> w64:
>>>>
>>>> # Use ASLR, no-SEH and DEP if available
>>>> if test "$mingw32" = "yes" ; then
>>>>   for flag in --dynamicbase --no-seh --nxcompat; do
>>>>       if $ld --help 2>/dev/null | grep ".$flag" >/dev/null 
>>>> 2>/dev/null ;
>>>> then
>>>>           LDFLAGS="-Wl,$flag $LDFLAGS"
>>>>       fi
>>>>   done
>>>> fi
>>>>
>>>> See resulting file:
>>>>
>>>> bin/debug/w64/config-host.mak:LDFLAGS=-Wl,--nxcompat -Wl,--no-seh
>>>> -Wl,--dynamicbase -Wl,--warn-common -m64 -g
>>>
>>>
>>> Yes, but I meant that since Mingw64 uses SEH, does -Wl,--no-seh
>>> conflict with Mingw64 SEH usage somehow? If yes, should we disable
>>> no-seh for Mingw64 and could we also use plain setjmp() then?
>>
>>
>> Using --no-seh conflicts with the default which was set by MS
>> to use SEH on w64.
>>
>> I don't know whether SEH makes any difference for C applications
>> like QEMU. Typically C code does not need stack unwinding,
>> therefore I don't think that SEH is really needed. I think that
>> MS wanted to improve the support of languages like C++ and .NET
>> which need SEH in their standard.
>>
>> SEH increases the size of the exe file. If we only remove
>> --no-seh for w64, QEMU's JIT code will still not support
>> SEH, so I expect that longjmp will still crash when trying
>> to unwind the stack.
>
> Thanks for the explanation. Would similar hack as was done with GDB
> for ELF help, so one day stack unwinding would work for generated
> code?

I had a discussion with Kai Tietz from MinGW-w64 who gave me
an overview what would be needed for SEH.

Each function needs SEH information in special sections which
are normally allocated and filled with data by the compiler and
linker. It's also possible to manipulate that data at run time.

>
>> When QEMU is compiled to use TCI, that's no problem, and
>> stack unwinding works although we still compile using --no-seh
>> (I had a w64 version with TCI long before it worked with tcg/i386).
>
> OK. BTW, have you tried to compile QEMU with MS compiler, would we
> need a lot of changes to support that?

QEMU has lots of dependencies on GNU gcc, therefore a compilation
with Visual Studio would need a lot of changes. Compiling QEMU with
gcc restricted to C99 gives an overview of those changes.

I remember that there was once a report on qemu-devel that someone
tried using VS with QEMU.

I never tried it myself and are not planning to try it.
diff mbox

Patch

diff --git a/qemu-os-win32.h b/qemu-os-win32.h
index b6533c0..753679b 100644
--- a/qemu-os-win32.h
+++ b/qemu-os-win32.h
@@ -56,6 +56,15 @@ 
 # define EWOULDBLOCK  WSAEWOULDBLOCK
 #endif
 
+#if defined(_WIN64)
+/* On w64, setjmp is implemented by _setjmp which needs a second parameter.
+ * If this parameter is NULL, longjump does no stack unwinding.
+ * That is what we need for QEMU. Passing the value of register rsp (default)
+ * lets longjmp try a stack unwinding which will crash with generated code. */
+# undef setjmp
+# define setjmp(env) _setjmp(env, NULL)
+#endif
+
 /* Declaration of ffs() is missing in MinGW's strings.h. */
 int ffs(int i);