86 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			C++
		
	
	
		
		
			
		
	
	
			86 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			C++
		
	
	
|  | #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); | ||
|  | } | ||
|  | 
 | ||
|  | } |