Skip to content

Commit 644da9b

Browse files
authored
Fix setjmp/longjmp on native Windows (unicorn-engine#1331)
* Add setjmp wrapper * Add to projects * Use wrapper on x64 * Always build on x64 and exclude on win32 * Fix signature * Add comments * Add comments for os-win32.h * Add extern decleration * Support cmake Windows build * Fix for MinGW
1 parent 225f6f2 commit 644da9b

File tree

7 files changed

+73
-3
lines changed

7 files changed

+73
-3
lines changed

CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,10 @@ if (MSVC)
859859
${CMAKE_CURRENT_SOURCE_DIR}/msvc/unicorn/qapi-types.c
860860
${CMAKE_CURRENT_SOURCE_DIR}/msvc/unicorn/qapi-visit.c
861861
)
862+
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
863+
enable_language(ASM_MASM)
864+
set(UNICORN_SRCS ${UNICORN_SRCS} qemu/util/setjmp-wrapper-win32.asm)
865+
endif()
862866
else()
863867
set(UNICORN_SRCS
864868
${UNICORN_SRCS_COMMON}

msvc/unicorn/unicorn/unicorn.vcxproj

+11-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
</PropertyGroup>
5454
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5555
<ImportGroup Label="ExtensionSettings">
56+
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
5657
</ImportGroup>
5758
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
5859
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@@ -357,7 +358,16 @@ copy "$(SolutionDir)..\include\unicorn\*.h" "$(SolutionDir)distro\include\unicor
357358
<ClInclude Include="..\qapi-types.h" />
358359
<ClInclude Include="..\qapi-visit.h" />
359360
</ItemGroup>
361+
<ItemGroup>
362+
<MASM Include="..\..\..\qemu\util\setjmp-wrapper-win32.asm">
363+
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
364+
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
365+
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
366+
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
367+
</MASM>
368+
</ItemGroup>
360369
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
361370
<ImportGroup Label="ExtensionTargets">
371+
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
362372
</ImportGroup>
363-
</Project>
373+
</Project>

msvc/unicorn/unicorn/unicorn.vcxproj.filters

+3
Original file line numberDiff line numberDiff line change
@@ -499,4 +499,7 @@
499499
<ClInclude Include="..\..\..\include\unicorn\unicorn.h" />
500500
<ClInclude Include="..\..\..\include\unicorn\x86.h" />
501501
</ItemGroup>
502+
<ItemGroup>
503+
<MASM Include="..\..\..\qemu\util\setjmp-wrapper-win32.asm" />
504+
</ItemGroup>
502505
</Project>

msvc/unicorn/unicorn_static/unicorn_static.vcxproj

+11-1
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,14 @@
169169
<ClInclude Include="..\qapi-types.h" />
170170
<ClInclude Include="..\qapi-visit.h" />
171171
</ItemGroup>
172+
<ItemGroup>
173+
<MASM Include="..\..\..\qemu\util\setjmp-wrapper-win32.asm">
174+
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
175+
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
176+
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
177+
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
178+
</MASM>
179+
</ItemGroup>
172180
<PropertyGroup Label="Globals">
173181
<ProjectGuid>{B6EFD6D7-C2D4-4FBB-B363-2E08CE09CC96}</ProjectGuid>
174182
<Keyword>Win32Proj</Keyword>
@@ -204,6 +212,7 @@
204212
</PropertyGroup>
205213
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
206214
<ImportGroup Label="ExtensionSettings">
215+
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
207216
</ImportGroup>
208217
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
209218
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@@ -363,5 +372,6 @@ copy "$(SolutionDir)..\include\unicorn\*.h" "$(SolutionDir)distro\include\unicor
363372
</ItemDefinitionGroup>
364373
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
365374
<ImportGroup Label="ExtensionTargets">
375+
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
366376
</ImportGroup>
367-
</Project>
377+
</Project>

msvc/unicorn/unicorn_static/unicorn_static.vcxproj.filters

+3
Original file line numberDiff line numberDiff line change
@@ -498,4 +498,7 @@
498498
<Filter>qemu</Filter>
499499
</ClInclude>
500500
</ItemGroup>
501+
<ItemGroup>
502+
<MASM Include="..\..\..\qemu\util\setjmp-wrapper-win32.asm" />
503+
</ItemGroup>
501504
</Project>

qemu/include/sysemu/os-win32.h

+15-1
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,27 @@
5656
# define EWOULDBLOCK WSAEWOULDBLOCK
5757
#endif
5858

59-
#if defined(_WIN64) && !defined(_MSC_VER)
59+
#if defined(_WIN64)
6060
/* On w64, setjmp is implemented by _setjmp which needs a second parameter.
6161
* If this parameter is NULL, longjump does no stack unwinding.
6262
* That is what we need for QEMU. Passing the value of register rsp (default)
6363
* lets longjmp try a stack unwinding which will crash with generated code. */
64+
65+
#if defined(_MSC_VER) // MSVC
66+
67+
// See qemu/include/utils/setjmp-wrapper-win32.asm for details.
68+
extern int _setjmp_wrapper(jmp_buf);
69+
70+
# undef setjmp
71+
# define setjmp(env) _setjmp_wrapper(env)
72+
73+
#else // MinGW
74+
75+
// Original QEMU patch.
6476
# undef setjmp
6577
# define setjmp(env) _setjmp(env, NULL)
78+
#endif
79+
6680
#endif
6781
/* QEMU uses sigsetjmp()/siglongjmp() as the portable way to specify
6882
* "longjmp and don't touch the signal masks". Since we know that the

qemu/util/setjmp-wrapper-win32.asm

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
EXTERN _setjmp: proc
2+
PUBLIC _setjmp_wrapper
3+
4+
_TEXT SEGMENT
5+
6+
_setjmp_wrapper PROC
7+
8+
; Why do we need this wrapper?
9+
; Short answer: Windows default implementation of setjmp/longjmp is incompatible with generated code.
10+
; A longer answer: https://blog.lazym.io/2020/09/21/Unicorn-Devblog-setjmp-longjmp-on-Windows/.
11+
12+
; From qemu os-win32 comments:
13+
; > On w64, setjmp is implemented by _setjmp which needs a second parameter.
14+
; > If this parameter is NULL, longjump does no stack unwinding.
15+
; > That is what we need for QEMU. Passing the value of register rsp (default)
16+
; > lets longjmp try a stack unwinding which will crash with generated code.
17+
; It's true indeed, but MSVC doesn't has a setjmp signature which receives two arguements.
18+
; Therefore, we add a wrapper to keep the second argument zero.
19+
xor rdx, rdx
20+
jmp _setjmp
21+
22+
_setjmp_wrapper ENDP
23+
24+
_TEXT ENDS
25+
26+
END

0 commit comments

Comments
 (0)