This setjmp.c builds in windows under Microsoft Visual Studio Professional 2019 (Version 16.10.1)
Rebuild started...
1>------ Rebuild All started: Project: setjmp, Configuration: Release x64 ------
1>setjmp.c
1>C:\Users\john\source\repos\setjmp\setjmp.c(48,10): warning C4013: 'setjmp' undefined; assuming extern returning int
1>Generating code
1>Previous IPDB not found, fall back to full compilation.
1>All 1 functions were compiled because no usable IPDB/IOBJ from previous compilation was found.
1>Finished generating code
1>setjmp.vcxproj -> C:\Users\john\source\repos\setjmp\x64\Release\setjmp.exe
1>Done building project "setjmp.vcxproj".
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
The actual cl.exe C compiler command is
1> C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30037\bin\HostX86\x64\CL.exe /c /Zi /nologo /W3 /WX- /diagnostics:column /sdl /O2 /Oi /GL /D NDEBUG /D _CONSOLE /D _UNICODE /D UNICODE /Gm- /EHsc /MD /GS /Gy /fp:precise /permissive- /Zc:wchar_t /Zc:forScope /Zc:inline /Fo"x64\Release\\" /Fd"x64\Release\vc142.pdb" /external:env:EXTERNAL_INCLUDE /external:W3 /Gd /TC /FC /errorReport:prompt setjmp.c
The source code is
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
typedef uint64_t QWORD;
typedef uint32_t DWORD;
typedef uint16_t WORD;
typedef uint8_t BYTE;
typedef struct MSTJMP_FLOAT128
{
QWORD Part[2];
} MSTJMP_FLOAT128;
typedef struct JUMP_BUFFER
{
QWORD Frame0;
QWORD Rbx0;
QWORD Rsp0;
QWORD Rbp0;
QWORD Rsi0;
QWORD Rdi0;
QWORD R120;
QWORD R130;
QWORD R140;
QWORD R150;
QWORD Rip0;
DWORD MxCsr4;
WORD FpCsr2;
WORD Spare2;
struct MSTJMP_FLOAT128 Xmm6x;
struct MSTJMP_FLOAT128 Xmm7x;
struct MSTJMP_FLOAT128 Xmm8x;
struct MSTJMP_FLOAT128 Xmm9x;
struct MSTJMP_FLOAT128 Xmm10x;
struct MSTJMP_FLOAT128 Xmm11x;
struct MSTJMP_FLOAT128 Xmm12x;
struct MSTJMP_FLOAT128 Xmm13x;
struct MSTJMP_FLOAT128 Xmm14x;
struct MSTJMP_FLOAT128 Xmm15x;
} JUMP_BUFFER;
int main() {
struct JUMP_BUFFER jumpbuffer;
setjmp(&jumpbuffer, 0);
return 0;
}
The disassembly for setjmp() call is
setjmp(&jumpbuffer, 0);
00007FF641B51019 xor edx,edx
00007FF641B5101B lea rcx,[jumpbuffer]
00007FF641B51020 call __intrinsic_setjmp (07FF641B51C20h)
which leads to the setjmp() code
--- d:\a01\_work\2\s\src\vctools\crt\vcruntime\src\eh\amd64\setjmp.asm ---------
00007FF82B6F0300 mov qword ptr [rcx],rdx
00007FF82B6F0303 mov qword ptr [rcx+8],rbx
00007FF82B6F0307 mov qword ptr [rcx+18h],rbp
so everything is functioning correctly without any errors because windows is using a C-runtime intrinsic within setjmp.asm
However, under linux, it generates an error:
error: macro "setjmp" passed 2 arguments, but takes just 1
Google'ing found this code snippet:
#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
To sum up, windows can take 2 args:
setjmp(&jumpbuffer, 0);
and linux can take 1 arg:
setjmp(&jumpbuffer);
To verify that linux likes that setjmp, I traced with gdb as follows: