vm: implement frame-based SEH for 64-bit Windows
parent
b330595c3b
commit
e5e51c40a1
|
@ -11,6 +11,7 @@ ML_FLAGS = /nologo /safeseh
|
||||||
EXE_OBJS = vm\main-windows-nt.obj vm\factor.res
|
EXE_OBJS = vm\main-windows-nt.obj vm\factor.res
|
||||||
|
|
||||||
DLL_OBJS = vm\os-windows-nt.obj \
|
DLL_OBJS = vm\os-windows-nt.obj \
|
||||||
|
vm\os-windows-nt-x86.32.obj \
|
||||||
vm\os-windows.obj \
|
vm\os-windows.obj \
|
||||||
vm\aging_collector.obj \
|
vm\aging_collector.obj \
|
||||||
vm\alien.obj \
|
vm\alien.obj \
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
PLAF_DLL_OBJS += vm/os-windows-nt-x86.32.o
|
||||||
DLL_PATH=http://factorcode.org/dlls
|
DLL_PATH=http://factorcode.org/dlls
|
||||||
WINDRES=windres
|
WINDRES=windres
|
||||||
include vm/Config.windows.nt
|
include vm/Config.windows.nt
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
PLAF_DLL_OBJS += vm/os-windows-nt-x86.64.o
|
||||||
DLL_PATH=http://factorcode.org/dlls/64
|
DLL_PATH=http://factorcode.org/dlls/64
|
||||||
CC=$(WIN64_PATH)-gcc.exe
|
CC=$(WIN64_PATH)-gcc.exe
|
||||||
WINDRES=$(WIN64_PATH)-windres.exe
|
WINDRES=$(WIN64_PATH)-windres.exe
|
||||||
|
|
|
@ -7,8 +7,14 @@ code_heap::code_heap(cell size)
|
||||||
{
|
{
|
||||||
if(size > ((u64)1 << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size);
|
if(size > ((u64)1 << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size);
|
||||||
seg = new segment(align_page(size),true);
|
seg = new segment(align_page(size),true);
|
||||||
if(!seg) fatal_error("Out of memory in heap allocator",size);
|
if(!seg) fatal_error("Out of memory in code_heap constructor",size);
|
||||||
allocator = new free_list_allocator<code_block>(size,seg->start);
|
|
||||||
|
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()
|
code_heap::~code_heap()
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
namespace factor
|
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 {
|
struct code_heap {
|
||||||
/* The actual memory area */
|
/* The actual memory area */
|
||||||
segment *seg;
|
segment *seg;
|
||||||
|
|
||||||
|
/* Memory area reserved for SEH. Only used on Windows */
|
||||||
|
char *seh_area;
|
||||||
|
|
||||||
/* Memory allocator */
|
/* Memory allocator */
|
||||||
free_list_allocator<code_block> *allocator;
|
free_list_allocator<code_block> *allocator;
|
||||||
|
|
||||||
|
|
|
@ -258,7 +258,7 @@ void factor_vm::load_image(vm_parameters *p)
|
||||||
init_objects(&h);
|
init_objects(&h);
|
||||||
|
|
||||||
cell data_offset = data->tenured->start - h.data_relocation_base;
|
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_data(data_offset,code_offset);
|
||||||
fixup_code(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.version = image_version;
|
||||||
h.data_relocation_base = data->tenured->start;
|
h.data_relocation_base = data->tenured->start;
|
||||||
h.data_size = data->tenured->occupied_space();
|
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.code_size = code->allocator->occupied_space();
|
||||||
|
|
||||||
h.true_object = true_object;
|
h.true_object = true_object;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
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()
|
void factor_vm::open_console()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue