]> gitweb.factorcode.org Git - factor.git/commitdiff
vm: implement frame-based SEH for 64-bit Windows
authorSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Thu, 8 Apr 2010 17:32:14 +0000 (10:32 -0700)
committerSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Thu, 8 Apr 2010 17:32:14 +0000 (10:32 -0700)
Nmakefile
vm/Config.windows.nt.x86.32
vm/Config.windows.nt.x86.64
vm/code_heap.cpp
vm/code_heap.hpp
vm/image.cpp
vm/os-windows-nt-x86.32.cpp [new file with mode: 0644]
vm/os-windows-nt-x86.64.cpp [new file with mode: 0644]
vm/os-windows-nt.cpp

index 02d2b5f1ed413405a1a6eef81b4f616cace367c5..b85197a776dc98a1d8cb947749d162c9bbda502e 100755 (executable)
--- a/Nmakefile
+++ b/Nmakefile
@@ -11,6 +11,7 @@ ML_FLAGS = /nologo /safeseh
 EXE_OBJS = vm\main-windows-nt.obj vm\factor.res
 
 DLL_OBJS = vm\os-windows-nt.obj \
+       vm\os-windows-nt-x86.32.obj \
        vm\os-windows.obj \
        vm\aging_collector.obj \
        vm\alien.obj \
index d27629fe8358552f93499239c2f1cb63a70aca9b..73bf064ce54042bf08adcfa3506c4fdc557727c7 100644 (file)
@@ -1,3 +1,4 @@
+PLAF_DLL_OBJS += vm/os-windows-nt-x86.32.o
 DLL_PATH=http://factorcode.org/dlls
 WINDRES=windres
 include vm/Config.windows.nt
index ddb61480e5cf8c340bf8a1708b0cda2fa259d5a4..495a3ccac9ac49925dde97c13c13132955445463 100644 (file)
@@ -1,3 +1,4 @@
+PLAF_DLL_OBJS += vm/os-windows-nt-x86.64.o
 DLL_PATH=http://factorcode.org/dlls/64
 CC=$(WIN64_PATH)-gcc.exe
 WINDRES=$(WIN64_PATH)-windres.exe
index 40fe00b0e9ff6a2ac906ac6ef606887998db6796..96d95416655ccb4af9251b28890fc46b637b9fcc 100755 (executable)
@@ -7,8 +7,14 @@ code_heap::code_heap(cell size)
 {
        if(size > ((u64)1 << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size);
        seg = new segment(align_page(size),true);
-       if(!seg) fatal_error("Out of memory in heap allocator",size);
-       allocator = new free_list_allocator<code_block>(size,seg->start);
+       if(!seg) fatal_error("Out of memory in code_heap constructor",size);
+
+       cell start = seg->start + seh_area_size;
+
+       allocator = new free_list_allocator<code_block>(seg->end - start,start);
+
+       /* See os-windows-nt-x86.64.cpp for seh_area usage */
+       seh_area = (char *)seg->start;
 }
 
 code_heap::~code_heap()
index 78ffa6c76a19cd06926c002f8031daca7aba8337..20ce03c8357a83648c483dc993ef8000eb6f3917 100755 (executable)
@@ -1,10 +1,19 @@
 namespace factor
 {
 
+#if defined(WINDOWS) && defined(FACTOR_64)
+       const cell seh_area_size = 1024;
+#else
+       const cell seh_area_size = 0;
+#endif
+
 struct code_heap {
        /* The actual memory area */
        segment *seg;
 
+       /* Memory area reserved for SEH. Only used on Windows */
+       char *seh_area;
+
        /* Memory allocator */
        free_list_allocator<code_block> *allocator;
 
index c74351c1911301846969058ea466505df2433ff3..ccce96a952c56970c8b728293989347173338bc6 100755 (executable)
@@ -258,7 +258,7 @@ void factor_vm::load_image(vm_parameters *p)
        init_objects(&h);
 
        cell data_offset = data->tenured->start - h.data_relocation_base;
-       cell code_offset = code->seg->start - h.code_relocation_base;
+       cell code_offset = code->allocator->start - h.code_relocation_base;
 
        fixup_data(data_offset,code_offset);
        fixup_code(data_offset,code_offset);
@@ -285,7 +285,7 @@ bool factor_vm::save_image(const vm_char *saving_filename, const vm_char *filena
        h.version = image_version;
        h.data_relocation_base = data->tenured->start;
        h.data_size = data->tenured->occupied_space();
-       h.code_relocation_base = code->seg->start;
+       h.code_relocation_base = code->allocator->start;
        h.code_size = code->allocator->occupied_space();
 
        h.true_object = true_object;
diff --git a/vm/os-windows-nt-x86.32.cpp b/vm/os-windows-nt-x86.32.cpp
new file mode 100644 (file)
index 0000000..61cf9f6
--- /dev/null
@@ -0,0 +1,12 @@
+#include "master.hpp"
+
+namespace factor
+{
+
+void factor_vm::c_to_factor_toplevel(cell quot)
+{
+       /* 32-bit Windows SEH is set up in basis/cpu/x86/32/winnt/bootstrap.factor */
+       c_to_factor(quot);
+}
+
+}
diff --git a/vm/os-windows-nt-x86.64.cpp b/vm/os-windows-nt-x86.64.cpp
new file mode 100644 (file)
index 0000000..876d0c5
--- /dev/null
@@ -0,0 +1,85 @@
+#include "master.hpp"
+
+namespace factor {
+
+typedef unsigned char UBYTE;
+
+const UBYTE UNW_FLAG_EHANDLER = 0x1;
+
+struct UNWIND_INFO {
+       UBYTE Version:3;
+       UBYTE Flags:5;
+       UBYTE SizeOfProlog;
+       UBYTE CountOfCodes;
+       UBYTE FrameRegister:4;
+       UBYTE FrameOffset:4;
+       ULONG ExceptionHandler;
+       ULONG ExceptionData[1];
+};
+
+struct seh_data {
+       UNWIND_INFO unwind_info;
+       RUNTIME_FUNCTION func;
+       UBYTE handler[32];
+};
+
+void factor_vm::c_to_factor_toplevel(cell quot)
+{
+       /* The annoying thing about Win64 SEH is that the offsets in
+        * function tables are 32-bit integers, and the exception handler
+        * itself must reside between the start and end pointers, so
+        * we stick everything at the beginning of the code heap and
+        * generate a small trampoline that jumps to the real
+        * exception handler. */
+
+       seh_data *seh_area = (seh_data *)code->seh_area;
+       cell base = code->seg->start;
+
+       /* Should look at generating this with the Factor assembler */
+
+       /* mov rax,0 */
+       seh_area->handler[0] = 0x48;
+       seh_area->handler[1] = 0xb8;
+       seh_area->handler[2] = 0x0;
+       seh_area->handler[3] = 0x0;
+       seh_area->handler[4] = 0x0;
+       seh_area->handler[5] = 0x0;
+       seh_area->handler[6] = 0x0;
+       seh_area->handler[7] = 0x0;
+       seh_area->handler[8] = 0x0;
+       seh_area->handler[9] = 0x0;
+
+       /* jmp rax */
+       seh_area->handler[10] = 0x48;
+       seh_area->handler[11] = 0xff;
+       seh_area->handler[12] = 0xe0;
+
+       /* Store address of exception handler in the operand of the 'mov' */
+       cell handler = (cell)&factor::exception_handler;
+       memcpy(&seh_area->handler[2],&handler,sizeof(cell));
+
+       UNWIND_INFO *unwind_info = &seh_area->unwind_info;
+       unwind_info->Version = 1;
+       unwind_info->Flags = UNW_FLAG_EHANDLER;
+       unwind_info->SizeOfProlog = 0;
+       unwind_info->CountOfCodes = 0;
+       unwind_info->FrameRegister = 0;
+       unwind_info->FrameOffset = 0;
+       unwind_info->ExceptionHandler = (DWORD)((cell)&seh_area->handler[0] - base);
+       unwind_info->ExceptionData[0] = 0;
+
+       RUNTIME_FUNCTION *func = &seh_area->func;
+       func->BeginAddress = 0;
+       func->EndAddress = (DWORD)(code->seg->end - base);
+       func->UnwindData = (DWORD)((cell)&seh_area->unwind_info - base);
+
+       if(!RtlAddFunctionTable(func,1,base))
+               fatal_error("RtlAddFunctionTable() failed",0);
+
+       c_to_factor(quot);
+
+       if(!RtlDeleteFunctionTable(func))
+               fatal_error("RtlDeleteFunctionTable() failed",0);
+}
+
+}
index 0d43cdecc23cbb7c6e7842b9921d3eb1c83ffcfb..4fea294a12da583fb82ff55565c83a67f636113d 100755 (executable)
@@ -92,11 +92,6 @@ VM_C_API LONG exception_handler(PEXCEPTION_RECORD e, void *frame, PCONTEXT c, vo
        return current_vm()->exception_handler(e,frame,c,dispatch);
 }
 
-void factor_vm::c_to_factor_toplevel(cell quot)
-{
-       c_to_factor(quot);
-}
-
 void factor_vm::open_console()
 {
 }