]> gitweb.factorcode.org Git - factor.git/blob - vm/os-windows-nt-x86.64.cpp
vm: implement frame-based SEH for 64-bit Windows
[factor.git] / vm / os-windows-nt-x86.64.cpp
1 #include "master.hpp"
2
3 namespace factor {
4
5 typedef unsigned char UBYTE;
6
7 const UBYTE UNW_FLAG_EHANDLER = 0x1;
8
9 struct UNWIND_INFO {
10         UBYTE Version:3;
11         UBYTE Flags:5;
12         UBYTE SizeOfProlog;
13         UBYTE CountOfCodes;
14         UBYTE FrameRegister:4;
15         UBYTE FrameOffset:4;
16         ULONG ExceptionHandler;
17         ULONG ExceptionData[1];
18 };
19
20 struct seh_data {
21         UNWIND_INFO unwind_info;
22         RUNTIME_FUNCTION func;
23         UBYTE handler[32];
24 };
25
26 void factor_vm::c_to_factor_toplevel(cell quot)
27 {
28         /* The annoying thing about Win64 SEH is that the offsets in
29          * function tables are 32-bit integers, and the exception handler
30          * itself must reside between the start and end pointers, so
31          * we stick everything at the beginning of the code heap and
32          * generate a small trampoline that jumps to the real
33          * exception handler. */
34
35         seh_data *seh_area = (seh_data *)code->seh_area;
36         cell base = code->seg->start;
37
38         /* Should look at generating this with the Factor assembler */
39
40         /* mov rax,0 */
41         seh_area->handler[0] = 0x48;
42         seh_area->handler[1] = 0xb8;
43         seh_area->handler[2] = 0x0;
44         seh_area->handler[3] = 0x0;
45         seh_area->handler[4] = 0x0;
46         seh_area->handler[5] = 0x0;
47         seh_area->handler[6] = 0x0;
48         seh_area->handler[7] = 0x0;
49         seh_area->handler[8] = 0x0;
50         seh_area->handler[9] = 0x0;
51
52         /* jmp rax */
53         seh_area->handler[10] = 0x48;
54         seh_area->handler[11] = 0xff;
55         seh_area->handler[12] = 0xe0;
56
57         /* Store address of exception handler in the operand of the 'mov' */
58         cell handler = (cell)&factor::exception_handler;
59         memcpy(&seh_area->handler[2],&handler,sizeof(cell));
60
61         UNWIND_INFO *unwind_info = &seh_area->unwind_info;
62         unwind_info->Version = 1;
63         unwind_info->Flags = UNW_FLAG_EHANDLER;
64         unwind_info->SizeOfProlog = 0;
65         unwind_info->CountOfCodes = 0;
66         unwind_info->FrameRegister = 0;
67         unwind_info->FrameOffset = 0;
68         unwind_info->ExceptionHandler = (DWORD)((cell)&seh_area->handler[0] - base);
69         unwind_info->ExceptionData[0] = 0;
70
71         RUNTIME_FUNCTION *func = &seh_area->func;
72         func->BeginAddress = 0;
73         func->EndAddress = (DWORD)(code->seg->end - base);
74         func->UnwindData = (DWORD)((cell)&seh_area->unwind_info - base);
75
76         if(!RtlAddFunctionTable(func,1,base))
77                 fatal_error("RtlAddFunctionTable() failed",0);
78
79         c_to_factor(quot);
80
81         if(!RtlDeleteFunctionTable(func))
82                 fatal_error("RtlDeleteFunctionTable() failed",0);
83 }
84
85 }