Message ID | 20230221153006.20300-3-pierrick.bouvier@linaro.org |
---|---|
State | Superseded |
Headers | show |
Series | Adds support for running QEMU natively on windows-arm64 | expand |
On 21/2/23 16:30, Pierrick Bouvier wrote: > Windows implementation of setjmp/longjmp is done in > C:/WINDOWS/system32/ucrtbase.dll. Alas, on arm64, it seems to *always* > perform stack unwinding, which crashes from generated code. > > By using alternative implementation built in mingw, we avoid doing stack > unwinding and this fixes crash when calling longjmp. > > Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> > Acked-by: Richard Henderson <richard.henderson@linaro.org> > --- > include/sysemu/os-win32.h | 28 ++++++++++++++++++++++++---- > meson.build | 21 +++++++++++++++++++++ > 2 files changed, 45 insertions(+), 4 deletions(-) > -#if defined(_WIN64) > -/* On w64, setjmp is implemented by _setjmp which needs a second parameter. > +#if defined(__aarch64__) > +/* > + * On windows-arm64, setjmp is available in only one variant, and longjmp always > + * does stack unwinding. This crash with generated code. > + * Thus, we use another implementation of setjmp (not windows one), coming from > + * mingw, which never performs stack unwinding. > + */ > +#undef setjmp > +#undef longjmp > +/* > + * These functions are not declared in setjmp.h because __aarch64__ defines > + * setjmp to _setjmpex instead. However, they are still defined in libmingwex.a, > + * which gets linked automatically. > + */ > +extern int __mingw_setjmp(jmp_buf); > +extern void __attribute__((noreturn)) __mingw_longjmp(jmp_buf, int); > +#define setjmp(env) __mingw_setjmp(env) > +#define longjmp(env, val) __mingw_longjmp(env, val) > +#elif defined(_WIN64) > +/* > + * On windows-x64, 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. */ > + * lets longjmp try a stack unwinding which will crash with generated code. > + */ > # undef setjmp > # define setjmp(env) _setjmp(env, NULL) > -#endif > +#endif /* __aarch64__ */ This comment is confusing, the previous if ladder is about i86. Maybe better not add any comment? Otherwise, Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
On 2/21/23 05:30, Pierrick Bouvier wrote: > Windows implementation of setjmp/longjmp is done in > C:/WINDOWS/system32/ucrtbase.dll. Alas, on arm64, it seems to *always* > perform stack unwinding, which crashes from generated code. > > By using alternative implementation built in mingw, we avoid doing stack > unwinding and this fixes crash when calling longjmp. > > Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> > Acked-by: Richard Henderson <richard.henderson@linaro.org> > --- > include/sysemu/os-win32.h | 28 ++++++++++++++++++++++++---- > meson.build | 21 +++++++++++++++++++++ > 2 files changed, 45 insertions(+), 4 deletions(-) Queueing this to tcg-next. r~
On 2/21/23 23:27, Philippe Mathieu-Daudé wrote: > On 21/2/23 16:30, Pierrick Bouvier wrote: >> Windows implementation of setjmp/longjmp is done in >> C:/WINDOWS/system32/ucrtbase.dll. Alas, on arm64, it seems to *always* >> perform stack unwinding, which crashes from generated code. >> >> By using alternative implementation built in mingw, we avoid doing stack >> unwinding and this fixes crash when calling longjmp. >> >> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> >> Acked-by: Richard Henderson <richard.henderson@linaro.org> >> --- >> include/sysemu/os-win32.h | 28 ++++++++++++++++++++++++---- >> meson.build | 21 +++++++++++++++++++++ >> 2 files changed, 45 insertions(+), 4 deletions(-) > > >> -#if defined(_WIN64) >> -/* On w64, setjmp is implemented by _setjmp which needs a second parameter. >> +#if defined(__aarch64__) >> +/* >> + * On windows-arm64, setjmp is available in only one variant, and longjmp always >> + * does stack unwinding. This crash with generated code. >> + * Thus, we use another implementation of setjmp (not windows one), coming from >> + * mingw, which never performs stack unwinding. >> + */ >> +#undef setjmp >> +#undef longjmp >> +/* >> + * These functions are not declared in setjmp.h because __aarch64__ defines >> + * setjmp to _setjmpex instead. However, they are still defined in libmingwex.a, >> + * which gets linked automatically. >> + */ >> +extern int __mingw_setjmp(jmp_buf); >> +extern void __attribute__((noreturn)) __mingw_longjmp(jmp_buf, int); >> +#define setjmp(env) __mingw_setjmp(env) >> +#define longjmp(env, val) __mingw_longjmp(env, val) >> +#elif defined(_WIN64) >> +/* >> + * On windows-x64, 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. */ >> + * lets longjmp try a stack unwinding which will crash with generated code. >> + */ >> # undef setjmp >> # define setjmp(env) _setjmp(env, NULL) >> -#endif >> +#endif /* __aarch64__ */ > > This comment is confusing, the previous if ladder is about i86. Maybe > better not add any comment? If I am not mistaken, before we had: #if x64 define setjmp as _setjmp(env, 0) #endif // nothing done for x86 and now we have: #if aarch64 define setjmp as __mingw_setjmp define longjmp as __mingw_longjmp #elif x64 define setjmp as _setjmp(env, 0) #endif // nothing done for x86 Maybe the patch format is confusing, or I missed what you pointed. Pierrick > > Otherwise, > Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> >
On 22/2/23 17:08, Pierrick Bouvier wrote: > On 2/21/23 23:27, Philippe Mathieu-Daudé wrote: >> On 21/2/23 16:30, Pierrick Bouvier wrote: >>> Windows implementation of setjmp/longjmp is done in >>> C:/WINDOWS/system32/ucrtbase.dll. Alas, on arm64, it seems to *always* >>> perform stack unwinding, which crashes from generated code. >>> >>> By using alternative implementation built in mingw, we avoid doing stack >>> unwinding and this fixes crash when calling longjmp. >>> >>> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> >>> Acked-by: Richard Henderson <richard.henderson@linaro.org> >>> --- >>> include/sysemu/os-win32.h | 28 ++++++++++++++++++++++++---- >>> meson.build | 21 +++++++++++++++++++++ >>> 2 files changed, 45 insertions(+), 4 deletions(-) >> >> >>> -#if defined(_WIN64) >>> -/* On w64, setjmp is implemented by _setjmp which needs a second >>> parameter. >>> +#if defined(__aarch64__) >>> +/* >>> + * On windows-arm64, setjmp is available in only one variant, and >>> longjmp always >>> + * does stack unwinding. This crash with generated code. >>> + * Thus, we use another implementation of setjmp (not windows one), >>> coming from >>> + * mingw, which never performs stack unwinding. >>> + */ >>> +#undef setjmp >>> +#undef longjmp >>> +/* >>> + * These functions are not declared in setjmp.h because __aarch64__ >>> defines >>> + * setjmp to _setjmpex instead. However, they are still defined in >>> libmingwex.a, >>> + * which gets linked automatically. >>> + */ >>> +extern int __mingw_setjmp(jmp_buf); >>> +extern void __attribute__((noreturn)) __mingw_longjmp(jmp_buf, int); >>> +#define setjmp(env) __mingw_setjmp(env) >>> +#define longjmp(env, val) __mingw_longjmp(env, val) >>> +#elif defined(_WIN64) >>> +/* >>> + * On windows-x64, 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. */ >>> + * lets longjmp try a stack unwinding which will crash with >>> generated code. >>> + */ >>> # undef setjmp >>> # define setjmp(env) _setjmp(env, NULL) >>> -#endif >>> +#endif /* __aarch64__ */ >> >> This comment is confusing, the previous if ladder is about i86. Maybe >> better not add any comment? > > If I am not mistaken, before we had: > > #if x64 > define setjmp as _setjmp(env, 0) > #endif > // nothing done for x86 > > and now we have: > > #if aarch64 > define setjmp as __mingw_setjmp > define longjmp as __mingw_longjmp > #elif x64 > define setjmp as _setjmp(env, 0) > #endif > // nothing done for x86 > > Maybe the patch format is confusing, or I missed what you pointed. Oh OK, we are good then, sorry :)
diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h index 5b38c7bd04..97d0243aee 100644 --- a/include/sysemu/os-win32.h +++ b/include/sysemu/os-win32.h @@ -51,14 +51,34 @@ typedef struct sockaddr_un { extern "C" { #endif -#if defined(_WIN64) -/* On w64, setjmp is implemented by _setjmp which needs a second parameter. +#if defined(__aarch64__) +/* + * On windows-arm64, setjmp is available in only one variant, and longjmp always + * does stack unwinding. This crash with generated code. + * Thus, we use another implementation of setjmp (not windows one), coming from + * mingw, which never performs stack unwinding. + */ +#undef setjmp +#undef longjmp +/* + * These functions are not declared in setjmp.h because __aarch64__ defines + * setjmp to _setjmpex instead. However, they are still defined in libmingwex.a, + * which gets linked automatically. + */ +extern int __mingw_setjmp(jmp_buf); +extern void __attribute__((noreturn)) __mingw_longjmp(jmp_buf, int); +#define setjmp(env) __mingw_setjmp(env) +#define longjmp(env, val) __mingw_longjmp(env, val) +#elif defined(_WIN64) +/* + * On windows-x64, 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. */ + * lets longjmp try a stack unwinding which will crash with generated code. + */ # undef setjmp # define setjmp(env) _setjmp(env, NULL) -#endif +#endif /* __aarch64__ */ /* QEMU uses sigsetjmp()/siglongjmp() as the portable way to specify * "longjmp and don't touch the signal masks". Since we know that the * savemask parameter will always be zero we can safely define these diff --git a/meson.build b/meson.build index a76c855312..b676c831b3 100644 --- a/meson.build +++ b/meson.build @@ -2470,6 +2470,27 @@ if targetos == 'windows' }''', name: '_lock_file and _unlock_file')) endif +if targetos == 'windows' + mingw_has_setjmp_longjmp = cc.links(''' + #include <setjmp.h> + int main(void) { + /* + * These functions are not available in setjmp header, but may be + * available at link time, from libmingwex.a. + */ + extern int __mingw_setjmp(jmp_buf); + extern void __attribute__((noreturn)) __mingw_longjmp(jmp_buf, int); + jmp_buf env; + __mingw_setjmp(env); + __mingw_longjmp(env, 0); + } + ''', name: 'mingw setjmp and longjmp') + + if cpu == 'aarch64' and not mingw_has_setjmp_longjmp + error('mingw must provide setjmp/longjmp for windows-arm64') + endif +endif + ######################## # Target configuration # ########################