First draft of dynamic detours using Ayuto's DynamicHooks library
https://github.com/Ayuto/DynamicHooks
This commit is contained in:
		
							parent
							
								
									fd8866a540
								
							
						
					
					
						commit
						2e52ab24b7
					
				| @ -240,6 +240,9 @@ class DHooksConfig(object): | ||||
|       os.path.join(self.sm_root, 'sourcepawn', 'vm', 'x86'), | ||||
|       os.path.join(self.sm_root, 'public', 'amtl', 'include'), | ||||
|       os.path.join(self.sm_root, 'public', 'amtl', 'amtl'), | ||||
|       os.path.join(builder.currentSourcePath, 'DynamicHooks', 'thirdparty'), | ||||
|       os.path.join(builder.currentSourcePath, 'DynamicHooks', 'thirdparty', 'AsmJit'), | ||||
|       os.path.join(builder.currentSourcePath, 'DynamicHooks'), | ||||
|     ] | ||||
| 	 | ||||
| 
 | ||||
| @ -256,6 +259,45 @@ program.sources += [ | ||||
|   'natives.cpp', | ||||
|   'vhook.cpp', | ||||
|   'util.cpp', | ||||
|   'dynhooks_sourcepawn.cpp', | ||||
| ] | ||||
| 
 | ||||
| # DynamicHooks | ||||
| program.sources += [ | ||||
| 	os.path.join('DynamicHooks', 'asm.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'hook.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'manager.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'registers.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'utilities.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'conventions', 'x86MsCdecl.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'conventions', 'x86MsStdcall.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'conventions', 'x86MsThiscall.cpp'), | ||||
| ] | ||||
| 
 | ||||
| # ASMJit | ||||
| program.sources += [ | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'assembler.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'compiler.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'compilercontext.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'constpool.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'containers.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'cpuinfo.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'globals.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'hlstream.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'logger.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'operand.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'podvector.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'runtime.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'utils.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'vmem.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'base', 'zone.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'x86', 'x86assembler.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'x86', 'x86compiler.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'x86', 'x86compilercontext.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'x86', 'x86compilerfunc.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'x86', 'x86inst.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'x86', 'x86operand.cpp'), | ||||
| 	os.path.join('DynamicHooks', 'thirdparty', 'AsmJit', 'x86', 'x86operand_regs.cpp'), | ||||
| ] | ||||
| 
 | ||||
| program.sources += [os.path.join(DHooks.sm_root, 'public', 'smsdk_ext.cpp')] | ||||
|  | ||||
							
								
								
									
										457
									
								
								DynamicHooks/asm.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										457
									
								
								DynamicHooks/asm.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,457 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include "asm.h" | ||||
| 
 | ||||
| #ifndef _WIN32 | ||||
| 
 | ||||
| #include <inttypes.h> | ||||
| 
 | ||||
| #ifndef _GNU_SOURCE | ||||
| #  define _GNU_SOURCE | ||||
| #endif // _GNU_SOURCE
 | ||||
| 
 | ||||
| #include <dlfcn.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #define REG_EAX			0 | ||||
| #define REG_ECX			1 | ||||
| #define REG_EDX			2 | ||||
| #define REG_EBX			3 | ||||
| 
 | ||||
| #define IA32_MOV_REG_IMM		0xB8	// encoding is +r <imm32>
 | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
| * Checks if a call to a fpic thunk has just been written into dest. | ||||
| * If found replaces it with a direct mov that sets the required register to the value of pc. | ||||
| * | ||||
| * @param dest		Destination buffer where a call opcode + addr (5 bytes) has just been written. | ||||
| * @param pc		The program counter value that needs to be set (usually the next address from the source). | ||||
| * @noreturn | ||||
| */ | ||||
| void check_thunks(unsigned char *dest, unsigned char *pc) | ||||
| { | ||||
| #if defined _WIN32 | ||||
| 	return; | ||||
| #else | ||||
| 	/* Step write address back 4 to the start of the function address */ | ||||
| 	unsigned char *writeaddr = dest - 4; | ||||
| 	unsigned char *calloffset = *(unsigned char **)writeaddr; | ||||
| 	unsigned char *calladdr = (unsigned char *)(dest + (intptr_t)calloffset); | ||||
| 
 | ||||
| 	/* Lookup name of function being called */ | ||||
| 	if ((*calladdr == 0x8B) && (*(calladdr+2) == 0x24) && (*(calladdr+3) == 0xC3)) | ||||
| 	{ | ||||
| 		//a thunk maybe?
 | ||||
| 		char movByte = IA32_MOV_REG_IMM; | ||||
| 
 | ||||
| 		/* Calculate the correct mov opcode */ | ||||
| 		switch (*(calladdr+1)) | ||||
| 		{ | ||||
| 		case 0x04: | ||||
| 			{ | ||||
| 				movByte += REG_EAX; | ||||
| 				break; | ||||
| 			} | ||||
| 		case 0x1C: | ||||
| 			{ | ||||
| 				movByte += REG_EBX; | ||||
| 				break; | ||||
| 			} | ||||
| 		case 0x0C: | ||||
| 			{ | ||||
| 				movByte += REG_ECX; | ||||
| 				break; | ||||
| 			} | ||||
| 		case 0x14: | ||||
| 			{ | ||||
| 				movByte += REG_EDX; | ||||
| 				break; | ||||
| 			} | ||||
| 		default: | ||||
| 			{ | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		/* Move our write address back one to where the call opcode was */ | ||||
| 		writeaddr--; | ||||
| 
 | ||||
| 
 | ||||
| 		/* Write our mov */ | ||||
| 		*writeaddr = movByte; | ||||
| 		writeaddr++; | ||||
| 
 | ||||
| 		/* Write the value - The provided program counter value */ | ||||
| 		*(void **)writeaddr = (void *)pc; | ||||
| 		writeaddr += 4; | ||||
| 	} | ||||
| 
 | ||||
| 	return; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| //if dest is NULL, returns minimum number of bytes needed to be copied
 | ||||
| //if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
 | ||||
| //http://www.devmaster.net/forums/showthread.php?t=2311
 | ||||
| int copy_bytes(unsigned char *func, unsigned char* dest, int required_len) { | ||||
| 	int bytecount = 0; | ||||
| 
 | ||||
| 	while(bytecount < required_len && *func != 0xCC) | ||||
| 	{ | ||||
| 		// prefixes F0h, F2h, F3h, 66h, 67h, D8h-DFh, 2Eh, 36h, 3Eh, 26h, 64h and 65h
 | ||||
| 		int operandSize = 4; | ||||
| 		int FPU = 0; | ||||
| 		int twoByte = 0; | ||||
| 		unsigned char opcode = 0x90; | ||||
| 		unsigned char modRM = 0xFF; | ||||
| 		while(*func == 0xF0 || | ||||
| 			*func == 0xF2 || | ||||
| 			*func == 0xF3 || | ||||
| 			(*func & 0xFC) == 0x64 || | ||||
| 			(*func & 0xF8) == 0xD8 || | ||||
| 			(*func & 0x7E) == 0x62) | ||||
| 		{ | ||||
| 			if(*func == 0x66) | ||||
| 			{ | ||||
| 				operandSize = 2; | ||||
| 			} | ||||
| 			else if((*func & 0xF8) == 0xD8) | ||||
| 			{ | ||||
| 				FPU = *func; | ||||
| 				if (dest) | ||||
| 					*dest++ = *func++; | ||||
| 				else | ||||
| 					func++; | ||||
| 				bytecount++; | ||||
| 				break; | ||||
| 			} | ||||
| 
 | ||||
| 			if (dest) | ||||
| 				*dest++ = *func++; | ||||
| 			else | ||||
| 				func++; | ||||
| 			bytecount++; | ||||
| 		} | ||||
| 
 | ||||
| 		// two-byte opcode byte
 | ||||
| 		if(*func == 0x0F) | ||||
| 		{ | ||||
| 			twoByte = 1; | ||||
| 			if (dest) | ||||
| 				*dest++ = *func++; | ||||
| 			else | ||||
| 				func++; | ||||
| 			bytecount++; | ||||
| 		} | ||||
| 
 | ||||
| 		// opcode byte
 | ||||
| 		opcode = *func++; | ||||
| 		if (dest) *dest++ = opcode; | ||||
| 		bytecount++; | ||||
| 
 | ||||
| 		// mod R/M byte
 | ||||
| 		modRM = 0xFF; | ||||
| 		if(FPU) | ||||
| 		{ | ||||
| 			if((opcode & 0xC0) != 0xC0) | ||||
| 			{ | ||||
| 				modRM = opcode; | ||||
| 			} | ||||
| 		} | ||||
| 		else if(!twoByte) | ||||
| 		{ | ||||
| 			if((opcode & 0xC4) == 0x00 || | ||||
| 				(opcode & 0xF4) == 0x60 && ((opcode & 0x0A) == 0x02 || (opcode & 0x09) == 0x09) || | ||||
| 				(opcode & 0xF0) == 0x80 || | ||||
| 				(opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02 || | ||||
| 				(opcode & 0xFC) == 0xD0 || | ||||
| 				(opcode & 0xF6) == 0xF6) | ||||
| 			{ | ||||
| 				modRM = *func++; | ||||
| 				if (dest) *dest++ = modRM; | ||||
| 				bytecount++; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D || | ||||
| 				(opcode & 0xF0) == 0x30 || | ||||
| 				opcode == 0x77 || | ||||
| 				(opcode & 0xF0) == 0x80 || | ||||
| 				(opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02 || | ||||
| 				(opcode & 0xF8) == 0xC8) | ||||
| 			{ | ||||
| 				// No mod R/M byte
 | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				modRM = *func++; | ||||
| 				if (dest) *dest++ = modRM; | ||||
| 				bytecount++; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// SIB
 | ||||
| 		if((modRM & 0x07) == 0x04 && | ||||
| 			(modRM & 0xC0) != 0xC0) | ||||
| 		{ | ||||
| 			if (dest) | ||||
| 				*dest++ = *func++;   //SIB
 | ||||
| 			else | ||||
| 				func++; | ||||
| 			bytecount++; | ||||
| 		} | ||||
| 
 | ||||
| 		// mod R/M displacement
 | ||||
| 
 | ||||
| 		// Dword displacement, no base
 | ||||
| 		if((modRM & 0xC5) == 0x05) { | ||||
| 			if (dest) { | ||||
| 				*(unsigned int*)dest = *(unsigned int*)func; | ||||
| 				dest += 4; | ||||
| 			} | ||||
| 			func += 4; | ||||
| 			bytecount += 4; | ||||
| 		} | ||||
| 
 | ||||
| 		// Byte displacement
 | ||||
| 		if((modRM & 0xC0) == 0x40) { | ||||
| 			if (dest) | ||||
| 				*dest++ = *func++; | ||||
| 			else | ||||
| 				func++; | ||||
| 			bytecount++; | ||||
| 		} | ||||
| 
 | ||||
| 		// Dword displacement
 | ||||
| 		if((modRM & 0xC0) == 0x80) { | ||||
| 			if (dest) { | ||||
| 				*(unsigned int*)dest = *(unsigned int*)func; | ||||
| 				dest += 4; | ||||
| 			} | ||||
| 			func += 4; | ||||
| 			bytecount += 4; | ||||
| 		} | ||||
| 
 | ||||
| 		// immediate
 | ||||
| 		if(FPU) | ||||
| 		{ | ||||
| 			// Can't have immediate operand
 | ||||
| 		} | ||||
| 		else if(!twoByte) | ||||
| 		{ | ||||
| 			if((opcode & 0xC7) == 0x04 || | ||||
| 				(opcode & 0xFE) == 0x6A ||   // PUSH/POP/IMUL
 | ||||
| 				(opcode & 0xF0) == 0x70 ||   // Jcc
 | ||||
| 				opcode == 0x80 || | ||||
| 				opcode == 0x83 || | ||||
| 				(opcode & 0xFD) == 0xA0 ||   // MOV
 | ||||
| 				opcode == 0xA8 ||			// TEST
 | ||||
| 				(opcode & 0xF8) == 0xB0 ||   // MOV
 | ||||
| 				(opcode & 0xFE) == 0xC0 ||   // RCL
 | ||||
| 				opcode == 0xC6 ||			// MOV
 | ||||
| 				opcode == 0xCD ||			// INT
 | ||||
| 				(opcode & 0xFE) == 0xD4 ||   // AAD/AAM
 | ||||
| 				(opcode & 0xF8) == 0xE0 ||   // LOOP/JCXZ
 | ||||
| 				opcode == 0xEB || | ||||
| 				opcode == 0xF6 && (modRM & 0x30) == 0x00)   // TEST
 | ||||
| 			{ | ||||
| 				if (dest) | ||||
| 					*dest++ = *func++; | ||||
| 				else | ||||
| 					func++; | ||||
| 				bytecount++; | ||||
| 			} | ||||
| 			else if((opcode & 0xF7) == 0xC2) // RET
 | ||||
| 			{ | ||||
| 				if (dest) { | ||||
| 					*(unsigned short*)dest = *(unsigned short*)func; | ||||
| 					dest += 2; | ||||
| 				} | ||||
| 				func += 2; | ||||
| 				bytecount += 2; | ||||
| 			} | ||||
| 			else if((opcode & 0xFC) == 0x80 || | ||||
| 				(opcode & 0xC7) == 0x05 || | ||||
| 				(opcode & 0xF8) == 0xB8 || | ||||
| 				(opcode & 0xFE) == 0xE8 ||	  // CALL/Jcc
 | ||||
| 				(opcode & 0xFE) == 0x68 || | ||||
| 				(opcode & 0xFC) == 0xA0 || | ||||
| 				(opcode & 0xEE) == 0xA8 || | ||||
| 				opcode == 0xC7 || | ||||
| 				opcode == 0xF7 && (modRM & 0x30) == 0x00) | ||||
| 			{ | ||||
| 				if (dest) { | ||||
| 					//Fix CALL/JMP offset
 | ||||
| 					if ((opcode & 0xFE) == 0xE8) { | ||||
| 						if (operandSize == 4) | ||||
| 						{ | ||||
| 							*(long*)dest = ((func + *(long*)func) - dest); | ||||
| 
 | ||||
| 							//pRED* edit. func is the current address of the call address, +4 is the next instruction, so the value of $pc
 | ||||
| 							check_thunks(dest+4, func+4); | ||||
| 						} | ||||
| 						else | ||||
| 							*(short*)dest = ((func + *(short*)func) - dest); | ||||
| 
 | ||||
| 					} else { | ||||
| 						if (operandSize == 4) | ||||
| 							*(unsigned long*)dest = *(unsigned long*)func; | ||||
| 						else | ||||
| 							*(unsigned short*)dest = *(unsigned short*)func; | ||||
| 					} | ||||
| 					dest += operandSize; | ||||
| 				} | ||||
| 				func += operandSize; | ||||
| 				bytecount += operandSize; | ||||
| 
 | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if(opcode == 0xBA ||			// BT
 | ||||
| 				opcode == 0x0F ||			// 3DNow!
 | ||||
| 				(opcode & 0xFC) == 0x70 ||   // PSLLW
 | ||||
| 				(opcode & 0xF7) == 0xA4 ||   // SHLD
 | ||||
| 				opcode == 0xC2 || | ||||
| 				opcode == 0xC4 || | ||||
| 				opcode == 0xC5 || | ||||
| 				opcode == 0xC6) | ||||
| 			{ | ||||
| 				if (dest) | ||||
| 					*dest++ = *func++; | ||||
| 				else | ||||
| 					func++; | ||||
| 			} | ||||
| 			else if((opcode & 0xF0) == 0x80) // Jcc -i
 | ||||
| 			{ | ||||
| 				if (dest) { | ||||
| 					if (operandSize == 4) | ||||
| 						*(unsigned long*)dest = *(unsigned long*)func; | ||||
| 					else | ||||
| 						*(unsigned short*)dest = *(unsigned short*)func; | ||||
| 
 | ||||
| 					dest += operandSize; | ||||
| 				} | ||||
| 				func += operandSize; | ||||
| 				bytecount += operandSize; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return bytecount; | ||||
| } | ||||
| 
 | ||||
| //insert a specific JMP instruction at the given location
 | ||||
| void inject_jmp(void* src, void* dest) { | ||||
| 	*(unsigned char*)src = OP_JMP; | ||||
| 	*(long*)((unsigned char*)src+1) = (long)((unsigned char*)dest - ((unsigned char*)src + OP_JMP_SIZE)); | ||||
| } | ||||
| 
 | ||||
| //fill a given block with NOPs
 | ||||
| void fill_nop(void* src, unsigned int len) { | ||||
| 	unsigned char* src2 = (unsigned char*)src; | ||||
| 	while (len) { | ||||
| 		*src2++ = OP_NOP; | ||||
| 		--len; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void* eval_jump(void* src) { | ||||
| 	unsigned char* addr = (unsigned char*)src; | ||||
| 
 | ||||
| 	if (!addr) return 0; | ||||
| 
 | ||||
| 	//import table jump
 | ||||
| 	if (addr[0] == OP_PREFIX && addr[1] == OP_JMP_SEG) { | ||||
| 		addr += 2; | ||||
| 		addr = *(unsigned char**)addr; | ||||
| 		//TODO: if addr points into the IAT
 | ||||
| 		return *(void**)addr; | ||||
| 	} | ||||
| 
 | ||||
| 	//8bit offset
 | ||||
| 	else if (addr[0] == OP_JMP_BYTE) { | ||||
| 		addr = &addr[OP_JMP_BYTE_SIZE] + *(char*)&addr[1]; | ||||
| 		//mangled 32bit jump?
 | ||||
| 		if (addr[0] = OP_JMP) { | ||||
| 			addr = addr + *(int*)&addr[1]; | ||||
| 		} | ||||
| 		return addr; | ||||
| 	} | ||||
| 	/*
 | ||||
| 	//32bit offset
 | ||||
| 	else if (addr[0] == OP_JMP) { | ||||
| 	addr = &addr[OP_JMP_SIZE] + *(int*)&addr[1]; | ||||
| 	} | ||||
| 	*/ | ||||
| 
 | ||||
| 	return addr; | ||||
| } | ||||
| /*
 | ||||
| from ms detours package | ||||
| static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress) | ||||
| { | ||||
| MEMORY_BASIC_INFORMATION mbi; | ||||
| VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi)); | ||||
| __try { | ||||
| PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase; | ||||
| if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { | ||||
| return false; | ||||
| } | ||||
| 
 | ||||
| PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + | ||||
| pDosHeader->e_lfanew); | ||||
| if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { | ||||
| return false; | ||||
| } | ||||
| 
 | ||||
| if (pbAddress >= ((PBYTE)pDosHeader + | ||||
| pNtHeader->OptionalHeader | ||||
| .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) && | ||||
| pbAddress < ((PBYTE)pDosHeader + | ||||
| pNtHeader->OptionalHeader | ||||
| .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + | ||||
| pNtHeader->OptionalHeader | ||||
| .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) { | ||||
| return true; | ||||
| } | ||||
| return false; | ||||
| } | ||||
| __except(EXCEPTION_EXECUTE_HANDLER) { | ||||
| return false; | ||||
| } | ||||
| } | ||||
| */ | ||||
							
								
								
									
										70
									
								
								DynamicHooks/asm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								DynamicHooks/asm.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| #ifndef __ASM_H__ | ||||
| #define __ASM_H__ | ||||
| 
 | ||||
| #define OP_JMP				0xE9 | ||||
| #define OP_JMP_SIZE			5 | ||||
| 
 | ||||
| #define OP_NOP				0x90 | ||||
| #define OP_NOP_SIZE			1 | ||||
| 
 | ||||
| #define OP_PREFIX			0xFF | ||||
| #define OP_JMP_SEG			0x25 | ||||
| 
 | ||||
| #define OP_JMP_BYTE			0xEB | ||||
| #define OP_JMP_BYTE_SIZE	2 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| 	void check_thunks(unsigned char *dest, unsigned char *pc); | ||||
| 
 | ||||
| 	//if dest is NULL, returns minimum number of bytes needed to be copied
 | ||||
| 	//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
 | ||||
| 	//http://www.devmaster.net/forums/showthread.php?t=2311
 | ||||
| 	int copy_bytes(unsigned char *func, unsigned char* dest, int required_len); | ||||
| 
 | ||||
| 	//insert a specific JMP instruction at the given location
 | ||||
| 	void inject_jmp(void* src, void* dest); | ||||
| 
 | ||||
| 	//fill a given block with NOPs
 | ||||
| 	void fill_nop(void* src, unsigned int len); | ||||
| 
 | ||||
| 	//evaluate a JMP at the target
 | ||||
| 	void* eval_jump(void* src); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif //__ASM_H__
 | ||||
							
								
								
									
										216
									
								
								DynamicHooks/convention.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								DynamicHooks/convention.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,216 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| #ifndef _CONVENTION_H | ||||
| #define _CONVENTION_H | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include <list> | ||||
| #include <vector> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| #include "registers.h" | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> DataType_t
 | ||||
| // ============================================================================
 | ||||
| enum DataType_t | ||||
| { | ||||
| 	DATA_TYPE_VOID, | ||||
| 	DATA_TYPE_BOOL, | ||||
| 	DATA_TYPE_CHAR, | ||||
| 	DATA_TYPE_UCHAR, | ||||
| 	DATA_TYPE_SHORT, | ||||
| 	DATA_TYPE_USHORT, | ||||
| 	DATA_TYPE_INT, | ||||
| 	DATA_TYPE_UINT, | ||||
| 	DATA_TYPE_LONG, | ||||
| 	DATA_TYPE_ULONG, | ||||
| 	DATA_TYPE_LONG_LONG, | ||||
| 	DATA_TYPE_ULONG_LONG, | ||||
| 	DATA_TYPE_FLOAT, | ||||
| 	DATA_TYPE_DOUBLE, | ||||
| 	DATA_TYPE_POINTER, | ||||
| 	DATA_TYPE_STRING, | ||||
| 	DATA_TYPE_OBJECT | ||||
| }; | ||||
| 
 | ||||
| typedef struct DataTypeSized_s { | ||||
| 	DataTypeSized_s() | ||||
| 	{ | ||||
| 		type = DATA_TYPE_POINTER; | ||||
| 		size = 0; | ||||
| 	} | ||||
| 	DataType_t type; | ||||
| 	size_t size; | ||||
| } DataTypeSized_t; | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> FUNCTIONS
 | ||||
| // ============================================================================
 | ||||
| /*
 | ||||
| Returns the size after applying alignment. | ||||
| 
 | ||||
| @param <size>: | ||||
| The size that should be aligned. | ||||
| 
 | ||||
| @param <alignment>: | ||||
| The alignment that should be used. | ||||
| */ | ||||
| inline int Align(int size, int alignment) | ||||
| {     | ||||
| 	int unaligned = size % alignment; | ||||
| 	if (unaligned == 0) | ||||
| 		return size; | ||||
| 
 | ||||
| 	return size + (alignment - unaligned); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| Returns the size of a data type after applying alignment. | ||||
| 
 | ||||
| @param <type>: | ||||
| The data type you would like to get the size of. | ||||
| 
 | ||||
| @param <alignment>: | ||||
| The alignment that should be used. | ||||
| */ | ||||
| inline int GetDataTypeSize(DataTypeSized_t type, int iAlignment=4) | ||||
| { | ||||
| 	switch(type.type) | ||||
| 	{ | ||||
| 		case DATA_TYPE_VOID:		return 0; | ||||
| 		case DATA_TYPE_BOOL:		return Align(sizeof(bool),					iAlignment); | ||||
| 		case DATA_TYPE_CHAR:		return Align(sizeof(char),					iAlignment); | ||||
| 		case DATA_TYPE_UCHAR:		return Align(sizeof(unsigned char),			iAlignment); | ||||
| 		case DATA_TYPE_SHORT:		return Align(sizeof(short),					iAlignment); | ||||
| 		case DATA_TYPE_USHORT:		return Align(sizeof(unsigned short),		iAlignment); | ||||
| 		case DATA_TYPE_INT:			return Align(sizeof(int),					iAlignment); | ||||
| 		case DATA_TYPE_UINT:		return Align(sizeof(unsigned int),			iAlignment); | ||||
| 		case DATA_TYPE_LONG:		return Align(sizeof(long),					iAlignment); | ||||
| 		case DATA_TYPE_ULONG:		return Align(sizeof(unsigned long),			iAlignment); | ||||
| 		case DATA_TYPE_LONG_LONG:	return Align(sizeof(long long),				iAlignment); | ||||
| 		case DATA_TYPE_ULONG_LONG:	return Align(sizeof(unsigned long long),	iAlignment); | ||||
| 		case DATA_TYPE_FLOAT:		return Align(sizeof(float),					iAlignment); | ||||
| 		case DATA_TYPE_DOUBLE:		return Align(sizeof(double),				iAlignment); | ||||
| 		case DATA_TYPE_POINTER:		return Align(sizeof(void *),				iAlignment); | ||||
| 		case DATA_TYPE_STRING:		return Align(sizeof(char *),				iAlignment); | ||||
| 		case DATA_TYPE_OBJECT:		return type.size; | ||||
| 		default: puts("Unknown data type."); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> CLASSES
 | ||||
| // ============================================================================
 | ||||
| /*
 | ||||
| This is the base class for every calling convention. Inherit from this class | ||||
| to create your own calling convention. | ||||
| */ | ||||
| class ICallingConvention | ||||
| { | ||||
| public: | ||||
| 	/*
 | ||||
| 	Initializes the calling convention. | ||||
| 
 | ||||
| 	@param <vecArgTypes>: | ||||
| 	A list of DataType_t objects, which define the arguments of the function. | ||||
| 
 | ||||
| 	@param <returnType>: | ||||
| 	The return type of the function. | ||||
| 	*/ | ||||
| 	ICallingConvention(std::vector<DataTypeSized_t> vecArgTypes, DataTypeSized_t returnType, int iAlignment=4) | ||||
| 	{ | ||||
| 		m_vecArgTypes = vecArgTypes; | ||||
| 		std::vector<DataTypeSized_t>::iterator it = m_vecArgTypes.begin(); | ||||
| 		for (; it != m_vecArgTypes.end(); it++) | ||||
| 		{ | ||||
| 			DataTypeSized_t &type = *it; | ||||
| 			if (!type.size) | ||||
| 				type.size = GetDataTypeSize(type); | ||||
| 		} | ||||
| 		m_returnType = returnType; | ||||
| 		if (!m_returnType.size) | ||||
| 			m_returnType.size = GetDataTypeSize(m_returnType); | ||||
| 		m_iAlignment = iAlignment; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	This should return a list of Register_t values. These registers will be | ||||
| 	saved for later access. | ||||
| 	*/ | ||||
| 	virtual std::list<Register_t> GetRegisters() = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	Returns the number of bytes that should be added to the stack to clean up. | ||||
| 	*/ | ||||
| 	virtual int GetPopSize() = 0; | ||||
| 
 | ||||
| 	virtual int GetArgStackSize() = 0; | ||||
| 	virtual void** GetStackArgumentPtr(CRegisters* pRegisters) = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	Returns a pointer to the argument at the given index. | ||||
| 
 | ||||
| 	@param <iIndex>: | ||||
| 	The index of the argument. | ||||
| 
 | ||||
| 	@param <pRegisters>: | ||||
| 	A snapshot of all saved registers. | ||||
| 	*/ | ||||
| 	virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters) = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	*/ | ||||
| 	virtual void ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr) = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	Returns a pointer to the return value. | ||||
| 
 | ||||
| 	@param <pRegisters>: | ||||
| 	A snapshot of all saved registers. | ||||
| 	*/ | ||||
| 	virtual void* GetReturnPtr(CRegisters* pRegisters) = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	*/ | ||||
| 	virtual void ReturnPtrChanged(CRegisters* pRegisters, void* pReturnPtr) = 0; | ||||
| 
 | ||||
| public: | ||||
| 	std::vector<DataTypeSized_t> m_vecArgTypes; | ||||
| 	DataTypeSized_t m_returnType; | ||||
| 	int m_iAlignment; | ||||
| }; | ||||
| 
 | ||||
| #endif // _CONVENTION_H
 | ||||
							
								
								
									
										46
									
								
								DynamicHooks/conventions/x86GccCdecl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								DynamicHooks/conventions/x86GccCdecl.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| #ifndef _X86_GCC_CDECL_H | ||||
| #define _X86_GCC_CDECL_H | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include "x86MsCdecl.h" | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> CLASSES
 | ||||
| // ============================================================================
 | ||||
| typedef x86MsCdecl x86GccCdecl; | ||||
| 
 | ||||
| 
 | ||||
| #endif // _X86_GCC_CDECL_H
 | ||||
							
								
								
									
										46
									
								
								DynamicHooks/conventions/x86GccThiscall.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								DynamicHooks/conventions/x86GccThiscall.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| #ifndef _X86_GCC_THISCALL_H | ||||
| #define _X86_GCC_THISCALL_H | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include "x86GccCdecl.h" | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> CLASSES
 | ||||
| // ============================================================================
 | ||||
| typedef x86GccCdecl x86GccThiscall; | ||||
| 
 | ||||
| 
 | ||||
| #endif // _X86_GCC_THISCALL_H
 | ||||
							
								
								
									
										145
									
								
								DynamicHooks/conventions/x86MsCdecl.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								DynamicHooks/conventions/x86MsCdecl.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,145 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include "x86MsCdecl.h" | ||||
| #include <string.h> | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> x86MsCdecl
 | ||||
| // ============================================================================
 | ||||
| x86MsCdecl::x86MsCdecl(std::vector<DataTypeSized_t> vecArgTypes, DataTypeSized_t returnType, int iAlignment) : | ||||
| 	ICallingConvention(vecArgTypes, returnType, iAlignment) | ||||
| { | ||||
| 	if (m_returnType.size > 4) | ||||
| 	{ | ||||
| 		m_pReturnBuffer = malloc(m_returnType.size); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		m_pReturnBuffer = NULL; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| x86MsCdecl::~x86MsCdecl() | ||||
| { | ||||
| 	if (m_pReturnBuffer) | ||||
| 	{ | ||||
| 		free(m_pReturnBuffer); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| std::list<Register_t> x86MsCdecl::GetRegisters() | ||||
| { | ||||
| 	std::list<Register_t> registers; | ||||
| 
 | ||||
| 	registers.push_back(ESP); | ||||
| 
 | ||||
| 	if (m_returnType.type == DATA_TYPE_FLOAT || m_returnType.type == DATA_TYPE_DOUBLE) | ||||
| 	{ | ||||
| 		registers.push_back(ST0); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		registers.push_back(EAX); | ||||
| 		if (m_pReturnBuffer) | ||||
| 		{ | ||||
| 			registers.push_back(EDX); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return registers; | ||||
| } | ||||
| 
 | ||||
| int x86MsCdecl::GetPopSize() | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int x86MsCdecl::GetArgStackSize() | ||||
| { | ||||
| 	int iArgStackSize = 0; | ||||
| 
 | ||||
| 	for (unsigned int i = 0; i < m_vecArgTypes.size(); i++) | ||||
| 	{ | ||||
| 		iArgStackSize += m_vecArgTypes[i].size; | ||||
| 	} | ||||
| 
 | ||||
| 	return iArgStackSize; | ||||
| } | ||||
| 
 | ||||
| void** x86MsCdecl::GetStackArgumentPtr(CRegisters* pRegisters) | ||||
| { | ||||
| 	return (void **)(pRegisters->m_esp->GetValue<unsigned long>() + 4); | ||||
| } | ||||
| 
 | ||||
| void* x86MsCdecl::GetArgumentPtr(int iIndex, CRegisters* pRegisters) | ||||
| { | ||||
| 	int iOffset = 4; | ||||
| 	for(int i=0; i < iIndex; i++) | ||||
| 	{ | ||||
| 		iOffset += m_vecArgTypes[i].size; | ||||
| 	} | ||||
| 
 | ||||
| 	return (void *) (pRegisters->m_esp->GetValue<unsigned long>() + iOffset); | ||||
| } | ||||
| 
 | ||||
| void x86MsCdecl::ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void* x86MsCdecl::GetReturnPtr(CRegisters* pRegisters) | ||||
| { | ||||
| 	if (m_returnType.type == DATA_TYPE_FLOAT || m_returnType.type == DATA_TYPE_DOUBLE) | ||||
| 		return pRegisters->m_st0->m_pAddress; | ||||
| 
 | ||||
| 	if (m_pReturnBuffer) | ||||
| 	{ | ||||
| 		// First half in eax, second half in edx
 | ||||
| 		memcpy(m_pReturnBuffer, pRegisters->m_eax, 4); | ||||
| 		memcpy((void *) ((unsigned long) m_pReturnBuffer + 4), pRegisters->m_edx, 4); | ||||
| 		return m_pReturnBuffer; | ||||
| 	} | ||||
| 
 | ||||
| 	return pRegisters->m_eax->m_pAddress; | ||||
| } | ||||
| 
 | ||||
| void x86MsCdecl::ReturnPtrChanged(CRegisters* pRegisters, void* pReturnPtr) | ||||
| { | ||||
| 	if (m_pReturnBuffer) | ||||
| 	{ | ||||
| 		// First half in eax, second half in edx
 | ||||
| 		memcpy(pRegisters->m_eax, m_pReturnBuffer, 4); | ||||
| 		memcpy(pRegisters->m_edx, (void *) ((unsigned long) m_pReturnBuffer + 4), 4); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										84
									
								
								DynamicHooks/conventions/x86MsCdecl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								DynamicHooks/conventions/x86MsCdecl.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| #ifndef _X86_MS_CDECL_H | ||||
| #define _X86_MS_CDECL_H | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include "../convention.h" | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> CLASSES
 | ||||
| // ============================================================================
 | ||||
| /*
 | ||||
| Source: DynCall manual and Windows docs | ||||
| 
 | ||||
| Registers: | ||||
| 	- eax = return value | ||||
| 	- edx = return value | ||||
| 	- esp = stack pointer | ||||
| 	- st0 = floating point return value | ||||
| 
 | ||||
| Parameter passing: | ||||
| 	- stack parameter order: right-to-left | ||||
| 	- caller cleans up the stack | ||||
| 	- all arguments are pushed onto the stack | ||||
| 	- alignment: 4 bytes | ||||
| 
 | ||||
| Return values: | ||||
| 	- return values of pointer or intergral type (<= 32 bits) are returned via the eax register | ||||
| 	- integers > 32 bits are returned via the eax and edx registers | ||||
| 	- floating pointer types are returned via the st0 register | ||||
| */ | ||||
| class x86MsCdecl: public ICallingConvention | ||||
| {	 | ||||
| public: | ||||
| 	x86MsCdecl(std::vector<DataTypeSized_t> vecArgTypes, DataTypeSized_t returnType, int iAlignment=4); | ||||
| 	~x86MsCdecl(); | ||||
| 
 | ||||
| 	virtual std::list<Register_t> GetRegisters(); | ||||
| 	virtual int GetPopSize(); | ||||
| 	virtual int GetArgStackSize(); | ||||
| 	virtual void** GetStackArgumentPtr(CRegisters* pRegisters); | ||||
| 	 | ||||
| 	virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters); | ||||
| 	virtual void ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr); | ||||
| 
 | ||||
| 	virtual void* GetReturnPtr(CRegisters* pRegisters); | ||||
| 	virtual void ReturnPtrChanged(CRegisters* pRegisters, void* pReturnPtr); | ||||
| 
 | ||||
| private: | ||||
| 	void* m_pReturnBuffer; | ||||
| }; | ||||
| 
 | ||||
| #endif // _X86_MS_CDECL_H
 | ||||
							
								
								
									
										152
									
								
								DynamicHooks/conventions/x86MsStdcall.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								DynamicHooks/conventions/x86MsStdcall.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,152 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include "x86MsStdcall.h" | ||||
| #include <string.h> | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> x86MsStdcall
 | ||||
| // ============================================================================
 | ||||
| x86MsStdcall::x86MsStdcall(std::vector<DataTypeSized_t> vecArgTypes, DataTypeSized_t returnType, int iAlignment) : | ||||
| 	ICallingConvention(vecArgTypes, returnType, iAlignment) | ||||
| { | ||||
| 	if (m_returnType.size > 4) | ||||
| 	{ | ||||
| 		m_pReturnBuffer = malloc(m_returnType.size); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		m_pReturnBuffer = NULL; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| x86MsStdcall::~x86MsStdcall() | ||||
| { | ||||
| 	if (m_pReturnBuffer) | ||||
| 	{ | ||||
| 		free(m_pReturnBuffer); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| std::list<Register_t> x86MsStdcall::GetRegisters() | ||||
| { | ||||
| 	std::list<Register_t> registers; | ||||
| 
 | ||||
| 	registers.push_back(ESP); | ||||
| 
 | ||||
| 	if (m_returnType.type == DATA_TYPE_FLOAT || m_returnType.type == DATA_TYPE_DOUBLE) | ||||
| 	{ | ||||
| 		registers.push_back(ST0); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		registers.push_back(EAX); | ||||
| 		if (m_pReturnBuffer) | ||||
| 		{ | ||||
| 			registers.push_back(EDX); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return registers; | ||||
| } | ||||
| 
 | ||||
| int x86MsStdcall::GetPopSize() | ||||
| { | ||||
| 	int iPopSize = 0; | ||||
| 
 | ||||
| 	for(unsigned int i=0; i < m_vecArgTypes.size(); i++) | ||||
| 	{ | ||||
| 		iPopSize += m_vecArgTypes[i].size; | ||||
| 	} | ||||
| 
 | ||||
| 	return iPopSize; | ||||
| } | ||||
| 
 | ||||
| int x86MsStdcall::GetArgStackSize() | ||||
| { | ||||
| 	int iArgStackSize = 0; | ||||
| 
 | ||||
| 	for (unsigned int i = 0; i < m_vecArgTypes.size(); i++) | ||||
| 	{ | ||||
| 		iArgStackSize += m_vecArgTypes[i].size; | ||||
| 	} | ||||
| 
 | ||||
| 	return iArgStackSize; | ||||
| } | ||||
| 
 | ||||
| void** x86MsStdcall::GetStackArgumentPtr(CRegisters* pRegisters) | ||||
| { | ||||
| 	return (void **)(pRegisters->m_esp->GetValue<unsigned long>() + 4); | ||||
| } | ||||
| 
 | ||||
| void* x86MsStdcall::GetArgumentPtr(int iIndex, CRegisters* pRegisters) | ||||
| { | ||||
| 	int iOffset = 4; | ||||
| 	for(int i=0; i < iIndex; i++) | ||||
| 	{ | ||||
| 		iOffset += m_vecArgTypes[i].size; | ||||
| 	} | ||||
| 
 | ||||
| 	return (void *) (pRegisters->m_esp->GetValue<unsigned long>() + iOffset); | ||||
| } | ||||
| 
 | ||||
| void x86MsStdcall::ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void* x86MsStdcall::GetReturnPtr(CRegisters* pRegisters) | ||||
| { | ||||
| 	if (m_returnType.type == DATA_TYPE_FLOAT || m_returnType.type == DATA_TYPE_DOUBLE) | ||||
| 		return pRegisters->m_st0->m_pAddress; | ||||
| 
 | ||||
| 	if (m_pReturnBuffer) | ||||
| 	{ | ||||
| 		// First half in eax, second half in edx
 | ||||
| 		memcpy(m_pReturnBuffer, pRegisters->m_eax, 4); | ||||
| 		memcpy((void *) ((unsigned long) m_pReturnBuffer + 4), pRegisters->m_edx, 4); | ||||
| 		return m_pReturnBuffer; | ||||
| 	} | ||||
| 
 | ||||
| 	return pRegisters->m_eax->m_pAddress; | ||||
| } | ||||
| 
 | ||||
| void x86MsStdcall::ReturnPtrChanged(CRegisters* pRegisters, void* pReturnPtr) | ||||
| { | ||||
| 	if (m_pReturnBuffer) | ||||
| 	{ | ||||
| 		// First half in eax, second half in edx
 | ||||
| 		memcpy(pRegisters->m_eax, m_pReturnBuffer, 4); | ||||
| 		memcpy(pRegisters->m_edx, (void *) ((unsigned long) m_pReturnBuffer + 4), 4); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										84
									
								
								DynamicHooks/conventions/x86MsStdcall.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								DynamicHooks/conventions/x86MsStdcall.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| #ifndef _X86_MS_STDCALL_H | ||||
| #define _X86_MS_STDCALL_H | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include "../convention.h" | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> CLASSES
 | ||||
| // ============================================================================
 | ||||
| /*
 | ||||
| Source: DynCall manual and Windows docs | ||||
| 
 | ||||
| Registers: | ||||
| 	- eax = return value | ||||
| 	- edx = return value | ||||
| 	- esp = stack pointer | ||||
| 	- st0 = floating point return value | ||||
| 
 | ||||
| Parameter passing: | ||||
| 	- stack parameter order: right-to-left | ||||
| 	- callee cleans up the stack | ||||
| 	- all arguments are pushed onto the stack | ||||
| 	- alignment: 4 bytes | ||||
| 
 | ||||
| Return values: | ||||
| 	- return values of pointer or intergral type (<= 32 bits) are returned via the eax register | ||||
| 	- integers > 32 bits are returned via the eax and edx registers | ||||
| 	- floating pointer types are returned via the st0 register | ||||
| */ | ||||
| class x86MsStdcall: public ICallingConvention | ||||
| {	 | ||||
| public: | ||||
| 	x86MsStdcall(std::vector<DataTypeSized_t> vecArgTypes, DataTypeSized_t returnType, int iAlignment=4); | ||||
| 	~x86MsStdcall(); | ||||
| 
 | ||||
| 	virtual std::list<Register_t> GetRegisters(); | ||||
| 	virtual int GetPopSize(); | ||||
| 	virtual int GetArgStackSize(); | ||||
| 	virtual void** GetStackArgumentPtr(CRegisters* pRegisters); | ||||
| 	 | ||||
| 	virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters); | ||||
| 	virtual void ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr); | ||||
| 
 | ||||
| 	virtual void* GetReturnPtr(CRegisters* pRegisters); | ||||
| 	virtual void ReturnPtrChanged(CRegisters* pRegisters, void* pReturnPtr); | ||||
| 
 | ||||
| private: | ||||
| 	void* m_pReturnBuffer; | ||||
| }; | ||||
| 
 | ||||
| #endif // _X86_MS_STDCALL_H
 | ||||
							
								
								
									
										161
									
								
								DynamicHooks/conventions/x86MsThiscall.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								DynamicHooks/conventions/x86MsThiscall.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,161 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include "x86MsThiscall.h" | ||||
| #include <string.h> | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> x86MsThiscall
 | ||||
| // ============================================================================
 | ||||
| x86MsThiscall::x86MsThiscall(std::vector<DataTypeSized_t> vecArgTypes, DataTypeSized_t returnType, int iAlignment) : | ||||
| 	ICallingConvention(vecArgTypes, returnType, iAlignment) | ||||
| { | ||||
| 	if (m_returnType.size > 4) | ||||
| 	{ | ||||
| 		m_pReturnBuffer = malloc(m_returnType.size); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		m_pReturnBuffer = NULL; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| x86MsThiscall::~x86MsThiscall() | ||||
| { | ||||
| 	if (m_pReturnBuffer) | ||||
| 	{ | ||||
| 		free(m_pReturnBuffer); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| std::list<Register_t> x86MsThiscall::GetRegisters() | ||||
| { | ||||
| 	std::list<Register_t> registers; | ||||
| 	 | ||||
| 	registers.push_back(ESP); | ||||
| 	registers.push_back(ECX); | ||||
| 
 | ||||
| 	if (m_returnType.type == DATA_TYPE_FLOAT || m_returnType.type == DATA_TYPE_DOUBLE) | ||||
| 	{ | ||||
| 		registers.push_back(ST0); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		registers.push_back(EAX); | ||||
| 		if (m_pReturnBuffer) | ||||
| 		{ | ||||
| 			registers.push_back(EDX); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return registers; | ||||
| } | ||||
| 
 | ||||
| int x86MsThiscall::GetPopSize() | ||||
| { | ||||
| 	// This pointer.
 | ||||
| 	// FIXME LINUX
 | ||||
| 	//int iPopSize = GetDataTypeSize(DATA_TYPE_POINTER, m_iAlignment);
 | ||||
| 	int iPopSize = 0; | ||||
| 
 | ||||
| 	for(unsigned int i=0; i < m_vecArgTypes.size(); i++) | ||||
| 	{ | ||||
| 		iPopSize += m_vecArgTypes[i].size; | ||||
| 	} | ||||
| 
 | ||||
| 	return iPopSize; | ||||
| } | ||||
| 
 | ||||
| int x86MsThiscall::GetArgStackSize() | ||||
| { | ||||
| 	int iArgStackSize = 0; | ||||
| 
 | ||||
| 	for (unsigned int i = 0; i < m_vecArgTypes.size(); i++) | ||||
| 	{ | ||||
| 		iArgStackSize += m_vecArgTypes[i].size; | ||||
| 	} | ||||
| 
 | ||||
| 	return iArgStackSize; | ||||
| } | ||||
| 
 | ||||
| void** x86MsThiscall::GetStackArgumentPtr(CRegisters* pRegisters) | ||||
| { | ||||
| 	return (void **)(pRegisters->m_esp->GetValue<unsigned long>() + 4); | ||||
| } | ||||
| 
 | ||||
| void* x86MsThiscall::GetArgumentPtr(int iIndex, CRegisters* pRegisters) | ||||
| { | ||||
| 	if (iIndex == 0) | ||||
| 	{ | ||||
| 		return pRegisters->m_ecx->m_pAddress; | ||||
| 	} | ||||
| 
 | ||||
| 	int iOffset = 4; | ||||
| 	for(int i=0; i < iIndex-1; i++) | ||||
| 	{ | ||||
| 		iOffset += m_vecArgTypes[i].size; | ||||
| 	} | ||||
| 
 | ||||
| 	return (void *) (pRegisters->m_esp->GetValue<unsigned long>() + iOffset); | ||||
| } | ||||
| 
 | ||||
| void x86MsThiscall::ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void* x86MsThiscall::GetReturnPtr(CRegisters* pRegisters) | ||||
| { | ||||
| 	if (m_returnType.type == DATA_TYPE_FLOAT || m_returnType.type == DATA_TYPE_DOUBLE) | ||||
| 		return pRegisters->m_st0->m_pAddress; | ||||
| 
 | ||||
| 	if (m_pReturnBuffer) | ||||
| 	{ | ||||
| 		// First half in eax, second half in edx
 | ||||
| 		memcpy(m_pReturnBuffer, pRegisters->m_eax, 4); | ||||
| 		memcpy((void *) ((unsigned long) m_pReturnBuffer + 4), pRegisters->m_edx, 4); | ||||
| 		return m_pReturnBuffer; | ||||
| 	} | ||||
| 
 | ||||
| 	return pRegisters->m_eax->m_pAddress; | ||||
| } | ||||
| 
 | ||||
| void x86MsThiscall::ReturnPtrChanged(CRegisters* pRegisters, void* pReturnPtr) | ||||
| { | ||||
| 	if (m_pReturnBuffer) | ||||
| 	{ | ||||
| 		// First half in eax, second half in edx
 | ||||
| 		memcpy(pRegisters->m_eax, m_pReturnBuffer, 4); | ||||
| 		memcpy(pRegisters->m_edx, (void *) ((unsigned long) m_pReturnBuffer + 4), 4); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										85
									
								
								DynamicHooks/conventions/x86MsThiscall.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								DynamicHooks/conventions/x86MsThiscall.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| #ifndef _X86_MS_THISCALL_H | ||||
| #define _X86_MS_THISCALL_H | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include "../convention.h" | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> CLASSES
 | ||||
| // ============================================================================
 | ||||
| /*
 | ||||
| Source: DynCall manual and Windows docs | ||||
| 
 | ||||
| Registers: | ||||
| 	- eax = return value | ||||
| 	- ecx = this pointer | ||||
| 	- edx = return value | ||||
| 	- esp = stack pointer | ||||
| 	- st0 = floating point return value | ||||
| 
 | ||||
| Parameter passing: | ||||
| 	- stack parameter order: right-to-left | ||||
| 	- callee cleans up the stack | ||||
| 	- all other arguments are pushed onto the stack | ||||
| 	- alignment: 4 bytes | ||||
| 
 | ||||
| Return values: | ||||
| 	- return values of pointer or intergral type (<= 32 bits) are returned via the eax register | ||||
| 	- integers > 32 bits are returned via the eax and edx registers | ||||
| 	- floating pointer types are returned via the st0 register | ||||
| */ | ||||
| class x86MsThiscall: public ICallingConvention | ||||
| {	 | ||||
| public: | ||||
| 	x86MsThiscall(std::vector<DataTypeSized_t> vecArgTypes, DataTypeSized_t returnType, int iAlignment=4); | ||||
| 	~x86MsThiscall(); | ||||
| 
 | ||||
| 	virtual std::list<Register_t> GetRegisters(); | ||||
| 	virtual int GetPopSize(); | ||||
| 	virtual int x86MsThiscall::GetArgStackSize(); | ||||
| 	virtual void** GetStackArgumentPtr(CRegisters* pRegisters); | ||||
| 	 | ||||
| 	virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters); | ||||
| 	virtual void ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr); | ||||
| 
 | ||||
| 	virtual void* GetReturnPtr(CRegisters* pRegisters); | ||||
| 	virtual void ReturnPtrChanged(CRegisters* pRegisters, void* pReturnPtr); | ||||
| 
 | ||||
| private: | ||||
| 	void* m_pReturnBuffer; | ||||
| }; | ||||
| 
 | ||||
| #endif // _X86_MS_THISCALL_H
 | ||||
							
								
								
									
										634
									
								
								DynamicHooks/hook.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										634
									
								
								DynamicHooks/hook.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,634 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from | ||||
| * the use of this software. | ||||
| * | ||||
| * Permission is granted to anyone to use this software for any purpose, | ||||
| * including commercial applications, and to alter it and redistribute it | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not | ||||
| * claim that you wrote the original software. If you use this software in a | ||||
| * product, an acknowledgment in the product documentation would be | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include "hook.h" | ||||
| #include "utilities.h" | ||||
| #include "asm.h" | ||||
| 
 | ||||
| 
 | ||||
| using namespace asmjit; | ||||
| using namespace asmjit::x86; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> DEFINITIONS
 | ||||
| // ============================================================================
 | ||||
| #define JMP_SIZE 6 | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> CHook
 | ||||
| // ============================================================================
 | ||||
| CHook::CHook(void* pFunc, ICallingConvention* pConvention) | ||||
| { | ||||
| 	m_pFunc = pFunc; | ||||
| 	m_pRegisters = new CRegisters(pConvention->GetRegisters()); | ||||
| 	m_pCallingConvention = pConvention; | ||||
| 
 | ||||
| 	unsigned char* pTarget = (unsigned char *) pFunc; | ||||
| 
 | ||||
| 	// Determine the number of bytes we need to copy
 | ||||
| 	int iBytesToCopy = copy_bytes(pTarget, NULL, JMP_SIZE); | ||||
| 
 | ||||
| 	// Create an array for the bytes to copy + a jump to the rest of the
 | ||||
| 	// function.
 | ||||
| 	unsigned char* pCopiedBytes = new unsigned char[iBytesToCopy + JMP_SIZE]; | ||||
| 
 | ||||
| 	// Fill the array with NOP instructions
 | ||||
| 	memset(pCopiedBytes, 0x90, iBytesToCopy + JMP_SIZE); | ||||
| 
 | ||||
| 	// Copy the required bytes to our array
 | ||||
| 	SetMemPatchable(pCopiedBytes, iBytesToCopy + JMP_SIZE); | ||||
| 	copy_bytes(pTarget, pCopiedBytes, JMP_SIZE); | ||||
| 
 | ||||
| 	// Write a jump after the copied bytes to the function/bridge + number of bytes to copy
 | ||||
| 	WriteJMP(pCopiedBytes + iBytesToCopy, pTarget + iBytesToCopy); | ||||
| 
 | ||||
| 	// Save the trampoline
 | ||||
| 	m_pTrampoline = (void *) pCopiedBytes; | ||||
| 
 | ||||
| 	// Create the bridge function
 | ||||
| 	m_pBridge = CreateBridge(); | ||||
| 
 | ||||
| 	// Write a jump to the bridge
 | ||||
| 	WriteJMP((unsigned char *) pFunc, m_pBridge); | ||||
| } | ||||
| 
 | ||||
| CHook::~CHook() | ||||
| { | ||||
| 	// Copy back the previously copied bytes
 | ||||
| 	copy_bytes((unsigned char *) m_pTrampoline, (unsigned char *) m_pFunc, JMP_SIZE); | ||||
| 
 | ||||
| 	// Free the trampoline array
 | ||||
| 	free(m_pTrampoline); | ||||
| 
 | ||||
| 	// Free the asm bridge and new return address
 | ||||
| 	m_Runtime.release(m_pBridge); | ||||
| 	m_Runtime.release(m_pNewRetAddr); | ||||
| 
 | ||||
| 	delete m_pRegisters; | ||||
| 	delete m_pCallingConvention; | ||||
| } | ||||
| 
 | ||||
| void CHook::AddCallback(HookType_t eHookType, HookHandlerFn* pCallback) | ||||
| { | ||||
| 	if (!pCallback) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (!IsCallbackRegistered(eHookType, pCallback)) | ||||
| 		m_hookHandler[eHookType].push_back(pCallback); | ||||
| } | ||||
| 
 | ||||
| void CHook::RemoveCallback(HookType_t eHookType, HookHandlerFn* pCallback) | ||||
| { | ||||
| 	if (IsCallbackRegistered(eHookType, pCallback)) | ||||
| 		m_hookHandler[eHookType].remove(pCallback); | ||||
| } | ||||
| 
 | ||||
| bool CHook::IsCallbackRegistered(HookType_t eHookType, HookHandlerFn* pCallback) | ||||
| { | ||||
| 	std::list<HookHandlerFn *> callbacks = m_hookHandler[eHookType]; | ||||
| 	for(std::list<HookHandlerFn *>::iterator it=callbacks.begin(); it != callbacks.end(); it++) | ||||
| 	{ | ||||
| 		if (*it == pCallback) | ||||
| 			return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| bool CHook::AreCallbacksRegistered() | ||||
| { | ||||
| 	return !m_hookHandler[HOOKTYPE_PRE].empty() || !m_hookHandler[HOOKTYPE_POST].empty(); | ||||
| } | ||||
| 
 | ||||
| bool CHook::HookHandler(HookType_t eHookType) | ||||
| { | ||||
| 	bool bOverride = false; | ||||
| 	std::list<HookHandlerFn *> callbacks = this->m_hookHandler[eHookType]; | ||||
| 	for(std::list<HookHandlerFn *>::iterator it=callbacks.begin(); it != callbacks.end(); it++) | ||||
| 	{ | ||||
| 		bool result = ((HookHandlerFn) *it)(eHookType, this); | ||||
| 		if (result) | ||||
| 			bOverride = true; | ||||
| 	} | ||||
| 	return bOverride; | ||||
| } | ||||
| 
 | ||||
| void* __cdecl CHook::GetReturnAddress(void* pESP) | ||||
| { | ||||
| 	if (m_RetAddr.count(pESP) == 0) | ||||
| 		puts("ESP not present."); | ||||
| 
 | ||||
| 	return m_RetAddr[pESP]; | ||||
| } | ||||
| 
 | ||||
| void __cdecl CHook::SetReturnAddress(void* pRetAddr, void* pESP) | ||||
| { | ||||
| 	m_RetAddr[pESP] = pRetAddr; | ||||
| } | ||||
| 
 | ||||
| void* CHook::CreateBridge() | ||||
| { | ||||
| 	X86Assembler a(&m_Runtime); | ||||
| 	Label label_supercede = a.newLabel(); | ||||
| 
 | ||||
| 	// Write a redirect to the post-hook code
 | ||||
| 	Write_ModifyReturnAddress(a); | ||||
| 
 | ||||
| 	// Call the pre-hook handler and jump to label_supercede if true was returned
 | ||||
| 	Write_CallHandler(a, HOOKTYPE_PRE); | ||||
| 	a.cmp(eax.r8(), true); | ||||
| 	 | ||||
| 	// Restore the previously saved registers, so any changes will be applied
 | ||||
| 	Write_RestoreRegisters(a); | ||||
| 
 | ||||
| 	a.je(label_supercede); | ||||
| 
 | ||||
| 	// Jump to the trampoline
 | ||||
| 	a.jmp(Ptr(m_pTrampoline)); | ||||
| 
 | ||||
| 	// This code will be executed if a pre-hook returns true
 | ||||
| 	a.bind(label_supercede); | ||||
| 
 | ||||
| 	// Finally, return to the caller
 | ||||
| 	// This will still call post hooks, but will skip the original function.
 | ||||
| 	a.ret(imm(m_pCallingConvention->GetPopSize())); | ||||
| 
 | ||||
| 	return a.make(); | ||||
| } | ||||
| 
 | ||||
| void CHook::Write_ModifyReturnAddress(X86Assembler& a) | ||||
| { | ||||
| 	// Save scratch registers that are used by SetReturnAddress
 | ||||
| 	static void* pEAX = NULL; | ||||
| 	static void* pECX = NULL; | ||||
| 	static void* pEDX = NULL; | ||||
| 	a.mov(dword_ptr_abs(Ptr(&pEAX)), eax); | ||||
| 	a.mov(dword_ptr_abs(Ptr(&pECX)), ecx); | ||||
| 	a.mov(dword_ptr_abs(Ptr(&pEDX)), edx); | ||||
| 
 | ||||
| 	// Store the return address in eax
 | ||||
| 	a.mov(eax, dword_ptr(esp)); | ||||
| 	 | ||||
| 	// Save the original return address by using the current esp as the key.
 | ||||
| 	// This should be unique until we have returned to the original caller.
 | ||||
| 	void (__cdecl CHook::*SetReturnAddress)(void*, void*) = &CHook::SetReturnAddress; | ||||
| 	a.push(esp); | ||||
| 	a.push(eax); | ||||
| 	a.push(imm_ptr(this)); | ||||
| 	a.call(imm_ptr((void *&)SetReturnAddress)); | ||||
| 	a.add(esp, 12); | ||||
| 	 | ||||
| 	// Restore scratch registers
 | ||||
| 	a.mov(eax, dword_ptr_abs(Ptr(&pEAX))); | ||||
| 	a.mov(ecx, dword_ptr_abs(Ptr(&pECX))); | ||||
| 	a.mov(edx, dword_ptr_abs(Ptr(&pEDX))); | ||||
| 
 | ||||
| 	// Override the return address. This is a redirect to our post-hook code
 | ||||
| 	m_pNewRetAddr = CreatePostCallback(); | ||||
| 	a.mov(dword_ptr(esp), imm_ptr(m_pNewRetAddr)); | ||||
| } | ||||
| 
 | ||||
| void* CHook::CreatePostCallback() | ||||
| { | ||||
| 	X86Assembler a(&m_Runtime); | ||||
| 
 | ||||
| 	int iPopSize = m_pCallingConvention->GetPopSize(); | ||||
| 
 | ||||
| 	// Subtract the previously added bytes (stack size + return address), so
 | ||||
| 	// that we can access the arguments again
 | ||||
| 	a.sub(esp, imm(iPopSize+4)); | ||||
| 
 | ||||
| 	// Call the post-hook handler
 | ||||
| 	Write_CallHandler(a, HOOKTYPE_POST); | ||||
| 
 | ||||
| 	// Restore the previously saved registers, so any changes will be applied
 | ||||
| 	Write_RestoreRegisters(a); | ||||
| 
 | ||||
| 	// Save scratch registers that are used by GetReturnAddress
 | ||||
| 	static void* pEAX = NULL; | ||||
| 	static void* pECX = NULL; | ||||
| 	static void* pEDX = NULL; | ||||
| 	a.mov(dword_ptr_abs(Ptr(&pEAX)), eax); | ||||
| 	a.mov(dword_ptr_abs(Ptr(&pECX)), ecx); | ||||
| 	a.mov(dword_ptr_abs(Ptr(&pEDX)), edx); | ||||
| 	 | ||||
| 	// Get the original return address
 | ||||
| 	void* (__cdecl CHook::*GetReturnAddress)(void*) = &CHook::GetReturnAddress; | ||||
| 	a.push(esp); | ||||
| 	a.push(imm_ptr(this)); | ||||
| 	a.call(imm_ptr((void *&)GetReturnAddress)); | ||||
| 	a.add(esp, 8); | ||||
| 
 | ||||
| 	// Save the original return address
 | ||||
| 	static void* pRetAddr = NULL; | ||||
| 	a.mov(dword_ptr_abs(Ptr(&pRetAddr)), eax); | ||||
| 	 | ||||
| 	// Restore scratch registers
 | ||||
| 	a.mov(eax, dword_ptr_abs(Ptr(&pEAX))); | ||||
| 	a.mov(ecx, dword_ptr_abs(Ptr(&pECX))); | ||||
| 	a.mov(edx, dword_ptr_abs(Ptr(&pEDX))); | ||||
| 
 | ||||
| 	// Add the bytes again to the stack (stack size + return address), so we
 | ||||
| 	// don't corrupt the stack.
 | ||||
| 	a.add(esp, imm(iPopSize+4)); | ||||
| 
 | ||||
| 	// Jump to the original return address
 | ||||
| 	a.jmp(dword_ptr_abs(Ptr(&pRetAddr))); | ||||
| 
 | ||||
| 	// Generate the code
 | ||||
| 	return a.make(); | ||||
| } | ||||
| 
 | ||||
| void CHook::Write_CallHandler(X86Assembler& a, HookType_t type) | ||||
| { | ||||
| 	bool (__cdecl CHook::*HookHandler)(HookType_t) = &CHook::HookHandler; | ||||
| 
 | ||||
| 	// Save the registers so that we can access them in our handlers
 | ||||
| 	Write_SaveRegisters(a); | ||||
| 
 | ||||
| 	// Call the global hook handler
 | ||||
| 	a.push(type); | ||||
| 	a.push(imm_ptr(this)); | ||||
| 	a.call(imm_ptr((void *&)HookHandler)); | ||||
| 	a.add(esp, 8); | ||||
| } | ||||
| 
 | ||||
| void CHook::Write_SaveRegisters(X86Assembler& a) | ||||
| { | ||||
| 	std::list<Register_t> vecRegistersToSave = m_pCallingConvention->GetRegisters(); | ||||
| 	for(std::list<Register_t>::iterator it=vecRegistersToSave.begin(); it != vecRegistersToSave.end(); it++) | ||||
| 	{ | ||||
| 		switch(*it) | ||||
| 		{ | ||||
| 		// ========================================================================
 | ||||
| 		// >> 8-bit General purpose registers
 | ||||
| 		// ========================================================================
 | ||||
| 		case AL: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_al->m_pAddress)), al); break; | ||||
| 		case CL: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_cl->m_pAddress)), cl); break; | ||||
| 		case DL: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_dl->m_pAddress)), dl); break; | ||||
| 		case BL: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_bl->m_pAddress)), bl); break; | ||||
| 
 | ||||
| #if defined(ASMJIT_X64) | ||||
| 		// 64-bit mode only
 | ||||
| 		case SPL: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_spl->m_pAddress)), spl); break; | ||||
| 		case BPL: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_bpl->m_pAddress)), bpl); break; | ||||
| 		case SIL: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_sil->m_pAddress)), sil); break; | ||||
| 		case DIL: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_dil->m_pAddress)), dil); break; | ||||
| 		case R8B: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_r8b->m_pAddress)), r8b); break; | ||||
| 		case R9B: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_r9b->m_pAddress)), r9b); break; | ||||
| 		case R10B: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_r10b->m_pAddress)), r10b); break; | ||||
| 		case R11B: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_r11b->m_pAddress)), r11b); break; | ||||
| 		case R12B: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_r12b->m_pAddress)), r12b); break; | ||||
| 		case R13B: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_r13b->m_pAddress)), r13b); break; | ||||
| 		case R14B: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_r14b->m_pAddress)), r14b); break; | ||||
| 		case R15B: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_r15b->m_pAddress)), r15b); break; | ||||
| #endif // ASMJIT_X64
 | ||||
| 
 | ||||
| 		case AH: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_ah->m_pAddress)), ah); break; | ||||
| 		case CH: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_ch->m_pAddress)), ch); break; | ||||
| 		case DH: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_dh->m_pAddress)), dh); break; | ||||
| 		case BH: a.mov(byte_ptr_abs(Ptr(m_pRegisters->m_bh->m_pAddress)), bh); break; | ||||
| 
 | ||||
| 		// ========================================================================
 | ||||
| 		// >> 16-bit General purpose registers
 | ||||
| 		// ========================================================================
 | ||||
| 		case AX: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_ax->m_pAddress)), ax); break; | ||||
| 		case CX: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_cx->m_pAddress)), cx); break; | ||||
| 		case DX: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_dx->m_pAddress)), dx); break; | ||||
| 		case BX: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_bx->m_pAddress)), bx); break; | ||||
| 		case SP: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_sp->m_pAddress)), x86::sp); break; | ||||
| 		case BP: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_bp->m_pAddress)), bp); break; | ||||
| 		case SI: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_si->m_pAddress)), si); break; | ||||
| 		case DI: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_di->m_pAddress)), di); break; | ||||
| 
 | ||||
| #if defined(ASMJIT_X64) | ||||
| 		// 64-bit mode only
 | ||||
| 		case R8W: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_r8w->m_pAddress)), r8w); break; | ||||
| 		case R9W: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_r9w->m_pAddress)), r9w); break; | ||||
| 		case R10W: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_r10w->m_pAddress)), r10w); break; | ||||
| 		case R11W: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_r11w->m_pAddress)), r11w); break; | ||||
| 		case R12W: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_r12w->m_pAddress)), r12w); break; | ||||
| 		case R13W: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_r13w->m_pAddress)), r13w); break; | ||||
| 		case R14W: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_r14w->m_pAddress)), r14w); break; | ||||
| 		case R15W: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_r15w->m_pAddress)), r15w); break; | ||||
| #endif // ASMJIT_X64
 | ||||
| 
 | ||||
| 		// ========================================================================
 | ||||
| 		// >> 32-bit General purpose registers
 | ||||
| 		// ========================================================================
 | ||||
| 		case EAX: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_eax->m_pAddress)), eax); break; | ||||
| 		case ECX: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_ecx->m_pAddress)), ecx); break; | ||||
| 		case EDX: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_edx->m_pAddress)), edx); break; | ||||
| 		case EBX: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_ebx->m_pAddress)), ebx); break; | ||||
| 		case ESP: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_esp->m_pAddress)), esp); break; | ||||
| 		case EBP: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_ebp->m_pAddress)), ebp); break; | ||||
| 		case ESI: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_esi->m_pAddress)), esi); break; | ||||
| 		case EDI: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_edi->m_pAddress)), edi); break; | ||||
| 
 | ||||
| #if defined(ASMJIT_X64) | ||||
| 		// 64-bit mode only
 | ||||
| 		case R8D: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_r8d->m_pAddress)), r8d); break; | ||||
| 		case R9D: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_r9d->m_pAddress)), r9d); break; | ||||
| 		case R10D: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_r10d->m_pAddress)), r10d); break; | ||||
| 		case R11D: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_r11d->m_pAddress)), r11d); break; | ||||
| 		case R12D: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_r12d->m_pAddress)), r12d); break; | ||||
| 		case R13D: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_r13d->m_pAddress)), r13d); break; | ||||
| 		case R14D: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_r14d->m_pAddress)), r14d); break; | ||||
| 		case R15D: a.mov(dword_ptr_abs(Ptr(m_pRegisters->m_r15d->m_pAddress)), r15d); break; | ||||
| #endif // ASMJIT_X64
 | ||||
| 
 | ||||
| 		// ========================================================================
 | ||||
| 		// >> 64-bit General purpose registers
 | ||||
| 		// ========================================================================
 | ||||
| #if defined(ASMJIT_X64) | ||||
| 		// 64-bit mode only
 | ||||
| 		case RAX: a.mov(qword_ptr_abs((m_pRegisters->m_rax->m_pAddress)), rax); break; | ||||
| 		case RCX: a.mov(qword_ptr_abs((m_pRegisters->m_rcx->m_pAddress)), rcx); break; | ||||
| 		case RDX: a.mov(qword_ptr_abs((m_pRegisters->m_rdx->m_pAddress)), rdx); break; | ||||
| 		case RBX: a.mov(qword_ptr_abs((m_pRegisters->m_rbx->m_pAddress)), rbx); break; | ||||
| 		case RSP: a.mov(qword_ptr_abs((m_pRegisters->m_rsp->m_pAddress)), rsp); break; | ||||
| 		case RBP: a.mov(qword_ptr_abs((m_pRegisters->m_rbp->m_pAddress)), rbp); break; | ||||
| 		case RSI: a.mov(qword_ptr_abs((m_pRegisters->m_rsi->m_pAddress)), rsi); break; | ||||
| 		case RDI: a.mov(qword_ptr_abs((m_pRegisters->m_rdi->m_pAddress)), rdi); break; | ||||
| #endif // ASMJIT_X64
 | ||||
| 
 | ||||
| #if defined(ASMJIT_X64) | ||||
| 		// 64-bit mode only
 | ||||
| 		case R8: a.mov(qword_ptr_abs(Ptr(m_pRegisters->m_r8->m_pAddress)), r8); break; | ||||
| 		case R9: a.mov(qword_ptr_abs(Ptr(m_pRegisters->m_r9->m_pAddress)), r9); break; | ||||
| 		case R10: a.mov(qword_ptr_abs(Ptr(m_pRegisters->m_r10->m_pAddress)), r10); break; | ||||
| 		case R11: a.mov(qword_ptr_abs(Ptr(m_pRegisters->m_r11->m_pAddress)), r11); break; | ||||
| 		case R12: a.mov(qword_ptr_abs(Ptr(m_pRegisters->m_r12->m_pAddress)), r12); break; | ||||
| 		case R13: a.mov(qword_ptr_abs(Ptr(m_pRegisters->m_r13->m_pAddress)), r13); break; | ||||
| 		case R14: a.mov(qword_ptr_abs(Ptr(m_pRegisters->m_r14->m_pAddress)), r14); break; | ||||
| 		case R15: a.mov(qword_ptr_abs(Ptr(m_pRegisters->m_r15->m_pAddress)), r15); break; | ||||
| #endif // ASMJIT_X64
 | ||||
| 
 | ||||
| 		// ========================================================================
 | ||||
| 		// >> 64-bit MM (MMX) registers
 | ||||
| 		// ========================================================================
 | ||||
| 		case MM0: a.movq(qword_ptr_abs(Ptr(m_pRegisters->m_mm0->m_pAddress)), mm0); break; | ||||
| 		case MM1: a.movq(qword_ptr_abs(Ptr(m_pRegisters->m_mm1->m_pAddress)), mm1); break; | ||||
| 		case MM2: a.movq(qword_ptr_abs(Ptr(m_pRegisters->m_mm2->m_pAddress)), mm2); break; | ||||
| 		case MM3: a.movq(qword_ptr_abs(Ptr(m_pRegisters->m_mm3->m_pAddress)), mm3); break; | ||||
| 		case MM4: a.movq(qword_ptr_abs(Ptr(m_pRegisters->m_mm4->m_pAddress)), mm4); break; | ||||
| 		case MM5: a.movq(qword_ptr_abs(Ptr(m_pRegisters->m_mm5->m_pAddress)), mm5); break; | ||||
| 		case MM6: a.movq(qword_ptr_abs(Ptr(m_pRegisters->m_mm6->m_pAddress)), mm6); break; | ||||
| 		case MM7: a.movq(qword_ptr_abs(Ptr(m_pRegisters->m_mm7->m_pAddress)), mm7); break; | ||||
| 
 | ||||
| 		// ========================================================================
 | ||||
| 		// >> 128-bit XMM registers
 | ||||
| 		// ========================================================================
 | ||||
| 		// TODO: Also provide movups?
 | ||||
| 		case XMM0: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm0->m_pAddress)), xmm0); break; | ||||
| 		case XMM1: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm1->m_pAddress)), xmm1); break; | ||||
| 		case XMM2: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm2->m_pAddress)), xmm2); break; | ||||
| 		case XMM3: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm3->m_pAddress)), xmm3); break; | ||||
| 		case XMM4: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm4->m_pAddress)), xmm4); break; | ||||
| 		case XMM5: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm5->m_pAddress)), xmm5); break; | ||||
| 		case XMM6: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm6->m_pAddress)), xmm6); break; | ||||
| 		case XMM7: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm7->m_pAddress)), xmm7); break; | ||||
| 
 | ||||
| #if defined(ASMJIT_X64) | ||||
| 		// 64-bit mode only
 | ||||
| 		case XMM8: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm8->m_pAddress)), xmm8); break; | ||||
| 		case XMM9: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm9->m_pAddress)), xmm9); break; | ||||
| 		case XMM10: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm10->m_pAddress)), xmm10); break; | ||||
| 		case XMM11: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm11->m_pAddress)), xmm11); break; | ||||
| 		case XMM12: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm12->m_pAddress)), xmm12); break; | ||||
| 		case XMM13: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm13->m_pAddress)), xmm13); break; | ||||
| 		case XMM14: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm14->m_pAddress)), xmm14); break; | ||||
| 		case XMM15: a.movaps(qword_ptr_abs(Ptr(m_pRegisters->m_xmm15->m_pAddress)), xmm15); break; | ||||
| #endif // ASMJIT_X64
 | ||||
| 
 | ||||
| 		// ========================================================================
 | ||||
| 		// >> 16-bit Segment registers
 | ||||
| 		// ========================================================================
 | ||||
| 		case CS: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_cs->m_pAddress)), cs); break; | ||||
| 		case SS: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_ss->m_pAddress)), ss); break; | ||||
| 		case DS: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_ds->m_pAddress)), ds); break; | ||||
| 		case ES: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_es->m_pAddress)), es); break; | ||||
| 		case FS: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_fs->m_pAddress)), fs); break; | ||||
| 		case GS: a.mov(word_ptr_abs(Ptr(m_pRegisters->m_gs->m_pAddress)), gs); break; | ||||
| 
 | ||||
| 		// ========================================================================
 | ||||
| 		// >> 80-bit FPU registers
 | ||||
| 		// ========================================================================
 | ||||
| 		case ST0: a.fst(dword_ptr_abs(Ptr(m_pRegisters->m_st0->m_pAddress))); break; | ||||
| 		//case ST1: a.mov(tword_ptr_abs(Ptr(m_pRegisters->m_st1->m_pAddress)), st1); break;
 | ||||
| 		//case ST2: a.mov(tword_ptr_abs(Ptr(m_pRegisters->m_st2->m_pAddress)), st2); break;
 | ||||
| 		//case ST3: a.mov(tword_ptr_abs(Ptr(m_pRegisters->m_st3->m_pAddress)), st3); break;
 | ||||
| 		//case ST4: a.mov(tword_ptr_abs(Ptr(m_pRegisters->m_st4->m_pAddress)), st4); break;
 | ||||
| 		//case ST5: a.mov(tword_ptr_abs(Ptr(m_pRegisters->m_st5->m_pAddress)), st5); break;
 | ||||
| 		//case ST6: a.mov(tword_ptr_abs(Ptr(m_pRegisters->m_st6->m_pAddress)), st6); break;
 | ||||
| 		//case ST7: a.mov(tword_ptr_abs(Ptr(m_pRegisters->m_st7->m_pAddress)), st7); break;
 | ||||
| 
 | ||||
| 		default: puts("Unsupported register."); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void CHook::Write_RestoreRegisters(X86Assembler& a) | ||||
| { | ||||
| 	std::list<Register_t> vecRegistersToSave = m_pCallingConvention->GetRegisters(); | ||||
| 	for(std::list<Register_t>::iterator it=vecRegistersToSave.begin(); it != vecRegistersToSave.end(); it++) | ||||
| 	{ | ||||
| 		switch(*it) | ||||
| 		{ | ||||
| 		// ========================================================================
 | ||||
| 		// >> 8-bit General purpose registers
 | ||||
| 		// ========================================================================
 | ||||
| 		case AL: a.mov(al, byte_ptr_abs(Ptr(m_pRegisters->m_al->m_pAddress))); break; | ||||
| 		case CL: a.mov(cl, byte_ptr_abs(Ptr(m_pRegisters->m_cl->m_pAddress))); break; | ||||
| 		case DL: a.mov(dl, byte_ptr_abs(Ptr(m_pRegisters->m_dl->m_pAddress))); break; | ||||
| 		case BL: a.mov(bl, byte_ptr_abs(Ptr(m_pRegisters->m_bl->m_pAddress))); break; | ||||
| 
 | ||||
| #if defined(ASMJIT_X64) | ||||
| 		// 64-bit mode only
 | ||||
| 		case SPL: a.mov(spl, byte_ptr_abs(Ptr(m_pRegisters->m_spl->m_pAddress))); break; | ||||
| 		case BPL: a.mov(bpl, byte_ptr_abs(Ptr(m_pRegisters->m_bpl->m_pAddress))); break; | ||||
| 		case SIL: a.mov(sil, byte_ptr_abs(Ptr(m_pRegisters->m_sil->m_pAddress))); break; | ||||
| 		case DIL: a.mov(dil, byte_ptr_abs(Ptr(m_pRegisters->m_dil->m_pAddress))); break; | ||||
| 		case R8B: a.mov(r8b, byte_ptr_abs(Ptr(m_pRegisters->m_r8b->m_pAddress))); break; | ||||
| 		case R9B: a.mov(r9b, byte_ptr_abs(Ptr(m_pRegisters->m_r9b->m_pAddress))); break; | ||||
| 		case R10B: a.mov(r10b, byte_ptr_abs(Ptr(m_pRegisters->m_r10b->m_pAddress))); break; | ||||
| 		case R11B: a.mov(r11b, byte_ptr_abs(Ptr(m_pRegisters->m_r11b->m_pAddress))); break; | ||||
| 		case R12B: a.mov(r12b, byte_ptr_abs(Ptr(m_pRegisters->m_r12b->m_pAddress))); break; | ||||
| 		case R13B: a.mov(r13b, byte_ptr_abs(Ptr(m_pRegisters->m_r13b->m_pAddress))); break; | ||||
| 		case R14B: a.mov(r14b, byte_ptr_abs(Ptr(m_pRegisters->m_r14b->m_pAddress))); break; | ||||
| 		case R15B: a.mov(r15b, byte_ptr_abs(Ptr(m_pRegisters->m_r15b->m_pAddress))); break; | ||||
| #endif // ASMJIT_X64
 | ||||
| 
 | ||||
| 		case AH: a.mov(ah, byte_ptr_abs(Ptr(m_pRegisters->m_ah->m_pAddress))); break; | ||||
| 		case CH: a.mov(ch, byte_ptr_abs(Ptr(m_pRegisters->m_ch->m_pAddress))); break; | ||||
| 		case DH: a.mov(dh, byte_ptr_abs(Ptr(m_pRegisters->m_dh->m_pAddress))); break; | ||||
| 		case BH: a.mov(bh, byte_ptr_abs(Ptr(m_pRegisters->m_bh->m_pAddress))); break; | ||||
| 
 | ||||
| 		// ========================================================================
 | ||||
| 		// >> 16-bit General purpose registers
 | ||||
| 		// ========================================================================
 | ||||
| 		case AX: a.mov(ax, word_ptr_abs(Ptr(m_pRegisters->m_ax->m_pAddress))); break; | ||||
| 		case CX: a.mov(cx, word_ptr_abs(Ptr(m_pRegisters->m_cx->m_pAddress))); break; | ||||
| 		case DX: a.mov(dx, word_ptr_abs(Ptr(m_pRegisters->m_dx->m_pAddress))); break; | ||||
| 		case BX: a.mov(bx, word_ptr_abs(Ptr(m_pRegisters->m_bx->m_pAddress))); break; | ||||
| 		case SP: a.mov(x86::sp, word_ptr_abs(Ptr(m_pRegisters->m_sp->m_pAddress))); break; | ||||
| 		case BP: a.mov(bp, word_ptr_abs(Ptr(m_pRegisters->m_bp->m_pAddress))); break; | ||||
| 		case SI: a.mov(si, word_ptr_abs(Ptr(m_pRegisters->m_si->m_pAddress))); break; | ||||
| 		case DI: a.mov(di, word_ptr_abs(Ptr(m_pRegisters->m_di->m_pAddress))); break; | ||||
| 
 | ||||
| #if defined(ASMJIT_X64) | ||||
| 		// 64-bit mode only
 | ||||
| 		case R8W: a.mov(r8w, word_ptr_abs(Ptr(m_pRegisters->m_r8w->m_pAddress))); break; | ||||
| 		case R9W: a.mov(r9w, word_ptr_abs(Ptr(m_pRegisters->m_r9w->m_pAddress))); break; | ||||
| 		case R10W: a.mov(r10w, word_ptr_abs(Ptr(m_pRegisters->m_r10w->m_pAddress))); break; | ||||
| 		case R11W: a.mov(r11w, word_ptr_abs(Ptr(m_pRegisters->m_r11w->m_pAddress))); break; | ||||
| 		case R12W: a.mov(r12w, word_ptr_abs(Ptr(m_pRegisters->m_r12w->m_pAddress))); break; | ||||
| 		case R13W: a.mov(r13w, word_ptr_abs(Ptr(m_pRegisters->m_r13w->m_pAddress))); break; | ||||
| 		case R14W: a.mov(r14w, word_ptr_abs(Ptr(m_pRegisters->m_r14w->m_pAddress))); break; | ||||
| 		case R15W: a.mov(r15w, word_ptr_abs(Ptr(m_pRegisters->m_r15w->m_pAddress))); break; | ||||
| #endif // ASMJIT_X64
 | ||||
| 
 | ||||
| 		// ========================================================================
 | ||||
| 		// >> 32-bit General purpose registers
 | ||||
| 		// ========================================================================
 | ||||
| 		case EAX: a.mov(eax, dword_ptr_abs(Ptr(m_pRegisters->m_eax->m_pAddress))); break; | ||||
| 		case ECX: a.mov(ecx, dword_ptr_abs(Ptr(m_pRegisters->m_ecx->m_pAddress))); break; | ||||
| 		case EDX: a.mov(edx, dword_ptr_abs(Ptr(m_pRegisters->m_edx->m_pAddress))); break; | ||||
| 		case EBX: a.mov(ebx, dword_ptr_abs(Ptr(m_pRegisters->m_ebx->m_pAddress))); break; | ||||
| 		case ESP: a.mov(esp, dword_ptr_abs(Ptr(m_pRegisters->m_esp->m_pAddress))); break; | ||||
| 		case EBP: a.mov(ebp, dword_ptr_abs(Ptr(m_pRegisters->m_ebp->m_pAddress))); break; | ||||
| 		case ESI: a.mov(esi, dword_ptr_abs(Ptr(m_pRegisters->m_esi->m_pAddress))); break; | ||||
| 		case EDI: a.mov(edi, dword_ptr_abs(Ptr(m_pRegisters->m_edi->m_pAddress))); break; | ||||
| 
 | ||||
| #if defined(ASMJIT_X64) | ||||
| 		// 64-bit mode only
 | ||||
| 		case R8D: a.mov(r8d, qword_ptr_abs(Ptr(m_pRegisters->m_r8d->m_pAddress))); break; | ||||
| 		case R9D: a.mov(r9d, qword_ptr_abs(Ptr(m_pRegisters->m_r9d->m_pAddress))); break; | ||||
| 		case R10D: a.mov(r10d, qword_ptr_abs(Ptr(m_pRegisters->m_r10d->m_pAddress))); break; | ||||
| 		case R11D: a.mov(r11d, qword_ptr_abs(Ptr(m_pRegisters->m_r11d->m_pAddress))); break; | ||||
| 		case R12D: a.mov(r12d, qword_ptr_abs(Ptr(m_pRegisters->m_r12d->m_pAddress))); break; | ||||
| 		case R13D: a.mov(r13d, qword_ptr_abs(Ptr(m_pRegisters->m_r13d->m_pAddress))); break; | ||||
| 		case R14D: a.mov(r14d, qword_ptr_abs(Ptr(m_pRegisters->m_r14d->m_pAddress))); break; | ||||
| 		case R15D: a.mov(r15d, qword_ptr_abs(Ptr(m_pRegisters->m_r15d->m_pAddress))); break; | ||||
| #endif // ASMJIT_X64
 | ||||
| 
 | ||||
| 		// ========================================================================
 | ||||
| 		// >> 64-bit General purpose registers
 | ||||
| 		// ========================================================================
 | ||||
| #if defined(ASMJIT_X64) | ||||
| 		// 64-bit mode only
 | ||||
| 		case RAX: a.mov(rax, qword_ptr_abs(Ptr(m_pRegisters->m_rax->m_pAddress))); break; | ||||
| 		case RCX: a.mov(rcx, qword_ptr_abs(Ptr(m_pRegisters->m_rcx->m_pAddress))); break; | ||||
| 		case RDX: a.mov(rdx, qword_ptr_abs(Ptr(m_pRegisters->m_rdx->m_pAddress))); break; | ||||
| 		case RBX: a.mov(rbx, qword_ptr_abs(Ptr(m_pRegisters->m_rbx->m_pAddress))); break; | ||||
| 		case RSP: a.mov(rsp, qword_ptr_abs(Ptr(m_pRegisters->m_rsp->m_pAddress))); break; | ||||
| 		case RBP: a.mov(rbp, qword_ptr_abs(Ptr(m_pRegisters->m_rbp->m_pAddress))); break; | ||||
| 		case RSI: a.mov(rsi, qword_ptr_abs(Ptr(m_pRegisters->m_rsi->m_pAddress))); break; | ||||
| 		case RDI: a.mov(rdi, qword_ptr_abs(Ptr(m_pRegisters->m_rdi->m_pAddress))); break; | ||||
| #endif // ASMJIT_X64
 | ||||
| 
 | ||||
| #if defined(ASMJIT_X64) | ||||
| 		// 64-bit mode only
 | ||||
| 		case R8: a.mov(r8, qword_ptr_abs(Ptr(m_pRegisters->m_r8->m_pAddress))); break; | ||||
| 		case R9: a.mov(r9, qword_ptr_abs(Ptr(m_pRegisters->m_r9->m_pAddress))); break; | ||||
| 		case R10: a.mov(r10, qword_ptr_abs(Ptr(m_pRegisters->m_r10->m_pAddress))); break; | ||||
| 		case R11: a.mov(r11, qword_ptr_abs(Ptr(m_pRegisters->m_r11->m_pAddress))); break; | ||||
| 		case R12: a.mov(r12, qword_ptr_abs(Ptr(m_pRegisters->m_r12->m_pAddress))); break; | ||||
| 		case R13: a.mov(r13, qword_ptr_abs(Ptr(m_pRegisters->m_r13->m_pAddress))); break; | ||||
| 		case R14: a.mov(r14, qword_ptr_abs(Ptr(m_pRegisters->m_r14->m_pAddress))); break; | ||||
| 		case R15: a.mov(r15, qword_ptr_abs(Ptr(m_pRegisters->m_r15->m_pAddress))); break; | ||||
| #endif // ASMJIT_X64
 | ||||
| 
 | ||||
| 		// ========================================================================
 | ||||
| 		// >> 64-bit MM (MMX) registers
 | ||||
| 		// ========================================================================
 | ||||
| 		case MM0: a.movq(mm0, qword_ptr_abs(Ptr(m_pRegisters->m_mm0->m_pAddress))); break; | ||||
| 		case MM1: a.movq(mm1, qword_ptr_abs(Ptr(m_pRegisters->m_mm1->m_pAddress))); break; | ||||
| 		case MM2: a.movq(mm2, qword_ptr_abs(Ptr(m_pRegisters->m_mm2->m_pAddress))); break; | ||||
| 		case MM3: a.movq(mm3, qword_ptr_abs(Ptr(m_pRegisters->m_mm3->m_pAddress))); break; | ||||
| 		case MM4: a.movq(mm4, qword_ptr_abs(Ptr(m_pRegisters->m_mm4->m_pAddress))); break; | ||||
| 		case MM5: a.movq(mm5, qword_ptr_abs(Ptr(m_pRegisters->m_mm5->m_pAddress))); break; | ||||
| 		case MM6: a.movq(mm6, qword_ptr_abs(Ptr(m_pRegisters->m_mm6->m_pAddress))); break; | ||||
| 		case MM7: a.movq(mm7, qword_ptr_abs(Ptr(m_pRegisters->m_mm7->m_pAddress))); break; | ||||
| 
 | ||||
| 		// ========================================================================
 | ||||
| 		// >> 128-bit XMM registers
 | ||||
| 		// ========================================================================
 | ||||
| 		// TODO: Also provide movups?
 | ||||
| 		case XMM0: a.movaps(xmm0, oword_ptr_abs(Ptr(m_pRegisters->m_xmm0->m_pAddress))); break; | ||||
| 		case XMM1: a.movaps(xmm1, oword_ptr_abs(Ptr(m_pRegisters->m_xmm1->m_pAddress))); break; | ||||
| 		case XMM2: a.movaps(xmm2, oword_ptr_abs(Ptr(m_pRegisters->m_xmm2->m_pAddress))); break; | ||||
| 		case XMM3: a.movaps(xmm3, oword_ptr_abs(Ptr(m_pRegisters->m_xmm3->m_pAddress))); break; | ||||
| 		case XMM4: a.movaps(xmm4, oword_ptr_abs(Ptr(m_pRegisters->m_xmm4->m_pAddress))); break; | ||||
| 		case XMM5: a.movaps(xmm5, oword_ptr_abs(Ptr(m_pRegisters->m_xmm5->m_pAddress))); break; | ||||
| 		case XMM6: a.movaps(xmm6, oword_ptr_abs(Ptr(m_pRegisters->m_xmm6->m_pAddress))); break; | ||||
| 		case XMM7: a.movaps(xmm7, oword_ptr_abs(Ptr(m_pRegisters->m_xmm7->m_pAddress))); break; | ||||
| 
 | ||||
| #if defined(ASMJIT_X64) | ||||
| 		// 64-bit mode only
 | ||||
| 		case XMM8: a.movaps(xmm8, qword_ptr_abs(Ptr(m_pRegisters->m_xmm8->m_pAddress))); break; | ||||
| 		case XMM9: a.movaps(xmm9, qword_ptr_abs(Ptr(m_pRegisters->m_xmm9->m_pAddress))); break; | ||||
| 		case XMM10: a.movaps(xmm10, qword_ptr_abs(Ptr(m_pRegisters->m_xmm10->m_pAddress))); break; | ||||
| 		case XMM11: a.movaps(xmm11, qword_ptr_abs(Ptr(m_pRegisters->m_xmm11->m_pAddress))); break; | ||||
| 		case XMM12: a.movaps(xmm12, qword_ptr_abs(Ptr(m_pRegisters->m_xmm12->m_pAddress))); break; | ||||
| 		case XMM13: a.movaps(xmm13, qword_ptr_abs(Ptr(m_pRegisters->m_xmm13->m_pAddress))); break; | ||||
| 		case XMM14: a.movaps(xmm14, qword_ptr_abs(Ptr(m_pRegisters->m_xmm14->m_pAddress))); break; | ||||
| 		case XMM15: a.movaps(xmm15, qword_ptr_abs(Ptr(m_pRegisters->m_xmm15->m_pAddress))); break; | ||||
| #endif // ASMJIT_X64
 | ||||
| 
 | ||||
| 		// ========================================================================
 | ||||
| 		// >> 16-bit Segment registers
 | ||||
| 		// ========================================================================
 | ||||
| 		case CS: a.mov(cs, word_ptr_abs(Ptr(m_pRegisters->m_cs->m_pAddress))); break; | ||||
| 		case SS: a.mov(ss, word_ptr_abs(Ptr(m_pRegisters->m_ss->m_pAddress))); break; | ||||
| 		case DS: a.mov(ds, word_ptr_abs(Ptr(m_pRegisters->m_ds->m_pAddress))); break; | ||||
| 		case ES: a.mov(es, word_ptr_abs(Ptr(m_pRegisters->m_es->m_pAddress))); break; | ||||
| 		case FS: a.mov(fs, word_ptr_abs(Ptr(m_pRegisters->m_fs->m_pAddress))); break; | ||||
| 		case GS: a.mov(gs, word_ptr_abs(Ptr(m_pRegisters->m_gs->m_pAddress))); break; | ||||
| 
 | ||||
| 		// ========================================================================
 | ||||
| 		// >> 80-bit FPU registers
 | ||||
| 		// ========================================================================
 | ||||
| 		case ST0: a.fld(dword_ptr_abs(Ptr(m_pRegisters->m_st0->m_pAddress))); break; | ||||
| 		//case ST1: a.mov(st1, tword_ptr_abs(Ptr(m_pRegisters->m_st1->m_pAddress))); break;
 | ||||
| 		//case ST2: a.mov(st2, tword_ptr_abs(Ptr(m_pRegisters->m_st2->m_pAddress))); break;
 | ||||
| 		//case ST3: a.mov(st3, tword_ptr_abs(Ptr(m_pRegisters->m_st3->m_pAddress))); break;
 | ||||
| 		//case ST4: a.mov(st4, tword_ptr_abs(Ptr(m_pRegisters->m_st4->m_pAddress))); break;
 | ||||
| 		//case ST5: a.mov(st5, tword_ptr_abs(Ptr(m_pRegisters->m_st5->m_pAddress))); break;
 | ||||
| 		//case ST6: a.mov(st6, tword_ptr_abs(Ptr(m_pRegisters->m_st6->m_pAddress))); break;
 | ||||
| 		//case ST7: a.mov(st7, tword_ptr_abs(Ptr(m_pRegisters->m_st7->m_pAddress))); break;
 | ||||
| 
 | ||||
| 		default: puts("Unsupported register."); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										187
									
								
								DynamicHooks/hook.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								DynamicHooks/hook.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,187 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| #ifndef _HOOK_H | ||||
| #define _HOOK_H | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include <list> | ||||
| #include <map> | ||||
| 
 | ||||
| #include "registers.h" | ||||
| #include "convention.h" | ||||
| #include "AsmJit/asmjit.h" | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> HookType_t
 | ||||
| // ============================================================================
 | ||||
| enum HookType_t | ||||
| { | ||||
| 	// Callback will be executed before the original function.
 | ||||
| 	HOOKTYPE_PRE, | ||||
| 
 | ||||
| 	// Callback will be executed after the original function.
 | ||||
| 	HOOKTYPE_POST | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> TYPEDEFS
 | ||||
| // ============================================================================
 | ||||
| class CHook; | ||||
| typedef bool (*HookHandlerFn)(HookType_t, CHook*); | ||||
| 
 | ||||
| #ifdef __linux__ | ||||
| #define __cdecl | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> CLASSES
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| class CHook | ||||
| { | ||||
| private: | ||||
| 	friend class CHookManager; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	Creates a new function hook. | ||||
| 
 | ||||
| 	@param <pFunc>: | ||||
| 	The address of the function to hook | ||||
| 
 | ||||
| 	@param <pConvention>: | ||||
| 	The calling convention of <pFunc>. | ||||
| 	*/ | ||||
| 	CHook(void* pFunc, ICallingConvention* pConvention); | ||||
| 	~CHook(); | ||||
| 
 | ||||
| public: | ||||
| 	/*
 | ||||
| 	Adds a hook handler to the hook. | ||||
| 
 | ||||
| 	@param type The hook type. | ||||
| 	@param pFunc The hook handler that should be added. | ||||
| 	*/ | ||||
| 	void AddCallback(HookType_t type, HookHandlerFn* pFunc); | ||||
| 	 | ||||
| 	/*
 | ||||
| 	Removes a hook handler to the hook. | ||||
| 
 | ||||
| 	@param type The hook type. | ||||
| 	@param pFunc The hook handler that should be removed. | ||||
| 	*/ | ||||
| 	void RemoveCallback(HookType_t type, HookHandlerFn* pFunc); | ||||
| 	 | ||||
| 	/*
 | ||||
| 	Checks if a hook handler is already added. | ||||
| 
 | ||||
| 	@param type The hook type. | ||||
| 	@param pFunc The hook handler that should be checked. | ||||
| 	*/ | ||||
| 	bool IsCallbackRegistered(HookType_t type, HookHandlerFn* pFunc); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	Checks if there are any hook handlers added to this hook. | ||||
| 	*/ | ||||
| 	bool AreCallbacksRegistered(); | ||||
| 
 | ||||
| 	template<class T> | ||||
| 	T GetArgument(int iIndex) | ||||
| 	{ | ||||
| 		return *(T *) m_pCallingConvention->GetArgumentPtr(iIndex, m_pRegisters); | ||||
| 	} | ||||
| 
 | ||||
| 	template<class T> | ||||
| 	void SetArgument(int iIndex, T value) | ||||
| 	{ | ||||
| 		void* pPtr = m_pCallingConvention->GetArgumentPtr(iIndex, m_pRegisters); | ||||
| 		*(T *) pPtr = value; | ||||
| 		m_pCallingConvention->ArgumentPtrChanged(iIndex, m_pRegisters, pPtr); | ||||
| 	} | ||||
| 
 | ||||
| 	template<class T> | ||||
| 	T GetReturnValue() | ||||
| 	{ | ||||
| 		return *(T *)  m_pCallingConvention->GetReturnPtr(m_pRegisters); | ||||
| 	} | ||||
| 
 | ||||
| 	template<class T> | ||||
| 	void SetReturnValue(T value) | ||||
| 	{ | ||||
| 		void* pPtr = m_pCallingConvention->GetReturnPtr(m_pRegisters); | ||||
| 		*(T *)  pPtr = value; | ||||
| 		m_pCallingConvention->ReturnPtrChanged(m_pRegisters, pPtr); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	void* CreateBridge(); | ||||
| 
 | ||||
| 	void Write_ModifyReturnAddress(asmjit::X86Assembler& a); | ||||
| 	void Write_CallHandler(asmjit::X86Assembler& a, HookType_t type); | ||||
| 	void Write_SaveRegisters(asmjit::X86Assembler& a); | ||||
| 	void Write_RestoreRegisters(asmjit::X86Assembler& a); | ||||
| 
 | ||||
| 	void* CreatePostCallback(); | ||||
| 
 | ||||
| 	bool __cdecl HookHandler(HookType_t type); | ||||
| 
 | ||||
| 	void* __cdecl GetReturnAddress(void* pESP); | ||||
| 	void __cdecl SetReturnAddress(void* pRetAddr, void* pESP); | ||||
| 
 | ||||
| public: | ||||
| 	std::map<HookType_t, std::list<HookHandlerFn*> > m_hookHandler; | ||||
| 
 | ||||
| 	// Address of the original function
 | ||||
| 	void* m_pFunc; | ||||
| 
 | ||||
| 	asmjit::JitRuntime m_Runtime; | ||||
| 
 | ||||
| 	ICallingConvention* m_pCallingConvention; | ||||
| 
 | ||||
| 	// Address of the bridge
 | ||||
| 	void* m_pBridge; | ||||
| 
 | ||||
| 	// Address of the trampoline
 | ||||
| 	void* m_pTrampoline; | ||||
| 
 | ||||
| 	// Register storage
 | ||||
| 	CRegisters* m_pRegisters; | ||||
| 
 | ||||
| 	// New return address
 | ||||
| 	void* m_pNewRetAddr; | ||||
| 
 | ||||
| 	std::map<void*, void*> m_RetAddr; | ||||
| }; | ||||
| 
 | ||||
| #endif // _HOOK_H
 | ||||
							
								
								
									
										97
									
								
								DynamicHooks/manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								DynamicHooks/manager.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,97 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include "manager.h" | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> CHookManager
 | ||||
| // ============================================================================
 | ||||
| CHook* CHookManager::HookFunction(void* pFunc, ICallingConvention* pConvention) | ||||
| { | ||||
| 	if (!pFunc) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	CHook* pHook = FindHook(pFunc); | ||||
| 	if (pHook) | ||||
| 	{ | ||||
| 		delete pConvention; | ||||
| 		return pHook; | ||||
| 	} | ||||
| 	 | ||||
| 	pHook = new CHook(pFunc, pConvention); | ||||
| 	m_Hooks.push_back(pHook); | ||||
| 	return pHook; | ||||
| } | ||||
| 
 | ||||
| void CHookManager::UnhookFunction(void* pFunc) | ||||
| { | ||||
| 	CHook* pHook = FindHook(pFunc); | ||||
| 	if (pHook) | ||||
| 	{ | ||||
| 		m_Hooks.remove(pHook); | ||||
| 		delete pHook; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| CHook* CHookManager::FindHook(void* pFunc) | ||||
| { | ||||
| 	if (!pFunc) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	for(std::list<CHook *>::iterator it=m_Hooks.begin(); it != m_Hooks.end(); it++) | ||||
| 	{ | ||||
| 		CHook* pHook = *it; | ||||
| 		if (pHook->m_pFunc == pFunc) | ||||
| 			return pHook; | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| void CHookManager::UnhookAllFunctions() | ||||
| { | ||||
| 	for(std::list<CHook *>::iterator it=m_Hooks.begin(); it != m_Hooks.end(); it++) | ||||
| 		delete *it; | ||||
| 
 | ||||
| 	m_Hooks.clear(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> GetHookManager
 | ||||
| // ============================================================================
 | ||||
| CHookManager* GetHookManager() | ||||
| { | ||||
| 	static CHookManager* s_pManager = new CHookManager; | ||||
| 	return s_pManager; | ||||
| } | ||||
							
								
								
									
										83
									
								
								DynamicHooks/manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								DynamicHooks/manager.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,83 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| #ifndef _MANAGER_H | ||||
| #define _MANAGER_H | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include <list> | ||||
| #include "hook.h" | ||||
| #include "convention.h" | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> CHookManager
 | ||||
| // ============================================================================
 | ||||
| class CHookManager | ||||
| { | ||||
| public: | ||||
| 	/*
 | ||||
| 	Hooks the given function and returns a new CHook instance. If the | ||||
| 	function was already hooked, the existing CHook instance will be | ||||
| 	returned. | ||||
| 	*/ | ||||
|     CHook* HookFunction(void* pFunc, ICallingConvention* pConvention); | ||||
| 	 | ||||
| 	/*
 | ||||
| 	Removes all callbacks and restores the original function. | ||||
| 	*/ | ||||
|     void UnhookFunction(void* pFunc); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	Returns either NULL or the found CHook instance. | ||||
| 	*/ | ||||
| 	CHook* FindHook(void* pFunc); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	Removes all callbacks and restores all functions. | ||||
| 	*/ | ||||
| 	void UnhookAllFunctions(); | ||||
| 
 | ||||
| public: | ||||
| 	std::list<CHook *> m_Hooks; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> GetHookManager
 | ||||
| // ============================================================================
 | ||||
| /*
 | ||||
| Returns a pointer to a static CHookManager object. | ||||
| */ | ||||
| CHookManager* GetHookManager(); | ||||
| 
 | ||||
| #endif // _MANAGER_H
 | ||||
							
								
								
									
										381
									
								
								DynamicHooks/registers.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										381
									
								
								DynamicHooks/registers.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,381 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| #include "registers.h" | ||||
| 
 | ||||
| CRegisters::CRegisters(std::list<Register_t> registers) | ||||
| {	 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 8-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	m_al = CreateRegister(registers, AL, 1); | ||||
| 	m_cl = CreateRegister(registers, CL, 1); | ||||
| 	m_dl = CreateRegister(registers, DL, 1); | ||||
| 	m_bl = CreateRegister(registers, BL, 1); | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	m_spl = CreateRegister(registers, SPL, 1); | ||||
| 	m_bpl = CreateRegister(registers, BPL, 1); | ||||
| 	m_sil = CreateRegister(registers, SIL, 1); | ||||
| 	m_dil = CreateRegister(registers, DIL, 1); | ||||
| 	m_r8b = CreateRegister(registers, R8B, 1); | ||||
| 	m_r9b = CreateRegister(registers, R9B, 1); | ||||
| 	m_r10b = CreateRegister(registers, R10B, 1); | ||||
| 	m_r11b = CreateRegister(registers, R11B, 1); | ||||
| 	m_r12b = CreateRegister(registers, R12B, 1); | ||||
| 	m_r13b = CreateRegister(registers, R13B, 1); | ||||
| 	m_r14b = CreateRegister(registers, R14B, 1); | ||||
| 	m_r15b = CreateRegister(registers, R15B, 1); | ||||
| 	*/ | ||||
| 
 | ||||
| 	m_ah = CreateRegister(registers, AH, 1); | ||||
| 	m_ch = CreateRegister(registers, CH, 1); | ||||
| 	m_dh = CreateRegister(registers, DH, 1); | ||||
| 	m_bh = CreateRegister(registers, BH, 1); | ||||
| 	 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 16-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	m_ax = CreateRegister(registers, AX, 2); | ||||
| 	m_cx = CreateRegister(registers, CX, 2); | ||||
| 	m_dx = CreateRegister(registers, DX, 2); | ||||
| 	m_bx = CreateRegister(registers, BX, 2); | ||||
| 	m_sp = CreateRegister(registers, SP, 2); | ||||
| 	m_bp = CreateRegister(registers, BP, 2); | ||||
| 	m_si = CreateRegister(registers, SI, 2); | ||||
| 	m_di = CreateRegister(registers, DI, 2); | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	m_r8w = CreateRegister(registers, R8W, 2); | ||||
| 	m_r9w = CreateRegister(registers, R9W, 2); | ||||
| 	m_r10w = CreateRegister(registers, R10W, 2); | ||||
| 	m_r11w = CreateRegister(registers, R11W, 2); | ||||
| 	m_r12w = CreateRegister(registers, R12W, 2); | ||||
| 	m_r13w = CreateRegister(registers, R13W, 2); | ||||
| 	m_r14w = CreateRegister(registers, R14W, 2); | ||||
| 	m_r15w = CreateRegister(registers, R14W, 2); | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 32-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	m_eax = CreateRegister(registers, EAX, 4); | ||||
| 	m_ecx = CreateRegister(registers, ECX, 4); | ||||
| 	m_edx = CreateRegister(registers, EDX, 4); | ||||
| 	m_ebx = CreateRegister(registers, EBX, 4); | ||||
| 	m_esp = CreateRegister(registers, ESP, 4); | ||||
| 	m_ebp = CreateRegister(registers, EBP, 4); | ||||
| 	m_esi = CreateRegister(registers, ESI, 4); | ||||
| 	m_edi = CreateRegister(registers, EDI, 4); | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	m_r8d = CreateRegister(registers, R8D, 4); | ||||
| 	m_r9d = CreateRegister(registers, R9D, 4); | ||||
| 	m_r10d = CreateRegister(registers, R10D, 4); | ||||
| 	m_r11d = CreateRegister(registers, R11D, 4); | ||||
| 	m_r12d = CreateRegister(registers, R12D, 4); | ||||
| 	m_r13d = CreateRegister(registers, R13D, 4); | ||||
| 	m_r14d = CreateRegister(registers, R14D, 4); | ||||
| 	m_r15d = CreateRegister(registers, R15D, 4); | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 64-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	m_rax = CreateRegister(registers, RAX, 8); | ||||
| 	m_rcx = CreateRegister(registers, RCX, 8); | ||||
| 	m_rdx = CreateRegister(registers, RDX, 8); | ||||
| 	m_rbx = CreateRegister(registers, RBX, 8); | ||||
| 	m_rsp = CreateRegister(registers, RSP, 8); | ||||
| 	m_rbp = CreateRegister(registers, RBP, 8); | ||||
| 	m_rsi = CreateRegister(registers, RSI, 8); | ||||
| 	m_rdi = CreateRegister(registers, RDI, 8); | ||||
| 	*/ | ||||
| 	 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	m_r8 = CreateRegister(registers, R8, 8); | ||||
| 	m_r9 = CreateRegister(registers, R9, 8); | ||||
| 	m_r10 = CreateRegister(registers, R10, 8); | ||||
| 	m_r11 = CreateRegister(registers, R11, 8); | ||||
| 	m_r12 = CreateRegister(registers, R12, 8); | ||||
| 	m_r13 = CreateRegister(registers, R13, 8); | ||||
| 	m_r14 = CreateRegister(registers, R14, 8); | ||||
| 	m_r15 = CreateRegister(registers, R15, 8); | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 64-bit MM (MMX) registers
 | ||||
| 	// ========================================================================
 | ||||
| 	m_mm0 = CreateRegister(registers, MM0, 8); | ||||
| 	m_mm1 = CreateRegister(registers, MM1, 8); | ||||
| 	m_mm2 = CreateRegister(registers, MM2, 8); | ||||
| 	m_mm3 = CreateRegister(registers, MM3, 8); | ||||
| 	m_mm4 = CreateRegister(registers, MM4, 8); | ||||
| 	m_mm5 = CreateRegister(registers, MM5, 8); | ||||
| 	m_mm6 = CreateRegister(registers, MM6, 8); | ||||
| 	m_mm7 = CreateRegister(registers, MM7, 8); | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 128-bit XMM registers
 | ||||
| 	// ========================================================================
 | ||||
| 	m_xmm0 = CreateRegister(registers, XMM0, 16); | ||||
| 	m_xmm1 = CreateRegister(registers, XMM1, 16); | ||||
| 	m_xmm2 = CreateRegister(registers, XMM2, 16); | ||||
| 	m_xmm3 = CreateRegister(registers, XMM3, 16); | ||||
| 	m_xmm4 = CreateRegister(registers, XMM4, 16); | ||||
| 	m_xmm5 = CreateRegister(registers, XMM5, 16); | ||||
| 	m_xmm6 = CreateRegister(registers, XMM6, 16); | ||||
| 	m_xmm7 = CreateRegister(registers, XMM7, 16); | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	m_xmm8 = CreateRegister(registers, XMM8, 16); | ||||
| 	m_xmm9 = CreateRegister(registers, XMM9, 16); | ||||
| 	m_xmm10 = CreateRegister(registers, XMM10, 16); | ||||
| 	m_xmm11 = CreateRegister(registers, XMM11, 16); | ||||
| 	m_xmm12 = CreateRegister(registers, XMM12, 16); | ||||
| 	m_xmm13 = CreateRegister(registers, XMM13, 16); | ||||
| 	m_xmm14 = CreateRegister(registers, XMM14, 16); | ||||
| 	m_xmm15 = CreateRegister(registers, XMM15, 16); | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 16-bit Segment registers
 | ||||
| 	// ========================================================================
 | ||||
| 	m_cs = CreateRegister(registers, CS, 2); | ||||
| 	m_ss = CreateRegister(registers, SS, 2); | ||||
| 	m_ds = CreateRegister(registers, DS, 2); | ||||
| 	m_es = CreateRegister(registers, ES, 2); | ||||
| 	m_fs = CreateRegister(registers, FS, 2); | ||||
| 	m_gs = CreateRegister(registers, GS, 2); | ||||
| 	 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 80-bit FPU registers
 | ||||
| 	// ========================================================================
 | ||||
| 	m_st0 = CreateRegister(registers, ST0, 10); | ||||
| 	m_st1 = CreateRegister(registers, ST1, 10); | ||||
| 	m_st2 = CreateRegister(registers, ST2, 10); | ||||
| 	m_st3 = CreateRegister(registers, ST3, 10); | ||||
| 	m_st4 = CreateRegister(registers, ST4, 10); | ||||
| 	m_st5 = CreateRegister(registers, ST5, 10); | ||||
| 	m_st6 = CreateRegister(registers, ST6, 10); | ||||
| 	m_st7 = CreateRegister(registers, ST7, 10); | ||||
| } | ||||
| 
 | ||||
| CRegisters::~CRegisters() | ||||
| { | ||||
| 	// ========================================================================
 | ||||
| 	// >> 8-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	DeleteRegister(m_al); | ||||
| 	DeleteRegister(m_cl); | ||||
| 	DeleteRegister(m_dl); | ||||
| 	DeleteRegister(m_bl); | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	DeleteRegister(m_spl); | ||||
| 	DeleteRegister(m_bpl); | ||||
| 	DeleteRegister(m_sil); | ||||
| 	DeleteRegister(m_dil); | ||||
| 	DeleteRegister(m_r8b); | ||||
| 	DeleteRegister(m_r9b); | ||||
| 	DeleteRegister(m_r10b); | ||||
| 	DeleteRegister(m_r11b); | ||||
| 	DeleteRegister(m_r12b); | ||||
| 	DeleteRegister(m_r13b); | ||||
| 	DeleteRegister(m_r14b); | ||||
| 	DeleteRegister(m_r15b); | ||||
| 	*/ | ||||
| 
 | ||||
| 	DeleteRegister(m_ah); | ||||
| 	DeleteRegister(m_ch); | ||||
| 	DeleteRegister(m_dh); | ||||
| 	DeleteRegister(m_bh); | ||||
| 	 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 16-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	DeleteRegister(m_ax); | ||||
| 	DeleteRegister(m_cx); | ||||
| 	DeleteRegister(m_dx); | ||||
| 	DeleteRegister(m_bx); | ||||
| 	DeleteRegister(m_sp); | ||||
| 	DeleteRegister(m_bp); | ||||
| 	DeleteRegister(m_si); | ||||
| 	DeleteRegister(m_di); | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	DeleteRegister(m_r8w); | ||||
| 	DeleteRegister(m_r9w); | ||||
| 	DeleteRegister(m_r10w); | ||||
| 	DeleteRegister(m_r11w); | ||||
| 	DeleteRegister(m_r12w); | ||||
| 	DeleteRegister(m_r13w); | ||||
| 	DeleteRegister(m_r14w); | ||||
| 	DeleteRegister(m_r15w); | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 32-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	DeleteRegister(m_eax); | ||||
| 	DeleteRegister(m_ecx); | ||||
| 	DeleteRegister(m_edx); | ||||
| 	DeleteRegister(m_ebx); | ||||
| 	DeleteRegister(m_esp); | ||||
| 	DeleteRegister(m_ebp); | ||||
| 	DeleteRegister(m_esi); | ||||
| 	DeleteRegister(m_edi); | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	DeleteRegister(m_r8d); | ||||
| 	DeleteRegister(m_r9d); | ||||
| 	DeleteRegister(m_r10d); | ||||
| 	DeleteRegister(m_r11d); | ||||
| 	DeleteRegister(m_r12d); | ||||
| 	DeleteRegister(m_r13d); | ||||
| 	DeleteRegister(m_r14d); | ||||
| 	DeleteRegister(m_r15d); | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 64-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	DeleteRegister(m_rax); | ||||
| 	DeleteRegister(m_rcx); | ||||
| 	DeleteRegister(m_rdx); | ||||
| 	DeleteRegister(m_rbx); | ||||
| 	DeleteRegister(m_rsp); | ||||
| 	DeleteRegister(m_rbp); | ||||
| 	DeleteRegister(m_rsi); | ||||
| 	DeleteRegister(m_rdi); | ||||
| 	*/ | ||||
| 	 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	DeleteRegister(m_r8); | ||||
| 	DeleteRegister(m_r9); | ||||
| 	DeleteRegister(m_r10); | ||||
| 	DeleteRegister(m_r11); | ||||
| 	DeleteRegister(m_r12); | ||||
| 	DeleteRegister(m_r13); | ||||
| 	DeleteRegister(m_r14); | ||||
| 	DeleteRegister(m_r15); | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 64-bit MM (MMX) registers
 | ||||
| 	// ========================================================================
 | ||||
| 	DeleteRegister(m_mm0); | ||||
| 	DeleteRegister(m_mm1); | ||||
| 	DeleteRegister(m_mm2); | ||||
| 	DeleteRegister(m_mm3); | ||||
| 	DeleteRegister(m_mm4); | ||||
| 	DeleteRegister(m_mm5); | ||||
| 	DeleteRegister(m_mm6); | ||||
| 	DeleteRegister(m_mm7); | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 128-bit XMM registers
 | ||||
| 	// ========================================================================
 | ||||
| 	DeleteRegister(m_xmm0); | ||||
| 	DeleteRegister(m_xmm1); | ||||
| 	DeleteRegister(m_xmm2); | ||||
| 	DeleteRegister(m_xmm3); | ||||
| 	DeleteRegister(m_xmm4); | ||||
| 	DeleteRegister(m_xmm5); | ||||
| 	DeleteRegister(m_xmm6); | ||||
| 	DeleteRegister(m_xmm7); | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	DeleteRegister(m_xmm8); | ||||
| 	DeleteRegister(m_xmm9); | ||||
| 	DeleteRegister(m_xmm10); | ||||
| 	DeleteRegister(m_xmm11); | ||||
| 	DeleteRegister(m_xmm12); | ||||
| 	DeleteRegister(m_xmm13); | ||||
| 	DeleteRegister(m_xmm14); | ||||
| 	DeleteRegister(m_xmm15); | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 2-bit Segment registers
 | ||||
| 	// ========================================================================
 | ||||
| 	DeleteRegister(m_cs); | ||||
| 	DeleteRegister(m_ss); | ||||
| 	DeleteRegister(m_ds); | ||||
| 	DeleteRegister(m_es); | ||||
| 	DeleteRegister(m_fs); | ||||
| 	DeleteRegister(m_gs); | ||||
| 	 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 80-bit FPU registers
 | ||||
| 	// ========================================================================
 | ||||
| 	DeleteRegister(m_st0); | ||||
| 	DeleteRegister(m_st1); | ||||
| 	DeleteRegister(m_st2); | ||||
| 	DeleteRegister(m_st3); | ||||
| 	DeleteRegister(m_st4); | ||||
| 	DeleteRegister(m_st5); | ||||
| 	DeleteRegister(m_st6); | ||||
| 	DeleteRegister(m_st7); | ||||
| } | ||||
| 
 | ||||
| CRegister* CRegisters::CreateRegister(std::list<Register_t>& registers, Register_t reg, int iSize) | ||||
| { | ||||
| 	for(std::list<Register_t>::iterator it=registers.begin(); it != registers.end(); it++) | ||||
| 	{ | ||||
| 		if ((*it) == reg) | ||||
| 		{ | ||||
| 			return new CRegister(iSize); | ||||
| 		} | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| void CRegisters::DeleteRegister(CRegister* pRegister) | ||||
| { | ||||
| 	if (pRegister) | ||||
| 	{ | ||||
| 		delete pRegister; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										435
									
								
								DynamicHooks/registers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										435
									
								
								DynamicHooks/registers.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,435 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| #ifndef _REGISTERS_H | ||||
| #define _REGISTERS_H | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #include <stdlib.h> | ||||
| #include <list> | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> Register_t
 | ||||
| // ============================================================================
 | ||||
| enum Register_t | ||||
| { | ||||
| 	// ========================================================================
 | ||||
| 	// >> 8-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	AL, | ||||
| 	CL, | ||||
| 	DL, | ||||
| 	BL, | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	SPL, | ||||
| 	BPL, | ||||
| 	SIL, | ||||
| 	DIL, | ||||
| 	R8B, | ||||
| 	R9B, | ||||
| 	R10B, | ||||
| 	R11B, | ||||
| 	R12B, | ||||
| 	R13B, | ||||
| 	R14B, | ||||
| 	R15B, | ||||
| 	*/ | ||||
| 
 | ||||
| 	AH, | ||||
| 	CH, | ||||
| 	DH, | ||||
| 	BH, | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 16-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	AX, | ||||
| 	CX, | ||||
| 	DX, | ||||
| 	BX, | ||||
| 	SP, | ||||
| 	BP, | ||||
| 	SI, | ||||
| 	DI, | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	R8W, | ||||
| 	R9W, | ||||
| 	R10W, | ||||
| 	R11W, | ||||
| 	R12W, | ||||
| 	R13W, | ||||
| 	R14W, | ||||
| 	R15W, | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 32-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	EAX, | ||||
| 	ECX, | ||||
| 	EDX, | ||||
| 	EBX, | ||||
| 	ESP, | ||||
| 	EBP, | ||||
| 	ESI, | ||||
| 	EDI, | ||||
| 	 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	R8D, | ||||
| 	R9D, | ||||
| 	R10D, | ||||
| 	R11D, | ||||
| 	R12D, | ||||
| 	R13D, | ||||
| 	R14D, | ||||
| 	R15D, | ||||
| 	*/ | ||||
| 	 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 64-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	RAX, | ||||
| 	RCX, | ||||
| 	RDX, | ||||
| 	RBX, | ||||
| 	RSP, | ||||
| 	RBP, | ||||
| 	RSI, | ||||
| 	RDI, | ||||
| 	*/ | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	R8, | ||||
| 	R9, | ||||
| 	R10, | ||||
| 	R11, | ||||
| 	R12, | ||||
| 	R13, | ||||
| 	R14, | ||||
| 	R15, | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 64-bit MM (MMX) registers
 | ||||
| 	// ========================================================================
 | ||||
| 	MM0, | ||||
| 	MM1, | ||||
| 	MM2, | ||||
| 	MM3, | ||||
| 	MM4, | ||||
| 	MM5, | ||||
| 	MM6, | ||||
| 	MM7, | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 128-bit XMM registers
 | ||||
| 	// ========================================================================
 | ||||
| 	XMM0, | ||||
| 	XMM1, | ||||
| 	XMM2, | ||||
| 	XMM3, | ||||
| 	XMM4, | ||||
| 	XMM5, | ||||
| 	XMM6, | ||||
| 	XMM7, | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	XMM8, | ||||
| 	XMM9, | ||||
| 	XMM10, | ||||
| 	XMM11, | ||||
| 	XMM12, | ||||
| 	XMM13, | ||||
| 	XMM14, | ||||
| 	XMM15, | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 16-bit Segment registers
 | ||||
| 	// ========================================================================
 | ||||
| 	CS, | ||||
| 	SS, | ||||
| 	DS, | ||||
| 	ES, | ||||
| 	FS, | ||||
| 	GS, | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 80-bit FPU registers
 | ||||
| 	// ========================================================================
 | ||||
| 	ST0, | ||||
| 	ST1, | ||||
| 	ST2, | ||||
| 	ST3, | ||||
| 	ST4, | ||||
| 	ST5, | ||||
| 	ST6, | ||||
| 	ST7, | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> CRegister
 | ||||
| // ============================================================================
 | ||||
| class CRegister | ||||
| { | ||||
| public: | ||||
| 	CRegister(int iSize) | ||||
| 	{ | ||||
| 		m_iSize = iSize; | ||||
| 		m_pAddress = malloc(iSize); | ||||
| 	} | ||||
| 
 | ||||
| 	~CRegister() | ||||
| 	{ | ||||
| 		free(m_pAddress); | ||||
| 	} | ||||
| 
 | ||||
| 	template<class T> | ||||
| 	T GetValue() | ||||
| 	{ | ||||
| 		return *(T *) m_pAddress; | ||||
| 	} | ||||
| 
 | ||||
| 	template<class T> | ||||
| 	T GetPointerValue(int iOffset=0) | ||||
| 	{ | ||||
| 		return *(T *) (GetValue<unsigned long>() + iOffset); | ||||
| 	} | ||||
| 
 | ||||
| 	template<class T> | ||||
| 	void SetValue(T value) | ||||
| 	{ | ||||
| 		*(T *) m_pAddress = value; | ||||
| 	} | ||||
| 
 | ||||
| 	template<class T> | ||||
| 	void SetPointerValue(T value, int iOffset=0) | ||||
| 	{ | ||||
| 		*(T *) (GetValue<unsigned long>() + iOffset) = value; | ||||
| 	} | ||||
| 
 | ||||
| public: | ||||
| 	int m_iSize; | ||||
| 	void* m_pAddress; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> CRegisters
 | ||||
| // ============================================================================
 | ||||
| class CRegisters | ||||
| { | ||||
| public: | ||||
| 	CRegisters(std::list<Register_t> registers); | ||||
| 	~CRegisters(); | ||||
| 
 | ||||
| private: | ||||
| 	CRegister* CreateRegister(std::list<Register_t>& registers, Register_t reg, int iSize); | ||||
| 	void DeleteRegister(CRegister* pRegister); | ||||
| 
 | ||||
| public: | ||||
| 	// ========================================================================
 | ||||
| 	// >> 8-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	CRegister* m_al; | ||||
| 	CRegister* m_cl; | ||||
| 	CRegister* m_dl; | ||||
| 	CRegister* m_bl; | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	CRegister* m_spl; | ||||
| 	CRegister* m_bpl; | ||||
| 	CRegister* m_sil; | ||||
| 	CRegister* m_dil; | ||||
| 	CRegister* m_r8b; | ||||
| 	CRegister* m_r9b; | ||||
| 	CRegister* m_r10b; | ||||
| 	CRegister* m_r11b; | ||||
| 	CRegister* m_r12b; | ||||
| 	CRegister* m_r13b; | ||||
| 	CRegister* m_r14b; | ||||
| 	CRegister* m_r15b; | ||||
| 	*/ | ||||
| 
 | ||||
| 	CRegister* m_ah; | ||||
| 	CRegister* m_ch; | ||||
| 	CRegister* m_dh; | ||||
| 	CRegister* m_bh; | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 16-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	CRegister* m_ax; | ||||
| 	CRegister* m_cx; | ||||
| 	CRegister* m_dx; | ||||
| 	CRegister* m_bx; | ||||
| 	CRegister* m_sp; | ||||
| 	CRegister* m_bp; | ||||
| 	CRegister* m_si; | ||||
| 	CRegister* m_di; | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	CRegister* m_r8w; | ||||
| 	CRegister* m_r9w; | ||||
| 	CRegister* m_r10w; | ||||
| 	CRegister* m_r11w; | ||||
| 	CRegister* m_r12w; | ||||
| 	CRegister* m_r13w; | ||||
| 	CRegister* m_r14w; | ||||
| 	CRegister* m_r15w; | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 32-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	CRegister* m_eax; | ||||
| 	CRegister* m_ecx; | ||||
| 	CRegister* m_edx; | ||||
| 	CRegister* m_ebx; | ||||
| 	CRegister* m_esp; | ||||
| 	CRegister* m_ebp; | ||||
| 	CRegister* m_esi; | ||||
| 	CRegister* m_edi; | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	CRegister* m_r8d; | ||||
| 	CRegister* m_r9d; | ||||
| 	CRegister* m_r10d; | ||||
| 	CRegister* m_r11d; | ||||
| 	CRegister* m_r12d; | ||||
| 	CRegister* m_r13d; | ||||
| 	CRegister* m_r14d; | ||||
| 	CRegister* m_r15d; | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 64-bit General purpose registers
 | ||||
| 	// ========================================================================
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	CRegister* m_rax; | ||||
| 	CRegister* m_rcx; | ||||
| 	CRegister* m_rdx; | ||||
| 	CRegister* m_rbx; | ||||
| 	CRegister* m_rsp; | ||||
| 	CRegister* m_rbp; | ||||
| 	CRegister* m_rsi; | ||||
| 	CRegister* m_rdi; | ||||
| 	*/ | ||||
| 	 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	CRegister* m_r8; | ||||
| 	CRegister* m_r9; | ||||
| 	CRegister* m_r10; | ||||
| 	CRegister* m_r11; | ||||
| 	CRegister* m_r12; | ||||
| 	CRegister* m_r13; | ||||
| 	CRegister* m_r14; | ||||
| 	CRegister* m_r15; | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 64-bit MM (MMX) registers
 | ||||
| 	// ========================================================================
 | ||||
| 	CRegister* m_mm0; | ||||
| 	CRegister* m_mm1; | ||||
| 	CRegister* m_mm2; | ||||
| 	CRegister* m_mm3; | ||||
| 	CRegister* m_mm4; | ||||
| 	CRegister* m_mm5; | ||||
| 	CRegister* m_mm6; | ||||
| 	CRegister* m_mm7; | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 128-bit XMM registers
 | ||||
| 	// ========================================================================
 | ||||
| 	CRegister* m_xmm0; | ||||
| 	CRegister* m_xmm1; | ||||
| 	CRegister* m_xmm2; | ||||
| 	CRegister* m_xmm3; | ||||
| 	CRegister* m_xmm4; | ||||
| 	CRegister* m_xmm5; | ||||
| 	CRegister* m_xmm6; | ||||
| 	CRegister* m_xmm7; | ||||
| 
 | ||||
| 	// 64-bit mode only
 | ||||
| 	/*
 | ||||
| 	CRegister* m_xmm8; | ||||
| 	CRegister* m_xmm9; | ||||
| 	CRegister* m_xmm10; | ||||
| 	CRegister* m_xmm11; | ||||
| 	CRegister* m_xmm12; | ||||
| 	CRegister* m_xmm13; | ||||
| 	CRegister* m_xmm14; | ||||
| 	CRegister* m_xmm15; | ||||
| 	*/ | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 16-bit Segment registers
 | ||||
| 	// ========================================================================
 | ||||
| 	CRegister* m_cs; | ||||
| 	CRegister* m_ss; | ||||
| 	CRegister* m_ds; | ||||
| 	CRegister* m_es; | ||||
| 	CRegister* m_fs; | ||||
| 	CRegister* m_gs; | ||||
| 
 | ||||
| 	// ========================================================================
 | ||||
| 	// >> 80-bit FPU registers
 | ||||
| 	// ========================================================================
 | ||||
| 	CRegister* m_st0; | ||||
| 	CRegister* m_st1; | ||||
| 	CRegister* m_st2; | ||||
| 	CRegister* m_st3; | ||||
| 	CRegister* m_st4; | ||||
| 	CRegister* m_st5; | ||||
| 	CRegister* m_st6; | ||||
| 	CRegister* m_st7; | ||||
| }; | ||||
| 
 | ||||
| #endif // _REGISTERS_H
 | ||||
							
								
								
									
										76
									
								
								DynamicHooks/thirdparty/AsmJit/apibegin.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								DynamicHooks/thirdparty/AsmJit/apibegin.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,76 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #if !defined(_ASMJIT_BUILD_H) | ||||
| #include "./build.h" | ||||
| #endif // !_ASMJIT_BUILD_H
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #if !defined(ASMJIT_API_SCOPE) | ||||
| # define ASMJIT_API_SCOPE | ||||
| #else | ||||
| # error "[asmjit] Api-Scope is already active, previous scope not closed by apiend.h?" | ||||
| #endif // ASMJIT_API_SCOPE
 | ||||
| 
 | ||||
| // [NoExcept]
 | ||||
| #if !ASMJIT_CC_HAS_NOEXCEPT && !defined(noexcept) | ||||
| # define noexcept ASMJIT_NOEXCEPT | ||||
| # define ASMJIT_UNDEF_NOEXCEPT | ||||
| #endif // !ASMJIT_CC_HAS_NOEXCEPT && !noexcept
 | ||||
| 
 | ||||
| // [NullPtr]
 | ||||
| #if !ASMJIT_CC_HAS_NULLPTR && !defined(nullptr) | ||||
| # define nullptr NULL | ||||
| # define ASMJIT_UNDEF_NULLPTR | ||||
| #endif // !ASMJIT_CC_HAS_NULLPTR && !nullptr
 | ||||
| 
 | ||||
| // [Override]
 | ||||
| #if !ASMJIT_CC_HAS_OVERRIDE && !defined(override) | ||||
| # define override | ||||
| # define ASMJIT_UNDEF_OVERRIDE | ||||
| #endif // !ASMJIT_CC_HAS_OVERRIDE && !override
 | ||||
| 
 | ||||
| // [CLang]
 | ||||
| #if ASMJIT_CC_CLANG | ||||
| # pragma clang diagnostic push | ||||
| # pragma clang diagnostic ignored "-Wunnamed-type-template-args" | ||||
| #endif // ASMJIT_CC_CLANG
 | ||||
| 
 | ||||
| // [GCC]
 | ||||
| #if ASMJIT_CC_GCC | ||||
| # pragma GCC diagnostic push | ||||
| # pragma GCC diagnostic warning "-Winline" | ||||
| #endif // ASMJIT_CC_GCC
 | ||||
| 
 | ||||
| // [MSC]
 | ||||
| #if ASMJIT_CC_MSC | ||||
| 
 | ||||
| # pragma warning(push) | ||||
| # pragma warning(disable: 4127) // conditional expression is constant
 | ||||
| # pragma warning(disable: 4201) // nameless struct/union
 | ||||
| # pragma warning(disable: 4244) // '+=' : conversion from 'int' to 'x', possible
 | ||||
|                                 // loss of data
 | ||||
| # pragma warning(disable: 4251) // struct needs to have dll-interface to be used
 | ||||
|                                 // by clients of struct ...
 | ||||
| # pragma warning(disable: 4275) // non dll-interface struct ... used as base for
 | ||||
|                                 // dll-interface struct
 | ||||
| # pragma warning(disable: 4355) // this used in base member initializer list
 | ||||
| # pragma warning(disable: 4480) // specifying underlying type for enum
 | ||||
| # pragma warning(disable: 4800) // forcing value to bool 'true' or 'false'
 | ||||
| 
 | ||||
| // TODO: Check if these defines are needed and for which version of MSC. There are
 | ||||
| // news about these as they are part of C99.
 | ||||
| # if !defined(vsnprintf) | ||||
| #  define ASMJIT_UNDEF_VSNPRINTF | ||||
| #  define vsnprintf _vsnprintf | ||||
| # endif // !vsnprintf
 | ||||
| # if !defined(snprintf) | ||||
| #  define ASMJIT_UNDEF_SNPRINTF | ||||
| #  define snprintf _snprintf | ||||
| # endif // !snprintf
 | ||||
| 
 | ||||
| #endif // ASMJIT_CC_MSC
 | ||||
							
								
								
									
										53
									
								
								DynamicHooks/thirdparty/AsmJit/apiend.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								DynamicHooks/thirdparty/AsmJit/apiend.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #if defined(ASMJIT_API_SCOPE) | ||||
| # undef ASMJIT_API_SCOPE | ||||
| #else | ||||
| # error "[asmjit] Api-Scope not active, forgot to include apibegin.h?" | ||||
| #endif // ASMJIT_API_SCOPE
 | ||||
| 
 | ||||
| // [NoExcept]
 | ||||
| #if defined(ASMJIT_UNDEF_NOEXCEPT) | ||||
| # undef noexcept | ||||
| # undef ASMJIT_UNDEF_NOEXCEPT | ||||
| #endif // ASMJIT_UNDEF_NOEXCEPT
 | ||||
| 
 | ||||
| // [NullPtr]
 | ||||
| #if defined(ASMJIT_UNDEF_NULLPTR) | ||||
| # undef nullptr | ||||
| # undef ASMJIT_UNDEF_NULLPTR | ||||
| #endif // ASMJIT_UNDEF_NULLPTR
 | ||||
| 
 | ||||
| // [Override]
 | ||||
| #if defined(ASMJIT_UNDEF_OVERRIDE) | ||||
| # undef override | ||||
| # undef ASMJIT_UNDEF_OVERRIDE | ||||
| #endif // ASMJIT_UNDEF_OVERRIDE
 | ||||
| 
 | ||||
| // [CLang]
 | ||||
| #if ASMJIT_CC_CLANG | ||||
| # pragma clang diagnostic pop | ||||
| #endif // ASMJIT_CC_CLANG
 | ||||
| 
 | ||||
| // [GCC]
 | ||||
| #if ASMJIT_CC_GCC | ||||
| # pragma GCC diagnostic pop | ||||
| #endif // ASMJIT_CC_GCC
 | ||||
| 
 | ||||
| // [MSC]
 | ||||
| #if ASMJIT_CC_MSC | ||||
| # pragma warning(pop) | ||||
| # if defined(ASMJIT_UNDEF_VSNPRINTF) | ||||
| #  undef vsnprintf | ||||
| #  undef ASMJIT_UNDEF_VSNPRINTF | ||||
| # endif // ASMJIT_UNDEF_VSNPRINTF
 | ||||
| # if defined(ASMJIT_UNDEF_SNPRINTF) | ||||
| #  undef snprintf | ||||
| #  undef ASMJIT_UNDEF_SNPRINTF | ||||
| # endif // ASMJIT_UNDEF_SNPRINTF
 | ||||
| #endif // ASMJIT_CC_MSC
 | ||||
							
								
								
									
										20
									
								
								DynamicHooks/thirdparty/AsmJit/arm.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								DynamicHooks/thirdparty/AsmJit/arm.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_ARM_H | ||||
| #define _ASMJIT_ARM_H | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "./base.h" | ||||
| 
 | ||||
| #include "./arm/armassembler.h" | ||||
| #include "./arm/armcompiler.h" | ||||
| #include "./arm/arminst.h" | ||||
| #include "./arm/armoperand.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_ARM_H
 | ||||
							
								
								
									
										360
									
								
								DynamicHooks/thirdparty/AsmJit/asmjit.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										360
									
								
								DynamicHooks/thirdparty/AsmJit/asmjit.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,360 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_ASMJIT_H | ||||
| #define _ASMJIT_ASMJIT_H | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit_mainpage]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! \mainpage
 | ||||
| //!
 | ||||
| //! AsmJit - Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //!
 | ||||
| //! A complete JIT and remote assembler for C++ language. It can generate native
 | ||||
| //! code for x86 and x64 architectures and supports the whole x86/x64 instruction
 | ||||
| //! set - from legacy MMX to the newest AVX2. It has a type-safe API that allows
 | ||||
| //! C++ compiler to do semantic checks at compile-time even before the assembled
 | ||||
| //! code is generated and executed.
 | ||||
| //!
 | ||||
| //! AsmJit is not a virtual machine (VM). It doesn't have functionality to
 | ||||
| //! implement VM out of the box; however, it can be be used as a JIT backend
 | ||||
| //! of your own VM. The usage of AsmJit is not limited at all; it's suitable
 | ||||
| //! for multimedia, VM backends, remote code generation, and many other tasks.
 | ||||
| //!
 | ||||
| //! \section AsmJit_Main_Concepts Code Generation Concepts
 | ||||
| //!
 | ||||
| //! AsmJit has two completely different code generation concepts. The difference
 | ||||
| //! is in how the code is generated. The first concept, also referred as a low
 | ||||
| //! level concept, is called `Assembler` and it's the same as writing RAW
 | ||||
| //! assembly by inserting instructions that use physical registers directly. In
 | ||||
| //! this case AsmJit does only instruction encoding, verification and final code
 | ||||
| //! relocation.
 | ||||
| //!
 | ||||
| //! The second concept, also referred as a high level concept, is called
 | ||||
| //! `Compiler`. Compiler lets you use virtually unlimited number of registers
 | ||||
| //! (it calls them variables), which significantly simplifies the code generation
 | ||||
| //! process. Compiler allocates these virtual registers to physical registers
 | ||||
| //! after the code generation is done. This requires some extra effort - Compiler
 | ||||
| //! has to generate information for each node (instruction, function declaration,
 | ||||
| //! function call, etc...) in the code, perform a variable liveness analysis and
 | ||||
| //! translate the code using variables to a code that uses only physical registers.
 | ||||
| //!
 | ||||
| //! In addition, Compiler understands functions and their calling conventions.
 | ||||
| //! It has been designed in a way that the code generated is always a function
 | ||||
| //! having a prototype like a real programming language. By having a function
 | ||||
| //! prototype the Compiler is able to insert prolog and epilog sequence to the
 | ||||
| //! function being generated and it's able to also generate a necessary code
 | ||||
| //! to call other function from your own code.
 | ||||
| //!
 | ||||
| //! There is no conclusion on which concept is better. `Assembler` brings full
 | ||||
| //! control and the best performance, while `Compiler` makes the code-generation
 | ||||
| //! more fun and more portable.
 | ||||
| //!
 | ||||
| //! \section AsmJit_Main_Sections Documentation Sections
 | ||||
| //!
 | ||||
| //! AsmJit documentation is structured into the following sections:
 | ||||
| //! - \ref asmjit_base "Base" - Base API (architecture independent).
 | ||||
| //! - \ref asmjit_x86 "X86/X64" - X86/X64 API.
 | ||||
| //!
 | ||||
| //! \section AsmJit_Main_HomePage AsmJit Homepage
 | ||||
| //!
 | ||||
| //! - https://github.com/kobalicek/asmjit
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit_base]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! \defgroup asmjit_base AsmJit Base API (architecture independent)
 | ||||
| //!
 | ||||
| //! \brief Base API.
 | ||||
| //!
 | ||||
| //! Base API contains all classes that are platform and architecture independent.
 | ||||
| //!
 | ||||
| //! Code-Generation and Operands
 | ||||
| //! ----------------------------
 | ||||
| //!
 | ||||
| //! List of the most useful code-generation and operand classes:
 | ||||
| //! - \ref asmjit::Assembler - Low-level code-generation.
 | ||||
| //! - \ref asmjit::ExternalTool - An external tool that can serialize to `Assembler`:
 | ||||
| //!   - \ref asmjit::Compiler - High-level code-generation.
 | ||||
| //! - \ref asmjit::Runtime - Describes where the code is stored and how it's executed:
 | ||||
| //!   - \ref asmjit::HostRuntime - Runtime that runs on the host machine:
 | ||||
| //!     - \ref asmjit::JitRuntime - Runtime designed for JIT code generation and execution.
 | ||||
| //!     - \ref asmjit::StaticRuntime - Runtime for code that starts at a specific address.
 | ||||
| //! - \ref asmjit::Stream - Stream is a list of \ref HLNode objects stored as a double
 | ||||
| //!   linked list:
 | ||||
| //!   - \ref asmjit::HLNode - Base node interface:
 | ||||
| //!     - \ref asmjit::HLInst - Instruction node.
 | ||||
| //!     - \ref asmjit::HLData - Data node.
 | ||||
| //!     - \ref asmjit::HLAlign - Align directive node.
 | ||||
| //!     - \ref asmjit::HLLabel - Label node.
 | ||||
| //!     - \ref asmjit::HLComment - Comment node.
 | ||||
| //!     - \ref asmjit::HLSentinel - Sentinel node.
 | ||||
| //!     - \ref asmjit::HLHint - Instruction node.
 | ||||
| //!     - \ref asmjit::HLFunc - Function declaration node.
 | ||||
| //!     - \ref asmjit::HLRet - Function return node.
 | ||||
| //!     - \ref asmjit::HLCall - Function call node.
 | ||||
| //!     - \ref asmjit::HLCallArg - Function call argument node.
 | ||||
| //! - \ref asmjit::Operand - base class for all operands:
 | ||||
| //!   - \ref asmjit::Reg - Register operand (`Assembler` only).
 | ||||
| //!   - \ref asmjit::Var - Variable operand (`Compiler` only).
 | ||||
| //!   - \ref asmjit::Mem - Memory operand.
 | ||||
| //!   - \ref asmjit::Imm - Immediate operand.
 | ||||
| //!   - \ref asmjit::Label - Label operand.
 | ||||
| //!
 | ||||
| //! The following snippet shows how to setup a basic JIT code generation:
 | ||||
| //!
 | ||||
| //! ~~~
 | ||||
| //! using namespace asmjit;
 | ||||
| //!
 | ||||
| //! int main(int argc, char* argv[]) {
 | ||||
| //!   // JIT runtime is designed for JIT code generation and execution.
 | ||||
| //!   JitRuntime runtime;
 | ||||
| //!
 | ||||
| //!   // Assembler instance requires to know the runtime to function.
 | ||||
| //!   X86Assembler a(&runtime);
 | ||||
| //!
 | ||||
| //!   // Compiler (if you indend to use it) requires an assembler instance.
 | ||||
| //!   X86Compiler c(&a);
 | ||||
| //!
 | ||||
| //!   return 0;
 | ||||
| //! }
 | ||||
| //! ~~~
 | ||||
| //!
 | ||||
| //! Logging and Error Handling
 | ||||
| //! --------------------------
 | ||||
| //!
 | ||||
| //! AsmJit contains a robust interface that can be used to log the generated code
 | ||||
| //! and to handle possible errors. Base logging interface is provided by \ref
 | ||||
| //! Logger, which is abstract and can be used as a base for your own logger.
 | ||||
| //! AsmJit also implements some trivial logging concepts out of the box to
 | ||||
| //! simplify the development. \ref FileLogger logs into a C `FILE*` stream and
 | ||||
| //! \ref StringLogger concatenates all log messages into a single string.
 | ||||
| //!
 | ||||
| //! The following snippet shows how to setup a basic logger and error handler:
 | ||||
| //!
 | ||||
| //! ~~~
 | ||||
| //! using namespace asmjit;
 | ||||
| //!
 | ||||
| //! struct MyErrorHandler : public ErrorHandler {
 | ||||
| //!   virtual bool handleError(Error code, const char* message, void* origin) {
 | ||||
| //!     printf("Error 0x%0.8X: %s\n", code, message);
 | ||||
| //!
 | ||||
| //!     // True  - error handled and code generation can continue.
 | ||||
| //!     // False - error not handled, code generation should stop.
 | ||||
| //!     return false;
 | ||||
| //!   }
 | ||||
| //! }
 | ||||
| //!
 | ||||
| //! int main(int argc, char* argv[]) {
 | ||||
| //!   JitRuntime runtime;
 | ||||
| //!   FileLogger logger(stderr);
 | ||||
| //!   MyErrorHandler eh;
 | ||||
| //!
 | ||||
| //!   X86Assembler a(&runtime);
 | ||||
| //!   a.setLogger(&logger);
 | ||||
| //!   a.setErrorHandler(&eh);
 | ||||
| //!
 | ||||
| //!   ...
 | ||||
| //!
 | ||||
| //!   return 0;
 | ||||
| //! }
 | ||||
| //! ~~~
 | ||||
| //!
 | ||||
| //! AsmJit also contains an \ref ErrorHandler, which is an abstract class that
 | ||||
| //! can be used to implement your own error handling. It can be associated with
 | ||||
| //! \ref Assembler and used to report all errors. It's a very convenient way to
 | ||||
| //! be aware of any error that happens during the code generation without making
 | ||||
| //! the error handling complicated.
 | ||||
| //!
 | ||||
| //! List of the most useful logging and error handling classes:
 | ||||
| //! - \ref asmjit::Logger - abstract logging interface:
 | ||||
| //!   - \ref asmjit::FileLogger - A logger that logs to `FILE*`.
 | ||||
| //!   - \ref asmjit::StringLogger - A logger that concatenates to a single string.
 | ||||
| //! - \ref asmjit::ErrorHandler - Easy way to handle \ref Assembler and \ref
 | ||||
| //!   Compiler
 | ||||
| //!   errors.
 | ||||
| //!
 | ||||
| //! Zone Memory Allocator
 | ||||
| //! ---------------------
 | ||||
| //!
 | ||||
| //! Zone memory allocator is an incremental memory allocator that can be used
 | ||||
| //! to allocate data of short life-time. It has much better performance
 | ||||
| //! characteristics than all other allocators, because the only thing it can do
 | ||||
| //! is to increment a pointer and return its previous address. See \ref Zone
 | ||||
| //! for more details.
 | ||||
| //!
 | ||||
| //! The whole AsmJit library is based on zone memory allocation for performance
 | ||||
| //! reasons. It has many other benefits, but the performance was the main one
 | ||||
| //! when designing the library.
 | ||||
| //!
 | ||||
| //! POD Containers
 | ||||
| //! --------------
 | ||||
| //!
 | ||||
| //! POD containers are used by AsmJit to manage its own data structures. The
 | ||||
| //! following classes can be used by AsmJit consumers:
 | ||||
| //!
 | ||||
| //!   - \ref asmjit::BitArray - A fixed bit-array that is used internally.
 | ||||
| //!   - \ref asmjit::PodVector<T> - A simple array-like container for storing
 | ||||
| //!     POD data.
 | ||||
| //!   - \ref asmjit::PodList<T> - A single linked list.
 | ||||
| //!   - \ref asmjit::StringBuilder - A string builder that can append strings
 | ||||
| //!     and integers.
 | ||||
| //!
 | ||||
| //! Utility Functions
 | ||||
| //! -----------------
 | ||||
| //!
 | ||||
| //! Utility functions are implementated static class \ref Utils. There are
 | ||||
| //! utilities for bit manipulation and bit counting, utilities to get an
 | ||||
| //! integer minimum / maximum and various other helpers required to perform
 | ||||
| //! alignment checks and binary casting from float to integer and vice versa.
 | ||||
| //!
 | ||||
| //! String utilities are also implemented by a static class \ref Utils. They
 | ||||
| //! are mostly used by AsmJit internals and not really important to end users.
 | ||||
| //!
 | ||||
| //! SIMD Utilities
 | ||||
| //! --------------
 | ||||
| //!
 | ||||
| //! SIMD code generation often requires to embed constants after each function
 | ||||
| //! or at the end of the whole code block. AsmJit contains `Vec64`, `Vec128`
 | ||||
| //! and `Vec256` classes that can be used to prepare data useful when generating
 | ||||
| //! SIMD code.
 | ||||
| //!
 | ||||
| //! X86/X64 code generators contain member functions `dmm`, `dxmm`, and `dymm`,
 | ||||
| //! which can be used to embed 64-bit, 128-bit and 256-bit data structures into
 | ||||
| //! the machine code.
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit_x86]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! \defgroup asmjit_x86 AsmJit X86/X64 API
 | ||||
| //!
 | ||||
| //! \brief X86/X64 API
 | ||||
| //!
 | ||||
| //! X86/X64 Code Generation
 | ||||
| //! -----------------------
 | ||||
| //!
 | ||||
| //! X86/X64 code generation is realized throught:
 | ||||
| //! - \ref X86Assembler - low-level code generation.
 | ||||
| //! - \ref X86Compiler - high-level code generation.
 | ||||
| //!
 | ||||
| //! X86/X64 Registers
 | ||||
| //! -----------------
 | ||||
| //!
 | ||||
| //! There are static objects that represents X86 and X64 registers. They can
 | ||||
| //! be used directly (like `eax`, `mm`, `xmm`, ...) or created through
 | ||||
| //! these functions:
 | ||||
| //!
 | ||||
| //! - `asmjit::x86::gpb_lo()` - Get an 8-bit low GPB register.
 | ||||
| //! - `asmjit::x86::gpb_hi()` - Get an 8-bit high GPB register.
 | ||||
| //! - `asmjit::x86::gpw()` - Get a 16-bit GPW register.
 | ||||
| //! - `asmjit::x86::gpd()` - Get a 32-bit GPD register.
 | ||||
| //! - `asmjit::x86::gpq()` - Get a 64-bit GPQ Gp register.
 | ||||
| //! - `asmjit::x86::gpz()` - Get a 32-bit or 64-bit GPD/GPQ register.
 | ||||
| //! - `asmjit::x86::fp()`  - Get a 80-bit FPU register.
 | ||||
| //! - `asmjit::x86::mm()`  - Get a 64-bit MMX register.
 | ||||
| //! - `asmjit::x86::xmm()` - Get a 128-bit XMM register.
 | ||||
| //! - `asmjit::x86::ymm()` - Get a 256-bit YMM register.
 | ||||
| //! - `asmjit::x86::amm()` - Get a 512-bit ZMM register.
 | ||||
| //!
 | ||||
| //! X86/X64 Addressing
 | ||||
| //! ------------------
 | ||||
| //!
 | ||||
| //! X86 and x64 architectures contains several addressing modes and most ones
 | ||||
| //! are possible with AsmJit library. Memory represents are represented by
 | ||||
| //! `BaseMem` class. These functions are used to make operands that represents
 | ||||
| //! memory addresses:
 | ||||
| //!
 | ||||
| //! - `asmjit::x86::ptr()`        - Address size not specified.
 | ||||
| //! - `asmjit::x86::byte_ptr()`   - 1 byte.
 | ||||
| //! - `asmjit::x86::word_ptr()`   - 2 bytes (GPW size).
 | ||||
| //! - `asmjit::x86::dword_ptr()`  - 4 bytes (GPD size).
 | ||||
| //! - `asmjit::x86::qword_ptr()`  - 8 bytes (GPQ/MMX size).
 | ||||
| //! - `asmjit::x86::tword_ptr()`  - 10 bytes (FPU size).
 | ||||
| //! - `asmjit::x86::dqword_ptr()` - 16 bytes (XMM size).
 | ||||
| //! - `asmjit::x86::yword_ptr()`  - 32 bytes (YMM size).
 | ||||
| //! - `asmjit::x86::zword_ptr()`  - 64 bytes (ZMM size).
 | ||||
| //!
 | ||||
| //! Most useful function to make pointer should be `asmjit::x86::ptr()`. It
 | ||||
| //! creates a pointer to the target with an unspecified size. Unspecified size
 | ||||
| //! works in all intrinsics where are used registers (this means that size is
 | ||||
| //! specified by register operand or by instruction itself). For example
 | ||||
| //! `asmjit::x86::ptr()` can't be used with `Assembler::inc()` instruction. In
 | ||||
| //! this case the size must be specified and it's also reason to differentiate
 | ||||
| //! between pointer sizes.
 | ||||
| //!
 | ||||
| //! X86 and X86 support simple address forms like `[base + displacement]` and
 | ||||
| //! also complex address forms like `[base + index * scale + displacement]`.
 | ||||
| //!
 | ||||
| //! X86/X64 Immediates
 | ||||
| //! ------------------
 | ||||
| //!
 | ||||
| //! Immediate values are constants thats passed directly after instruction
 | ||||
| //! opcode. To create such value use `asmjit::imm()` or `asmjit::imm_u()`
 | ||||
| //! methods to create a signed or unsigned immediate value.
 | ||||
| //!
 | ||||
| //! X86/X64 CPU Information
 | ||||
| //! -----------------------
 | ||||
| //!
 | ||||
| //! The CPUID instruction can be used to get an exhaustive information about
 | ||||
| //! the host X86/X64 processor. AsmJit contains utilities that can get the most
 | ||||
| //! important information related to the features supported by the CPU and the
 | ||||
| //! host operating system, in addition to host processor name and number of
 | ||||
| //! cores. Class `CpuInfo` provides generic information about a host or target
 | ||||
| //! processor and contains also a specific X86/X64 information.
 | ||||
| //!
 | ||||
| //! By default AsmJit queries the CPU information after the library is loaded
 | ||||
| //! and the queried information is reused by all instances of `JitRuntime`.
 | ||||
| //! The global instance of `CpuInfo` can't be changed, because it will affect
 | ||||
| //! the code generation of all `Runtime`s. If there is a need to have a
 | ||||
| //! specific CPU information which contains modified features or processor
 | ||||
| //! vendor it's possible by creating a new instance of the `CpuInfo` and setting
 | ||||
| //! up its members.
 | ||||
| //!
 | ||||
| //! Cpu detection is important when generating a JIT code that may or may not
 | ||||
| //! use certain CPU features. For example there used to be a SSE/SSE2 detection
 | ||||
| //! in the past and today there is often AVX/AVX2 detection.
 | ||||
| //!
 | ||||
| //! The example below shows how to detect a SSE4.1 instruction set:
 | ||||
| //!
 | ||||
| //! ~~~
 | ||||
| //! using namespace asmjit;
 | ||||
| //!
 | ||||
| //! const CpuInfo& cpuInfo = CpuInfo::getHost();
 | ||||
| //!
 | ||||
| //! if (cpuInfo.hasFeature(CpuInfo::kX86FeatureSSE4_1)) {
 | ||||
| //!   // Processor has SSE4.1.
 | ||||
| //! }
 | ||||
| //! else if (cpuInfo.hasFeature(CpuInfo::kX86FeatureSSE2)) {
 | ||||
| //!   // Processor doesn't have SSE4.1, but has SSE2.
 | ||||
| //! }
 | ||||
| //! else {
 | ||||
| //!   // Processor is archaic; it's a wonder AsmJit works here!
 | ||||
| //! }
 | ||||
| //! ~~~
 | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "./base.h" | ||||
| 
 | ||||
| // [ARM/ARM64]
 | ||||
| #if defined(ASMJIT_BUILD_ARM32) || defined(ASMJIT_BUILD_ARM64) | ||||
| #include "./arm.h" | ||||
| #endif // ASMJIT_BUILD_ARM32 || ASMJIT_BUILD_ARM64
 | ||||
| 
 | ||||
| // [X86/X64]
 | ||||
| #if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64) | ||||
| #include "./x86.h" | ||||
| #endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
 | ||||
| 
 | ||||
| // [Host]
 | ||||
| #include "./host.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_ASMJIT_H
 | ||||
							
								
								
									
										35
									
								
								DynamicHooks/thirdparty/AsmJit/base.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								DynamicHooks/thirdparty/AsmJit/base.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_BASE_H | ||||
| #define _ASMJIT_BASE_H | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "./build.h" | ||||
| 
 | ||||
| #include "./base/assembler.h" | ||||
| #include "./base/constpool.h" | ||||
| #include "./base/containers.h" | ||||
| #include "./base/cpuinfo.h" | ||||
| #include "./base/globals.h" | ||||
| #include "./base/logger.h" | ||||
| #include "./base/operand.h" | ||||
| #include "./base/podvector.h" | ||||
| #include "./base/runtime.h" | ||||
| #include "./base/utils.h" | ||||
| #include "./base/vectypes.h" | ||||
| #include "./base/vmem.h" | ||||
| #include "./base/zone.h" | ||||
| 
 | ||||
| #if !defined(ASMJIT_DISABLE_COMPILER) | ||||
| #include "./base/compiler.h" | ||||
| #include "./base/compilerfunc.h" | ||||
| #include "./base/hlstream.h" | ||||
| #endif // !ASMJIT_DISABLE_COMPILER
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_BASE_H
 | ||||
							
								
								
									
										503
									
								
								DynamicHooks/thirdparty/AsmJit/base/assembler.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										503
									
								
								DynamicHooks/thirdparty/AsmJit/base/assembler.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,503 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/assembler.h" | ||||
| #include "../base/utils.h" | ||||
| #include "../base/vmem.h" | ||||
| #include <stdarg.h> | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::ErrorHandler]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| ErrorHandler::ErrorHandler() noexcept {} | ||||
| ErrorHandler::~ErrorHandler() noexcept {} | ||||
| 
 | ||||
| ErrorHandler* ErrorHandler::addRef() const noexcept { | ||||
|   return const_cast<ErrorHandler*>(this); | ||||
| } | ||||
| void ErrorHandler::release() noexcept {} | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::ExternalTool]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| ExternalTool::ExternalTool() noexcept | ||||
|   : _assembler(nullptr), | ||||
|     _exId(0), | ||||
|     _arch(kArchNone), | ||||
|     _regSize(0), | ||||
|     _finalized(false), | ||||
|     _reserved(0), | ||||
|     _lastError(kErrorNotInitialized) {} | ||||
| ExternalTool::~ExternalTool() noexcept {} | ||||
| 
 | ||||
| Error ExternalTool::setLastError(Error error, const char* message) noexcept { | ||||
|   // Special case, reset the last error the error is `kErrorOk`.
 | ||||
|   if (error == kErrorOk)  { | ||||
|     _lastError = kErrorOk; | ||||
|     return kErrorOk; | ||||
|   } | ||||
| 
 | ||||
|   // Don't do anything if the code-generator doesn't have associated assembler.
 | ||||
|   Assembler* assembler = getAssembler(); | ||||
|   if (assembler == nullptr) | ||||
|     return error; | ||||
| 
 | ||||
|   if (message == nullptr) | ||||
|     message = DebugUtils::errorAsString(error); | ||||
| 
 | ||||
|   // Logging is skipped if the error is handled by `ErrorHandler.
 | ||||
|   ErrorHandler* eh = assembler->getErrorHandler(); | ||||
|   ASMJIT_TLOG("[ERROR (ExternalTool)] %s (0x%0.8u) %s\n", message, | ||||
|     static_cast<unsigned int>(error), | ||||
|     !eh ? "(Possibly unhandled?)" : ""); | ||||
| 
 | ||||
|   if (eh != nullptr && eh->handleError(error, message, this)) | ||||
|     return error; | ||||
| 
 | ||||
| #if !defined(ASMJIT_DISABLE_LOGGER) | ||||
|   Logger* logger = assembler->getLogger(); | ||||
|   if (logger != nullptr) | ||||
|     logger->logFormat(Logger::kStyleComment, | ||||
|       "*** ERROR (ExternalTool): %s (0x%0.8u).\n", message, | ||||
|       static_cast<unsigned int>(error)); | ||||
| #endif // !ASMJIT_DISABLE_LOGGER
 | ||||
| 
 | ||||
|   // The handler->handleError() function may throw an exception or longjmp()
 | ||||
|   // to terminate the execution of `setLastError()`. This is the reason why
 | ||||
|   // we have delayed changing the `_error` member until now.
 | ||||
|   _lastError = error; | ||||
|   return error; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Assembler - Construction / Destruction]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Assembler::Assembler(Runtime* runtime) noexcept | ||||
|   : _runtime(runtime), | ||||
|     _logger(nullptr), | ||||
|     _errorHandler(nullptr), | ||||
|     _arch(kArchNone), | ||||
|     _regSize(0), | ||||
|     _reserved(0), | ||||
|     _asmOptions(0), | ||||
|     _instOptions(0), | ||||
|     _lastError(runtime ? kErrorOk : kErrorNotInitialized), | ||||
|     _exIdGenerator(0), | ||||
|     _exCountAttached(0), | ||||
|     _zoneAllocator(8192 - Zone::kZoneOverhead), | ||||
|     _buffer(nullptr), | ||||
|     _end(nullptr), | ||||
|     _cursor(nullptr), | ||||
|     _trampolinesSize(0), | ||||
|     _comment(nullptr), | ||||
|     _unusedLinks(nullptr), | ||||
|     _labels(), | ||||
|     _relocations() {} | ||||
| 
 | ||||
| Assembler::~Assembler() noexcept { | ||||
|   reset(true); | ||||
| 
 | ||||
|   if (_errorHandler != nullptr) | ||||
|     _errorHandler->release(); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Assembler - Reset]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void Assembler::reset(bool releaseMemory) noexcept { | ||||
|   _asmOptions = 0; | ||||
|   _instOptions = 0; | ||||
|   _lastError = kErrorOk; | ||||
|   _exIdGenerator = 0; | ||||
|   _exCountAttached = 0; | ||||
| 
 | ||||
|   _zoneAllocator.reset(releaseMemory); | ||||
| 
 | ||||
|   if (releaseMemory && _buffer != nullptr) { | ||||
|     ASMJIT_FREE(_buffer); | ||||
|     _buffer = nullptr; | ||||
|     _end = nullptr; | ||||
|   } | ||||
| 
 | ||||
|   _cursor = _buffer; | ||||
|   _trampolinesSize = 0; | ||||
| 
 | ||||
|   _comment = nullptr; | ||||
|   _unusedLinks = nullptr; | ||||
| 
 | ||||
|   _sections.reset(releaseMemory); | ||||
|   _labels.reset(releaseMemory); | ||||
|   _relocations.reset(releaseMemory); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Assembler - Logging & Error Handling]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error Assembler::setLastError(Error error, const char* message) noexcept { | ||||
|   // Special case, reset the last error the error is `kErrorOk`.
 | ||||
|   if (error == kErrorOk)  { | ||||
|     _lastError = kErrorOk; | ||||
|     return kErrorOk; | ||||
|   } | ||||
| 
 | ||||
|   if (message == nullptr) | ||||
|     message = DebugUtils::errorAsString(error); | ||||
| 
 | ||||
|   // Logging is skipped if the error is handled by `ErrorHandler`.
 | ||||
|   ErrorHandler* eh = _errorHandler; | ||||
|   ASMJIT_TLOG("[ERROR (Assembler)] %s (0x%0.8u) %s\n", message, | ||||
|     static_cast<unsigned int>(error), | ||||
|     !eh ? "(Possibly unhandled?)" : ""); | ||||
| 
 | ||||
|   if (eh != nullptr && eh->handleError(error, message, this)) | ||||
|     return error; | ||||
| 
 | ||||
| #if !defined(ASMJIT_DISABLE_LOGGER) | ||||
|   Logger* logger = _logger; | ||||
|   if (logger != nullptr) | ||||
|     logger->logFormat(Logger::kStyleComment, | ||||
|       "*** ERROR (Assembler): %s (0x%0.8u).\n", message, | ||||
|       static_cast<unsigned int>(error)); | ||||
| #endif // !ASMJIT_DISABLE_LOGGER
 | ||||
| 
 | ||||
|   // The handler->handleError() function may throw an exception or longjmp()
 | ||||
|   // to terminate the execution of `setLastError()`. This is the reason why
 | ||||
|   // we have delayed changing the `_error` member until now.
 | ||||
|   _lastError = error; | ||||
|   return error; | ||||
| } | ||||
| 
 | ||||
| Error Assembler::setErrorHandler(ErrorHandler* handler) noexcept { | ||||
|   ErrorHandler* oldHandler = _errorHandler; | ||||
| 
 | ||||
|   if (oldHandler != nullptr) | ||||
|     oldHandler->release(); | ||||
| 
 | ||||
|   if (handler != nullptr) | ||||
|     handler = handler->addRef(); | ||||
| 
 | ||||
|   _errorHandler = handler; | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Assembler - Buffer]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error Assembler::_grow(size_t n) noexcept { | ||||
|   size_t capacity = getCapacity(); | ||||
|   size_t after = getOffset() + n; | ||||
| 
 | ||||
|   // Overflow.
 | ||||
|   if (n > IntTraits<uintptr_t>::maxValue() - capacity) | ||||
|     return setLastError(kErrorNoHeapMemory); | ||||
| 
 | ||||
|   // Grow is called when allocation is needed, so it shouldn't happen, but on
 | ||||
|   // the other hand it is simple to catch and it's not an error.
 | ||||
|   if (after <= capacity) | ||||
|     return kErrorOk; | ||||
| 
 | ||||
|   if (capacity < kMemAllocOverhead) | ||||
|     capacity = kMemAllocOverhead; | ||||
|   else | ||||
|     capacity += kMemAllocOverhead; | ||||
| 
 | ||||
|   do { | ||||
|     size_t oldCapacity = capacity; | ||||
| 
 | ||||
|     if (capacity < kMemAllocGrowMax) | ||||
|       capacity *= 2; | ||||
|     else | ||||
|       capacity += kMemAllocGrowMax; | ||||
| 
 | ||||
|     // Overflow.
 | ||||
|     if (oldCapacity > capacity) | ||||
|       return setLastError(kErrorNoHeapMemory); | ||||
|   } while (capacity - kMemAllocOverhead < after); | ||||
| 
 | ||||
|   capacity -= kMemAllocOverhead; | ||||
|   return _reserve(capacity); | ||||
| } | ||||
| 
 | ||||
| Error Assembler::_reserve(size_t n) noexcept { | ||||
|   size_t capacity = getCapacity(); | ||||
|   if (n <= capacity) | ||||
|     return kErrorOk; | ||||
| 
 | ||||
|   uint8_t* newBuffer; | ||||
|   if (_buffer == nullptr) | ||||
|     newBuffer = static_cast<uint8_t*>(ASMJIT_ALLOC(n)); | ||||
|   else | ||||
|     newBuffer = static_cast<uint8_t*>(ASMJIT_REALLOC(_buffer, n)); | ||||
| 
 | ||||
|   if (newBuffer == nullptr) | ||||
|     return setLastError(kErrorNoHeapMemory); | ||||
| 
 | ||||
|   size_t offset = getOffset(); | ||||
| 
 | ||||
|   _buffer = newBuffer; | ||||
|   _end = _buffer + n; | ||||
|   _cursor = newBuffer + offset; | ||||
| 
 | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Assembler - Label]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error Assembler::_newLabelId() noexcept { | ||||
|   LabelData* data = _zoneAllocator.allocT<LabelData>(); | ||||
| 
 | ||||
|   data->offset = -1; | ||||
|   data->links = nullptr; | ||||
|   data->exId = 0; | ||||
|   data->exData = nullptr; | ||||
| 
 | ||||
|   uint32_t id = OperandUtil::makeLabelId(static_cast<uint32_t>(_labels.getLength())); | ||||
|   Error error = _labels.append(data); | ||||
| 
 | ||||
|   if (error != kErrorOk) { | ||||
|     setLastError(kErrorNoHeapMemory); | ||||
|     return kInvalidValue; | ||||
|   } | ||||
| 
 | ||||
|   return id; | ||||
| } | ||||
| 
 | ||||
| LabelLink* Assembler::_newLabelLink() noexcept { | ||||
|   LabelLink* link = _unusedLinks; | ||||
| 
 | ||||
|   if (link) { | ||||
|     _unusedLinks = link->prev; | ||||
|   } | ||||
|   else { | ||||
|     link = _zoneAllocator.allocT<LabelLink>(); | ||||
|     if (link == nullptr) | ||||
|       return nullptr; | ||||
|   } | ||||
| 
 | ||||
|   link->prev = nullptr; | ||||
|   link->offset = 0; | ||||
|   link->displacement = 0; | ||||
|   link->relocId = -1; | ||||
| 
 | ||||
|   return link; | ||||
| } | ||||
| 
 | ||||
| Error Assembler::bind(const Label& label) noexcept { | ||||
|   // Get label data based on label id.
 | ||||
|   uint32_t index = label.getId(); | ||||
|   LabelData* data = getLabelData(index); | ||||
| 
 | ||||
|   // Label can be bound only once.
 | ||||
|   if (data->offset != -1) | ||||
|     return setLastError(kErrorLabelAlreadyBound); | ||||
| 
 | ||||
| #if !defined(ASMJIT_DISABLE_LOGGER) | ||||
|   if (_logger) { | ||||
|     StringBuilderTmp<256> sb; | ||||
|     sb.setFormat("L%u:", index); | ||||
| 
 | ||||
|     size_t binSize = 0; | ||||
|     if (!_logger->hasOption(Logger::kOptionBinaryForm)) | ||||
|       binSize = kInvalidIndex; | ||||
| 
 | ||||
|     LogUtil::formatLine(sb, nullptr, binSize, 0, 0, _comment); | ||||
|     _logger->logString(Logger::kStyleLabel, sb.getData(), sb.getLength()); | ||||
|   } | ||||
| #endif // !ASMJIT_DISABLE_LOGGER
 | ||||
| 
 | ||||
|   Error error = kErrorOk; | ||||
|   size_t pos = getOffset(); | ||||
| 
 | ||||
|   LabelLink* link = data->links; | ||||
|   LabelLink* prev = nullptr; | ||||
| 
 | ||||
|   while (link) { | ||||
|     intptr_t offset = link->offset; | ||||
| 
 | ||||
|     if (link->relocId != -1) { | ||||
|       // Handle RelocData - We have to update RelocData information instead of
 | ||||
|       // patching the displacement in LabelData.
 | ||||
|       _relocations[link->relocId].data += static_cast<Ptr>(pos); | ||||
|     } | ||||
|     else { | ||||
|       // Not using relocId, this means that we are overwriting a real
 | ||||
|       // displacement in the binary stream.
 | ||||
|       int32_t patchedValue = static_cast<int32_t>( | ||||
|         static_cast<intptr_t>(pos) - offset + link->displacement); | ||||
| 
 | ||||
|       // Size of the value we are going to patch. Only BYTE/DWORD is allowed.
 | ||||
|       uint32_t size = readU8At(offset); | ||||
|       ASMJIT_ASSERT(size == 1 || size == 4); | ||||
| 
 | ||||
|       if (size == 4) { | ||||
|         writeI32At(offset, patchedValue); | ||||
|       } | ||||
|       else { | ||||
|         ASMJIT_ASSERT(size == 1); | ||||
|         if (Utils::isInt8(patchedValue)) | ||||
|           writeU8At(offset, static_cast<uint32_t>(patchedValue) & 0xFF); | ||||
|         else | ||||
|           error = kErrorIllegalDisplacement; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     prev = link->prev; | ||||
|     link = prev; | ||||
|   } | ||||
| 
 | ||||
|   // Chain unused links.
 | ||||
|   link = data->links; | ||||
|   if (link) { | ||||
|     if (prev == nullptr) | ||||
|       prev = link; | ||||
| 
 | ||||
|     prev->prev = _unusedLinks; | ||||
|     _unusedLinks = link; | ||||
|   } | ||||
| 
 | ||||
|   // Set as bound (offset is zero or greater and no links).
 | ||||
|   data->offset = pos; | ||||
|   data->links = nullptr; | ||||
| 
 | ||||
|   if (error != kErrorOk) | ||||
|     return setLastError(error); | ||||
| 
 | ||||
|   _comment = nullptr; | ||||
|   return error; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Assembler - Embed]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error Assembler::embed(const void* data, uint32_t size) noexcept { | ||||
|   if (getRemainingSpace() < size) { | ||||
|     Error error = _grow(size); | ||||
|     if (error != kErrorOk) | ||||
|       return setLastError(error); | ||||
|   } | ||||
| 
 | ||||
|   uint8_t* cursor = getCursor(); | ||||
|   ::memcpy(cursor, data, size); | ||||
|   setCursor(cursor + size); | ||||
| 
 | ||||
| #if !defined(ASMJIT_DISABLE_LOGGER) | ||||
|   if (_logger) | ||||
|     _logger->logBinary(Logger::kStyleData, data, size); | ||||
| #endif // !ASMJIT_DISABLE_LOGGER
 | ||||
| 
 | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Assembler - Reloc]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| size_t Assembler::relocCode(void* dst, Ptr baseAddress) const noexcept { | ||||
|   if (baseAddress == kNoBaseAddress) | ||||
|     baseAddress = static_cast<Ptr>((uintptr_t)dst); | ||||
|   return _relocCode(dst, baseAddress); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Assembler - Make]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void* Assembler::make() noexcept { | ||||
|   // Do nothing on error condition or if no instruction has been emitted.
 | ||||
|   if (_lastError != kErrorOk || getCodeSize() == 0) | ||||
|     return nullptr; | ||||
| 
 | ||||
|   void* p; | ||||
|   Error error = _runtime->add(&p, this); | ||||
| 
 | ||||
|   if (error != kErrorOk) | ||||
|     setLastError(error); | ||||
| 
 | ||||
|   return p; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Assembler - Emit (Helpers)]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #define NA noOperand | ||||
| 
 | ||||
| Error Assembler::emit(uint32_t code) { | ||||
|   return _emit(code, NA, NA, NA, NA); | ||||
| } | ||||
| 
 | ||||
| Error Assembler::emit(uint32_t code, const Operand& o0) { | ||||
|   return _emit(code, o0, NA, NA, NA); | ||||
| } | ||||
| 
 | ||||
| Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1) { | ||||
|   return _emit(code, o0, o1, NA, NA); | ||||
| } | ||||
| 
 | ||||
| Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2) { | ||||
|   return _emit(code, o0, o1, o2, NA); | ||||
| } | ||||
| 
 | ||||
| Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) { | ||||
|   return _emit(code, o0, o1, o2, o3); | ||||
| } | ||||
| 
 | ||||
| Error Assembler::emit(uint32_t code, int o0) { | ||||
|   return _emit(code, Imm(o0), NA, NA, NA); | ||||
| } | ||||
| 
 | ||||
| Error Assembler::emit(uint32_t code, const Operand& o0, int o1) { | ||||
|   return _emit(code, o0, Imm(o1), NA, NA); | ||||
| } | ||||
| 
 | ||||
| Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, int o2) { | ||||
|   return _emit(code, o0, o1, Imm(o2), NA); | ||||
| } | ||||
| 
 | ||||
| Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int o3) { | ||||
|   return _emit(code, o0, o1, o2, Imm(o3)); | ||||
| } | ||||
| 
 | ||||
| Error Assembler::emit(uint32_t code, int64_t o0) { | ||||
|   return _emit(code, Imm(o0), NA, NA, NA); | ||||
| } | ||||
| 
 | ||||
| Error Assembler::emit(uint32_t code, const Operand& o0, int64_t o1) { | ||||
|   return _emit(code, o0, Imm(o1), NA, NA); | ||||
| } | ||||
| 
 | ||||
| Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, int64_t o2) { | ||||
|   return _emit(code, o0, o1, Imm(o2), NA); | ||||
| } | ||||
| 
 | ||||
| Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int64_t o3) { | ||||
|   return _emit(code, o0, o1, o2, Imm(o3)); | ||||
| } | ||||
| 
 | ||||
| #undef NA | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
							
								
								
									
										1005
									
								
								DynamicHooks/thirdparty/AsmJit/base/assembler.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1005
									
								
								DynamicHooks/thirdparty/AsmJit/base/assembler.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										630
									
								
								DynamicHooks/thirdparty/AsmJit/base/compiler.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										630
									
								
								DynamicHooks/thirdparty/AsmJit/base/compiler.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,630 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #include "../build.h" | ||||
| #if !defined(ASMJIT_DISABLE_COMPILER) | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/assembler.h" | ||||
| #include "../base/compiler.h" | ||||
| #include "../base/compilercontext_p.h" | ||||
| #include "../base/cpuinfo.h" | ||||
| #include "../base/logger.h" | ||||
| #include "../base/utils.h" | ||||
| #include <stdarg.h> | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [Constants]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| static const char noName[1] = { '\0' }; | ||||
| enum { kCompilerDefaultLookAhead = 64 }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Compiler - Construction / Destruction]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Compiler::Compiler() noexcept | ||||
|   : _features(0), | ||||
|     _maxLookAhead(kCompilerDefaultLookAhead), | ||||
|     _instOptions(0), | ||||
|     _tokenGenerator(0), | ||||
|     _nodeFlowId(0), | ||||
|     _nodeFlags(0), | ||||
|     _targetVarMapping(nullptr), | ||||
|     _firstNode(nullptr), | ||||
|     _lastNode(nullptr), | ||||
|     _cursor(nullptr), | ||||
|     _func(nullptr), | ||||
|     _zoneAllocator(8192 - Zone::kZoneOverhead), | ||||
|     _varAllocator(4096 - Zone::kZoneOverhead), | ||||
|     _stringAllocator(4096 - Zone::kZoneOverhead), | ||||
|     _constAllocator(4096 - Zone::kZoneOverhead), | ||||
|     _localConstPool(&_constAllocator), | ||||
|     _globalConstPool(&_zoneAllocator) {} | ||||
| Compiler::~Compiler() noexcept {} | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Compiler - Attach / Reset]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void Compiler::reset(bool releaseMemory) noexcept { | ||||
|   Assembler* assembler = getAssembler(); | ||||
|   if (assembler != nullptr) | ||||
|     assembler->_detached(this); | ||||
| 
 | ||||
|   _arch = kArchNone; | ||||
|   _regSize = 0; | ||||
|   _finalized = false; | ||||
|   _lastError = kErrorNotInitialized; | ||||
| 
 | ||||
|   _features = 0; | ||||
|   _maxLookAhead = kCompilerDefaultLookAhead; | ||||
| 
 | ||||
|   _instOptions = 0; | ||||
|   _tokenGenerator = 0; | ||||
| 
 | ||||
|   _nodeFlowId = 0; | ||||
|   _nodeFlags = 0; | ||||
| 
 | ||||
|   _firstNode = nullptr; | ||||
|   _lastNode = nullptr; | ||||
| 
 | ||||
|   _cursor = nullptr; | ||||
|   _func = nullptr; | ||||
| 
 | ||||
|   _localConstPool.reset(); | ||||
|   _globalConstPool.reset(); | ||||
| 
 | ||||
|   _localConstPoolLabel.reset(); | ||||
|   _globalConstPoolLabel.reset(); | ||||
| 
 | ||||
|   _zoneAllocator.reset(releaseMemory); | ||||
|   _varAllocator.reset(releaseMemory); | ||||
|   _stringAllocator.reset(releaseMemory); | ||||
|   _constAllocator.reset(releaseMemory); | ||||
| 
 | ||||
|   _varList.reset(releaseMemory); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Compiler - Node-Factory]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| HLData* Compiler::newDataNode(const void* data, uint32_t size) noexcept { | ||||
|   if (size > HLData::kInlineBufferSize) { | ||||
|     void* clonedData = _stringAllocator.alloc(size); | ||||
|     if (clonedData == nullptr) | ||||
|       return nullptr; | ||||
| 
 | ||||
|     if (data != nullptr) | ||||
|       ::memcpy(clonedData, data, size); | ||||
|     data = clonedData; | ||||
|   } | ||||
| 
 | ||||
|   return newNode<HLData>(const_cast<void*>(data), size); | ||||
| } | ||||
| 
 | ||||
| HLAlign* Compiler::newAlignNode(uint32_t alignMode, uint32_t offset) noexcept { | ||||
|   return newNode<HLAlign>(alignMode, offset); | ||||
| } | ||||
| 
 | ||||
| HLLabel* Compiler::newLabelNode() noexcept { | ||||
|   Assembler* assembler = getAssembler(); | ||||
|   if (assembler == nullptr) return nullptr; | ||||
| 
 | ||||
|   uint32_t id = assembler->_newLabelId(); | ||||
|   LabelData* ld = assembler->getLabelData(id); | ||||
| 
 | ||||
|   HLLabel* node = newNode<HLLabel>(id); | ||||
|   if (node == nullptr) return nullptr; | ||||
| 
 | ||||
|   // These have to be zero now.
 | ||||
|   ASMJIT_ASSERT(ld->exId == 0); | ||||
|   ASMJIT_ASSERT(ld->exData == nullptr); | ||||
| 
 | ||||
|   ld->exId = _exId; | ||||
|   ld->exData = node; | ||||
| 
 | ||||
|   return node; | ||||
| } | ||||
| 
 | ||||
| HLComment* Compiler::newCommentNode(const char* str) noexcept { | ||||
|   if (str != nullptr && str[0]) { | ||||
|     str = _stringAllocator.sdup(str); | ||||
|     if (str == nullptr) | ||||
|       return nullptr; | ||||
|   } | ||||
| 
 | ||||
|   return newNode<HLComment>(str); | ||||
| } | ||||
| 
 | ||||
| HLHint* Compiler::newHintNode(Var& var, uint32_t hint, uint32_t value) noexcept { | ||||
|   if (var.getId() == kInvalidValue) | ||||
|     return nullptr; | ||||
| 
 | ||||
|   VarData* vd = getVd(var); | ||||
|   return newNode<HLHint>(vd, hint, value); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Compiler - Code-Stream]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| HLNode* Compiler::addFunc(HLFunc* func) noexcept { | ||||
|   ASMJIT_ASSERT(_func == nullptr); | ||||
|   _func = func; | ||||
| 
 | ||||
|   addNode(func);                 // Add function node.
 | ||||
|   addNode(func->getEntryNode()); // Add function entry.
 | ||||
|   HLNode* cursor = getCursor(); | ||||
| 
 | ||||
|   addNode(func->getExitNode());  // Add function exit / epilog marker.
 | ||||
|   addNode(func->getEnd());       // Add function end.
 | ||||
|   setCursor(cursor); | ||||
| 
 | ||||
|   return func; | ||||
| } | ||||
| 
 | ||||
| HLNode* Compiler::addNode(HLNode* node) noexcept { | ||||
|   ASMJIT_ASSERT(node != nullptr); | ||||
|   ASMJIT_ASSERT(node->_prev == nullptr); | ||||
|   ASMJIT_ASSERT(node->_next == nullptr); | ||||
| 
 | ||||
|   if (_cursor == nullptr) { | ||||
|     if (_firstNode == nullptr) { | ||||
|       _firstNode = node; | ||||
|       _lastNode = node; | ||||
|     } | ||||
|     else { | ||||
|       node->_next = _firstNode; | ||||
|       _firstNode->_prev = node; | ||||
|       _firstNode = node; | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
|     HLNode* prev = _cursor; | ||||
|     HLNode* next = _cursor->_next; | ||||
| 
 | ||||
|     node->_prev = prev; | ||||
|     node->_next = next; | ||||
| 
 | ||||
|     prev->_next = node; | ||||
|     if (next) | ||||
|       next->_prev = node; | ||||
|     else | ||||
|       _lastNode = node; | ||||
|   } | ||||
| 
 | ||||
|   _cursor = node; | ||||
|   return node; | ||||
| } | ||||
| 
 | ||||
| HLNode* Compiler::addNodeBefore(HLNode* node, HLNode* ref) noexcept { | ||||
|   ASMJIT_ASSERT(node != nullptr); | ||||
|   ASMJIT_ASSERT(node->_prev == nullptr); | ||||
|   ASMJIT_ASSERT(node->_next == nullptr); | ||||
|   ASMJIT_ASSERT(ref != nullptr); | ||||
| 
 | ||||
|   HLNode* prev = ref->_prev; | ||||
|   HLNode* next = ref; | ||||
| 
 | ||||
|   node->_prev = prev; | ||||
|   node->_next = next; | ||||
| 
 | ||||
|   next->_prev = node; | ||||
|   if (prev) | ||||
|     prev->_next = node; | ||||
|   else | ||||
|     _firstNode = node; | ||||
| 
 | ||||
|   return node; | ||||
| } | ||||
| 
 | ||||
| HLNode* Compiler::addNodeAfter(HLNode* node, HLNode* ref) noexcept { | ||||
|   ASMJIT_ASSERT(node != nullptr); | ||||
|   ASMJIT_ASSERT(node->_prev == nullptr); | ||||
|   ASMJIT_ASSERT(node->_next == nullptr); | ||||
|   ASMJIT_ASSERT(ref != nullptr); | ||||
| 
 | ||||
|   HLNode* prev = ref; | ||||
|   HLNode* next = ref->_next; | ||||
| 
 | ||||
|   node->_prev = prev; | ||||
|   node->_next = next; | ||||
| 
 | ||||
|   prev->_next = node; | ||||
|   if (next) | ||||
|     next->_prev = node; | ||||
|   else | ||||
|     _lastNode = node; | ||||
| 
 | ||||
|   return node; | ||||
| } | ||||
| 
 | ||||
| static ASMJIT_INLINE void Compiler_nodeRemoved(Compiler* self, HLNode* node_) noexcept { | ||||
|   if (node_->isJmpOrJcc()) { | ||||
|     HLJump* node = static_cast<HLJump*>(node_); | ||||
|     HLLabel* label = node->getTarget(); | ||||
| 
 | ||||
|     if (label != nullptr) { | ||||
|       // Disconnect.
 | ||||
|       HLJump** pPrev = &label->_from; | ||||
|       for (;;) { | ||||
|         ASMJIT_ASSERT(*pPrev != nullptr); | ||||
|         HLJump* current = *pPrev; | ||||
| 
 | ||||
|         if (current == nullptr) | ||||
|           break; | ||||
| 
 | ||||
|         if (current == node) { | ||||
|           *pPrev = node->_jumpNext; | ||||
|           break; | ||||
|         } | ||||
| 
 | ||||
|         pPrev = ¤t->_jumpNext; | ||||
|       } | ||||
| 
 | ||||
|       label->subNumRefs(); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| HLNode* Compiler::removeNode(HLNode* node) noexcept { | ||||
|   HLNode* prev = node->_prev; | ||||
|   HLNode* next = node->_next; | ||||
| 
 | ||||
|   if (_firstNode == node) | ||||
|     _firstNode = next; | ||||
|   else | ||||
|     prev->_next = next; | ||||
| 
 | ||||
|   if (_lastNode == node) | ||||
|     _lastNode  = prev; | ||||
|   else | ||||
|     next->_prev = prev; | ||||
| 
 | ||||
|   node->_prev = nullptr; | ||||
|   node->_next = nullptr; | ||||
| 
 | ||||
|   if (_cursor == node) | ||||
|     _cursor = prev; | ||||
|   Compiler_nodeRemoved(this, node); | ||||
| 
 | ||||
|   return node; | ||||
| } | ||||
| 
 | ||||
| void Compiler::removeNodes(HLNode* first, HLNode* last) noexcept { | ||||
|   if (first == last) { | ||||
|     removeNode(first); | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   HLNode* prev = first->_prev; | ||||
|   HLNode* next = last->_next; | ||||
| 
 | ||||
|   if (_firstNode == first) | ||||
|     _firstNode = next; | ||||
|   else | ||||
|     prev->_next = next; | ||||
| 
 | ||||
|   if (_lastNode == last) | ||||
|     _lastNode  = prev; | ||||
|   else | ||||
|     next->_prev = prev; | ||||
| 
 | ||||
|   HLNode* node = first; | ||||
|   for (;;) { | ||||
|     HLNode* next = node->getNext(); | ||||
|     ASMJIT_ASSERT(next != nullptr); | ||||
| 
 | ||||
|     node->_prev = nullptr; | ||||
|     node->_next = nullptr; | ||||
| 
 | ||||
|     if (_cursor == node) | ||||
|       _cursor = prev; | ||||
|     Compiler_nodeRemoved(this, node); | ||||
| 
 | ||||
|     if (node == last) | ||||
|       break; | ||||
|     node = next; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| HLNode* Compiler::setCursor(HLNode* node) noexcept { | ||||
|   HLNode* old = _cursor; | ||||
|   _cursor = node; | ||||
|   return old; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Compiler - Align]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error Compiler::align(uint32_t alignMode, uint32_t offset) noexcept { | ||||
|   HLAlign* node = newAlignNode(alignMode, offset); | ||||
|   if (node == nullptr) | ||||
|     return setLastError(kErrorNoHeapMemory); | ||||
| 
 | ||||
|   addNode(node); | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Compiler - Label]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| HLLabel* Compiler::getHLLabel(uint32_t id) const noexcept { | ||||
|   Assembler* assembler = getAssembler(); | ||||
|   if (assembler == nullptr) return nullptr; | ||||
| 
 | ||||
|   LabelData* ld = assembler->getLabelData(id); | ||||
|   if (ld->exId == _exId) | ||||
|     return static_cast<HLLabel*>(ld->exData); | ||||
|   else | ||||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
| bool Compiler::isLabelValid(uint32_t id) const noexcept { | ||||
|   Assembler* assembler = getAssembler(); | ||||
|   if (assembler == nullptr) return false; | ||||
| 
 | ||||
|   return static_cast<size_t>(id) < assembler->getLabelsCount(); | ||||
| } | ||||
| 
 | ||||
| uint32_t Compiler::_newLabelId() noexcept { | ||||
|   HLLabel* node = newLabelNode(); | ||||
|   if (node == nullptr) { | ||||
|     setLastError(kErrorNoHeapMemory); | ||||
|     return kInvalidValue; | ||||
|   } | ||||
| 
 | ||||
|   return node->getLabelId(); | ||||
| } | ||||
| 
 | ||||
| Error Compiler::bind(const Label& label) noexcept { | ||||
|   HLLabel* node = getHLLabel(label); | ||||
|   if (node == nullptr) | ||||
|     return setLastError(kErrorInvalidState); | ||||
|   addNode(node); | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Compiler - Embed]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error Compiler::embed(const void* data, uint32_t size) noexcept { | ||||
|   HLData* node = newDataNode(data, size); | ||||
|   if (node == nullptr) | ||||
|     return setLastError(kErrorNoHeapMemory); | ||||
| 
 | ||||
|   addNode(node); | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| Error Compiler::embedConstPool(const Label& label, const ConstPool& pool) noexcept { | ||||
|   if (label.getId() == kInvalidValue) | ||||
|     return kErrorInvalidState; | ||||
| 
 | ||||
|   align(kAlignData, static_cast<uint32_t>(pool.getAlignment())); | ||||
|   bind(label); | ||||
| 
 | ||||
|   HLData* embedNode = newDataNode(nullptr, static_cast<uint32_t>(pool.getSize())); | ||||
|   if (embedNode == nullptr) | ||||
|     return kErrorNoHeapMemory; | ||||
| 
 | ||||
|   pool.fill(embedNode->getData()); | ||||
|   addNode(embedNode); | ||||
| 
 | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Compiler - Comment]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error Compiler::comment(const char* fmt, ...) noexcept { | ||||
|   char buf[256]; | ||||
|   char* p = buf; | ||||
| 
 | ||||
|   if (fmt) { | ||||
|     va_list ap; | ||||
|     va_start(ap, fmt); | ||||
|     p += vsnprintf(p, 254, fmt, ap); | ||||
|     va_end(ap); | ||||
|   } | ||||
| 
 | ||||
|   p[0] = '\0'; | ||||
| 
 | ||||
|   HLComment* node = newCommentNode(buf); | ||||
|   if (node == nullptr) | ||||
|     return setLastError(kErrorNoHeapMemory); | ||||
| 
 | ||||
|   addNode(node); | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Compiler - Hint]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error Compiler::_hint(Var& var, uint32_t hint, uint32_t value) noexcept { | ||||
|   if (var.getId() == kInvalidValue) | ||||
|     return kErrorOk; | ||||
| 
 | ||||
|   HLHint* node = newHintNode(var, hint, value); | ||||
|   if (node == nullptr) | ||||
|     return setLastError(kErrorNoHeapMemory); | ||||
| 
 | ||||
|   addNode(node); | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Compiler - Vars]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| VarData* Compiler::_newVd(const VarInfo& vi, const char* name) noexcept { | ||||
|   VarData* vd = reinterpret_cast<VarData*>(_varAllocator.alloc(sizeof(VarData))); | ||||
|   if (ASMJIT_UNLIKELY(vd == nullptr)) | ||||
|     goto _NoMemory; | ||||
| 
 | ||||
|   vd->_name = noName; | ||||
|   vd->_id = OperandUtil::makeVarId(static_cast<uint32_t>(_varList.getLength())); | ||||
|   vd->_localId = kInvalidValue; | ||||
| 
 | ||||
| #if !defined(ASMJIT_DISABLE_LOGGER) | ||||
|   if (name != nullptr && name[0] != '\0') { | ||||
|     vd->_name = _stringAllocator.sdup(name); | ||||
|   } | ||||
| #endif // !ASMJIT_DISABLE_LOGGER
 | ||||
| 
 | ||||
|   vd->_type = static_cast<uint8_t>(vi.getTypeId()); | ||||
|   vd->_class = static_cast<uint8_t>(vi.getRegClass()); | ||||
|   vd->_flags = 0; | ||||
|   vd->_priority = 10; | ||||
| 
 | ||||
|   vd->_state = kVarStateNone; | ||||
|   vd->_regIndex = kInvalidReg; | ||||
|   vd->_isStack = false; | ||||
|   vd->_isMemArg = false; | ||||
|   vd->_isCalculated = false; | ||||
|   vd->_saveOnUnuse = false; | ||||
|   vd->_modified = false; | ||||
|   vd->_reserved0 = 0; | ||||
|   vd->_alignment = static_cast<uint8_t>(Utils::iMin<uint32_t>(vi.getSize(), 64)); | ||||
| 
 | ||||
|   vd->_size = vi.getSize(); | ||||
|   vd->_homeMask = 0; | ||||
| 
 | ||||
|   vd->_memOffset = 0; | ||||
|   vd->_memCell = nullptr; | ||||
| 
 | ||||
|   vd->rReadCount = 0; | ||||
|   vd->rWriteCount = 0; | ||||
|   vd->mReadCount = 0; | ||||
|   vd->mWriteCount = 0; | ||||
| 
 | ||||
|   vd->_va = nullptr; | ||||
| 
 | ||||
|   if (ASMJIT_UNLIKELY(_varList.append(vd) != kErrorOk)) | ||||
|     goto _NoMemory; | ||||
|   return vd; | ||||
| 
 | ||||
| _NoMemory: | ||||
|   setLastError(kErrorNoHeapMemory); | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| Error Compiler::alloc(Var& var) noexcept { | ||||
|   if (var.getId() == kInvalidValue) | ||||
|     return kErrorOk; | ||||
|   return _hint(var, kVarHintAlloc, kInvalidValue); | ||||
| } | ||||
| 
 | ||||
| Error Compiler::alloc(Var& var, uint32_t regIndex) noexcept { | ||||
|   if (var.getId() == kInvalidValue) | ||||
|     return kErrorOk; | ||||
|   return _hint(var, kVarHintAlloc, regIndex); | ||||
| } | ||||
| 
 | ||||
| Error Compiler::alloc(Var& var, const Reg& reg) noexcept { | ||||
|   if (var.getId() == kInvalidValue) | ||||
|     return kErrorOk; | ||||
|   return _hint(var, kVarHintAlloc, reg.getRegIndex()); | ||||
| } | ||||
| 
 | ||||
| Error Compiler::save(Var& var) noexcept { | ||||
|   if (var.getId() == kInvalidValue) | ||||
|     return kErrorOk; | ||||
|   return _hint(var, kVarHintSave, kInvalidValue); | ||||
| } | ||||
| 
 | ||||
| Error Compiler::spill(Var& var) noexcept { | ||||
|   if (var.getId() == kInvalidValue) | ||||
|     return kErrorOk; | ||||
|   return _hint(var, kVarHintSpill, kInvalidValue); | ||||
| } | ||||
| 
 | ||||
| Error Compiler::unuse(Var& var) noexcept { | ||||
|   if (var.getId() == kInvalidValue) | ||||
|     return kErrorOk; | ||||
|   return _hint(var, kVarHintUnuse, kInvalidValue); | ||||
| } | ||||
| 
 | ||||
| uint32_t Compiler::getPriority(Var& var) const noexcept { | ||||
|   if (var.getId() == kInvalidValue) | ||||
|     return kInvalidValue; | ||||
| 
 | ||||
|   VarData* vd = getVdById(var.getId()); | ||||
|   return vd->getPriority(); | ||||
| } | ||||
| 
 | ||||
| void Compiler::setPriority(Var& var, uint32_t priority) noexcept { | ||||
|   if (var.getId() == kInvalidValue) | ||||
|     return; | ||||
| 
 | ||||
|   if (priority > 255) | ||||
|     priority = 255; | ||||
| 
 | ||||
|   VarData* vd = getVdById(var.getId()); | ||||
|   vd->_priority = static_cast<uint8_t>(priority); | ||||
| } | ||||
| 
 | ||||
| bool Compiler::getSaveOnUnuse(Var& var) const noexcept { | ||||
|   if (var.getId() == kInvalidValue) | ||||
|     return false; | ||||
| 
 | ||||
|   VarData* vd = getVdById(var.getId()); | ||||
|   return static_cast<bool>(vd->_saveOnUnuse); | ||||
| } | ||||
| 
 | ||||
| void Compiler::setSaveOnUnuse(Var& var, bool value) noexcept { | ||||
|   if (var.getId() == kInvalidValue) | ||||
|     return; | ||||
| 
 | ||||
|   VarData* vd = getVdById(var.getId()); | ||||
|   vd->_saveOnUnuse = value; | ||||
| } | ||||
| 
 | ||||
| void Compiler::rename(Var& var, const char* fmt, ...) noexcept { | ||||
|   if (var.getId() == kInvalidValue) | ||||
|     return; | ||||
| 
 | ||||
|   VarData* vd = getVdById(var.getId()); | ||||
|   vd->_name = noName; | ||||
| 
 | ||||
|   if (fmt != nullptr && fmt[0] != '\0') { | ||||
|     char buf[64]; | ||||
| 
 | ||||
|     va_list ap; | ||||
|     va_start(ap, fmt); | ||||
| 
 | ||||
|     vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap); | ||||
|     buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0'; | ||||
| 
 | ||||
|     vd->_name = _stringAllocator.sdup(buf); | ||||
|     va_end(ap); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // !ASMJIT_DISABLE_COMPILER
 | ||||
							
								
								
									
										576
									
								
								DynamicHooks/thirdparty/AsmJit/base/compiler.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										576
									
								
								DynamicHooks/thirdparty/AsmJit/base/compiler.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,576 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_BASE_COMPILER_H | ||||
| #define _ASMJIT_BASE_COMPILER_H | ||||
| 
 | ||||
| #include "../build.h" | ||||
| #if !defined(ASMJIT_DISABLE_COMPILER) | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/assembler.h" | ||||
| #include "../base/compilerfunc.h" | ||||
| #include "../base/constpool.h" | ||||
| #include "../base/containers.h" | ||||
| #include "../base/hlstream.h" | ||||
| #include "../base/operand.h" | ||||
| #include "../base/podvector.h" | ||||
| #include "../base/utils.h" | ||||
| #include "../base/zone.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [Forward Declarations]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| struct VarAttr; | ||||
| struct VarData; | ||||
| struct VarMap; | ||||
| struct VarState; | ||||
| 
 | ||||
| //! \addtogroup asmjit_base
 | ||||
| //! \{
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::CompilerFeatures]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| ASMJIT_ENUM(CompilerFeatures) { | ||||
|   //! Schedule instructions so they can be executed faster (`Compiler` only).
 | ||||
|   //!
 | ||||
|   //! Default `false` - has to be explicitly enabled as the scheduler needs
 | ||||
|   //! some time to run.
 | ||||
|   //!
 | ||||
|   //! X86/X64 Specific
 | ||||
|   //! ----------------
 | ||||
|   //!
 | ||||
|   //! If scheduling is enabled AsmJit will try to reorder instructions to
 | ||||
|   //! minimize the dependency chain. Scheduler always runs after the registers
 | ||||
|   //! are allocated so it doesn't change count of register allocs/spills.
 | ||||
|   //!
 | ||||
|   //! This feature is highly experimental and untested.
 | ||||
|   kCompilerFeatureEnableScheduler = 0 | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::ConstScope]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Scope of the constant.
 | ||||
| ASMJIT_ENUM(ConstScope) { | ||||
|   //! Local constant, always embedded right after the current function.
 | ||||
|   kConstScopeLocal = 0, | ||||
|   //! Global constant, embedded at the end of the currently compiled code.
 | ||||
|   kConstScopeGlobal = 1 | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::VarInfo]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| struct VarInfo { | ||||
|   // ============================================================================
 | ||||
|   // [Flags]
 | ||||
|   // ============================================================================
 | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Variable flags.
 | ||||
|   ASMJIT_ENUM(Flags) { | ||||
|     //! Variable contains one or more single-precision floating point.
 | ||||
|     kFlagSP = 0x10, | ||||
|     //! Variable contains one or more double-precision floating point.
 | ||||
|     kFlagDP = 0x20, | ||||
|     //! Variable is a vector, contains packed data.
 | ||||
|     kFlagSIMD = 0x80 | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get type id.
 | ||||
|   ASMJIT_INLINE uint32_t getTypeId() const noexcept { return _typeId; } | ||||
|   //! Get type name.
 | ||||
|   ASMJIT_INLINE const char* getTypeName() const noexcept { return _typeName; } | ||||
| 
 | ||||
|   //! Get register size in bytes.
 | ||||
|   ASMJIT_INLINE uint32_t getSize() const noexcept { return _size; } | ||||
|   //! Get variable class, see \ref RegClass.
 | ||||
|   ASMJIT_INLINE uint32_t getRegClass() const noexcept { return _regClass; } | ||||
|   //! Get register type, see `X86RegType`.
 | ||||
|   ASMJIT_INLINE uint32_t getRegType() const noexcept { return _regType; } | ||||
|   //! Get type flags, see `VarFlag`.
 | ||||
|   ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Variable type id.
 | ||||
|   uint8_t _typeId; | ||||
|   //! Variable and register size (in bytes).
 | ||||
|   uint8_t _size; | ||||
|   //! Register class, see `RegClass`.
 | ||||
|   uint8_t _regClass; | ||||
|   //! Register type the variable is mapped to.
 | ||||
|   uint8_t _regType; | ||||
| 
 | ||||
|   //! Variable info flags, see \ref Flags.
 | ||||
|   uint32_t _flags; | ||||
| 
 | ||||
|   //! Variable type name.
 | ||||
|   char _typeName[8]; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Compiler]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Compiler interface.
 | ||||
| //!
 | ||||
| //! \sa Assembler.
 | ||||
| class ASMJIT_VIRTAPI Compiler : public ExternalTool { | ||||
|  public: | ||||
|   ASMJIT_NO_COPY(Compiler) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Create a new `Compiler` instance.
 | ||||
|   ASMJIT_API Compiler() noexcept; | ||||
|   //! Destroy the `Compiler` instance.
 | ||||
|   ASMJIT_API virtual ~Compiler() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Reset]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! \override
 | ||||
|   ASMJIT_API virtual void reset(bool releaseMemory) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Compiler Features]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get code-generator features.
 | ||||
|   ASMJIT_INLINE uint32_t getFeatures() const noexcept { | ||||
|     return _features; | ||||
|   } | ||||
|   //! Set code-generator features.
 | ||||
|   ASMJIT_INLINE void setFeatures(uint32_t features) noexcept { | ||||
|     _features = features; | ||||
|   } | ||||
| 
 | ||||
|   //! Get code-generator `feature`.
 | ||||
|   ASMJIT_INLINE bool hasFeature(uint32_t feature) const noexcept { | ||||
|     ASMJIT_ASSERT(feature < 32); | ||||
|     return (_features & (1 << feature)) != 0; | ||||
|   } | ||||
| 
 | ||||
|   //! Set code-generator `feature` to `value`.
 | ||||
|   ASMJIT_INLINE void setFeature(uint32_t feature, bool value) noexcept { | ||||
|     ASMJIT_ASSERT(feature < 32); | ||||
|     feature = static_cast<uint32_t>(value) << feature; | ||||
|     _features = (_features & ~feature) | feature; | ||||
|   } | ||||
| 
 | ||||
|   //! Get maximum look ahead.
 | ||||
|   ASMJIT_INLINE uint32_t getMaxLookAhead() const noexcept { | ||||
|     return _maxLookAhead; | ||||
|   } | ||||
|   //! Set maximum look ahead to `val`.
 | ||||
|   ASMJIT_INLINE void setMaxLookAhead(uint32_t val) noexcept { | ||||
|     _maxLookAhead = val; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Token ID]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Reset the token-id generator.
 | ||||
|   ASMJIT_INLINE void _resetTokenGenerator() noexcept { | ||||
|     _tokenGenerator = 0; | ||||
|   } | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Generate a new unique token id.
 | ||||
|   ASMJIT_INLINE uint32_t _generateUniqueToken() noexcept { | ||||
|     return ++_tokenGenerator; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Instruction Options]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get options of the next instruction.
 | ||||
|   ASMJIT_INLINE uint32_t getInstOptions() const noexcept { | ||||
|     return _instOptions; | ||||
|   } | ||||
|   //! Set options of the next instruction.
 | ||||
|   ASMJIT_INLINE void setInstOptions(uint32_t instOptions) noexcept { | ||||
|     _instOptions = instOptions; | ||||
|   } | ||||
| 
 | ||||
|   //! Get options of the next instruction and reset them.
 | ||||
|   ASMJIT_INLINE uint32_t getInstOptionsAndReset() { | ||||
|     uint32_t instOptions = _instOptions; | ||||
|     _instOptions = 0; | ||||
|     return instOptions; | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Node-Factory]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   template<typename T> | ||||
|   ASMJIT_INLINE T* newNode() noexcept { | ||||
|     void* p = _zoneAllocator.alloc(sizeof(T)); | ||||
|     return new(p) T(this); | ||||
|   } | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   template<typename T, typename P0> | ||||
|   ASMJIT_INLINE T* newNode(P0 p0) noexcept { | ||||
|     void* p = _zoneAllocator.alloc(sizeof(T)); | ||||
|     return new(p) T(this, p0); | ||||
|   } | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   template<typename T, typename P0, typename P1> | ||||
|   ASMJIT_INLINE T* newNode(P0 p0, P1 p1) noexcept { | ||||
|     void* p = _zoneAllocator.alloc(sizeof(T)); | ||||
|     return new(p) T(this, p0, p1); | ||||
|   } | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   template<typename T, typename P0, typename P1, typename P2> | ||||
|   ASMJIT_INLINE T* newNode(P0 p0, P1 p1, P2 p2) noexcept { | ||||
|     void* p = _zoneAllocator.alloc(sizeof(T)); | ||||
|     return new(p) T(this, p0, p1, p2); | ||||
|   } | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Create a new `HLData` node.
 | ||||
|   ASMJIT_API HLData* newDataNode(const void* data, uint32_t size) noexcept; | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Create a new `HLAlign` node.
 | ||||
|   ASMJIT_API HLAlign* newAlignNode(uint32_t alignMode, uint32_t offset) noexcept; | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Create a new `HLLabel` node.
 | ||||
|   ASMJIT_API HLLabel* newLabelNode() noexcept; | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Create a new `HLComment`.
 | ||||
|   ASMJIT_API HLComment* newCommentNode(const char* str) noexcept; | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Create a new `HLHint`.
 | ||||
|   ASMJIT_API HLHint* newHintNode(Var& var, uint32_t hint, uint32_t value) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Code-Stream]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Add a function `node` to the stream.
 | ||||
|   ASMJIT_API HLNode* addFunc(HLFunc* func) noexcept; | ||||
| 
 | ||||
|   //! Add node `node` after current and set current to `node`.
 | ||||
|   ASMJIT_API HLNode* addNode(HLNode* node) noexcept; | ||||
|   //! Insert `node` before `ref`.
 | ||||
|   ASMJIT_API HLNode* addNodeBefore(HLNode* node, HLNode* ref) noexcept; | ||||
|   //! Insert `node` after `ref`.
 | ||||
|   ASMJIT_API HLNode* addNodeAfter(HLNode* node, HLNode* ref) noexcept; | ||||
|   //! Remove `node`.
 | ||||
|   ASMJIT_API HLNode* removeNode(HLNode* node) noexcept; | ||||
|   //! Remove multiple nodes.
 | ||||
|   ASMJIT_API void removeNodes(HLNode* first, HLNode* last) noexcept; | ||||
| 
 | ||||
|   //! Get the first node.
 | ||||
|   ASMJIT_INLINE HLNode* getFirstNode() const noexcept { return _firstNode; } | ||||
|   //! Get the last node.
 | ||||
|   ASMJIT_INLINE HLNode* getLastNode() const noexcept { return _lastNode; } | ||||
| 
 | ||||
|   //! Get current node.
 | ||||
|   //!
 | ||||
|   //! \note If this method returns `nullptr` it means that nothing has been
 | ||||
|   //! emitted yet.
 | ||||
|   ASMJIT_INLINE HLNode* getCursor() const noexcept { return _cursor; } | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Set the current node without returning the previous node.
 | ||||
|   ASMJIT_INLINE void _setCursor(HLNode* node) noexcept { _cursor = node; } | ||||
|   //! Set the current node to `node` and return the previous one.
 | ||||
|   ASMJIT_API HLNode* setCursor(HLNode* node) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Func]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get current function.
 | ||||
|   ASMJIT_INLINE HLFunc* getFunc() const noexcept { return _func; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Align]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Align target buffer to the `offset` specified.
 | ||||
|   //!
 | ||||
|   //! The sequence that is used to fill the gap between the aligned location
 | ||||
|   //! and the current depends on `alignMode`, see \ref AlignMode.
 | ||||
|   ASMJIT_API Error align(uint32_t alignMode, uint32_t offset) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Label]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get `HLLabel` by `id`.
 | ||||
|   //!
 | ||||
|   //! NOTE: The label has to be valid, see `isLabelValid()`.
 | ||||
|   ASMJIT_API HLLabel* getHLLabel(uint32_t id) const noexcept; | ||||
| 
 | ||||
|   //! Get `HLLabel` by `label`.
 | ||||
|   //!
 | ||||
|   //! NOTE: The label has to be valid, see `isLabelValid()`.
 | ||||
|   ASMJIT_INLINE HLLabel* getHLLabel(const Label& label) noexcept { | ||||
|     return getHLLabel(label.getId()); | ||||
|   } | ||||
| 
 | ||||
|   //! Get whether the label `id` is valid.
 | ||||
|   ASMJIT_API bool isLabelValid(uint32_t id) const noexcept; | ||||
|   //! Get whether the `label` is valid.
 | ||||
|   ASMJIT_INLINE bool isLabelValid(const Label& label) const noexcept { | ||||
|     return isLabelValid(label.getId()); | ||||
|   } | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Create a new label and return its ID.
 | ||||
|   ASMJIT_API uint32_t _newLabelId() noexcept; | ||||
| 
 | ||||
|   //! Create and return a new `Label`.
 | ||||
|   ASMJIT_INLINE Label newLabel() noexcept { return Label(_newLabelId()); } | ||||
| 
 | ||||
|   //! Bind label to the current offset.
 | ||||
|   //!
 | ||||
|   //! NOTE: Label can be bound only once!
 | ||||
|   ASMJIT_API Error bind(const Label& label) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Embed]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Embed data.
 | ||||
|   ASMJIT_API Error embed(const void* data, uint32_t size) noexcept; | ||||
| 
 | ||||
|   //! Embed a constant pool data, adding the following in order:
 | ||||
|   //!   1. Data alignment.
 | ||||
|   //!   2. Label.
 | ||||
|   //!   3. Constant pool data.
 | ||||
|   ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Comment]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Emit a single comment line.
 | ||||
|   ASMJIT_API Error comment(const char* fmt, ...) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Hint]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Emit a new hint (purery informational node).
 | ||||
|   ASMJIT_API Error _hint(Var& var, uint32_t hint, uint32_t value) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Vars]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get whether variable `var` is created.
 | ||||
|   ASMJIT_INLINE bool isVarValid(const Var& var) const noexcept { | ||||
|     return static_cast<size_t>(var.getId() & Operand::kIdIndexMask) < _varList.getLength(); | ||||
|   } | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Get `VarData` by `var`.
 | ||||
|   ASMJIT_INLINE VarData* getVd(const Var& var) const noexcept { | ||||
|     return getVdById(var.getId()); | ||||
|   } | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Get `VarData` by `id`.
 | ||||
|   ASMJIT_INLINE VarData* getVdById(uint32_t id) const noexcept { | ||||
|     ASMJIT_ASSERT(id != kInvalidValue); | ||||
|     ASMJIT_ASSERT(static_cast<size_t>(id & Operand::kIdIndexMask) < _varList.getLength()); | ||||
| 
 | ||||
|     return _varList[id & Operand::kIdIndexMask]; | ||||
|   } | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Get an array of 'VarData*'.
 | ||||
|   ASMJIT_INLINE VarData** _getVdArray() const noexcept { | ||||
|     return const_cast<VarData**>(_varList.getData()); | ||||
|   } | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Create a new `VarData`.
 | ||||
|   ASMJIT_API VarData* _newVd(const VarInfo& vi, const char* name) noexcept; | ||||
| 
 | ||||
|   //! Alloc variable `var`.
 | ||||
|   ASMJIT_API Error alloc(Var& var) noexcept; | ||||
|   //! Alloc variable `var` using `regIndex` as a register index.
 | ||||
|   ASMJIT_API Error alloc(Var& var, uint32_t regIndex) noexcept; | ||||
|   //! Alloc variable `var` using `reg` as a register operand.
 | ||||
|   ASMJIT_API Error alloc(Var& var, const Reg& reg) noexcept; | ||||
|   //! Spill variable `var`.
 | ||||
|   ASMJIT_API Error spill(Var& var) noexcept; | ||||
|   //! Save variable `var` if the status is `modified` at this point.
 | ||||
|   ASMJIT_API Error save(Var& var) noexcept; | ||||
|   //! Unuse variable `var`.
 | ||||
|   ASMJIT_API Error unuse(Var& var) noexcept; | ||||
| 
 | ||||
|   //! Get priority of variable `var`.
 | ||||
|   ASMJIT_API uint32_t getPriority(Var& var) const noexcept; | ||||
|   //! Set priority of variable `var` to `priority`.
 | ||||
|   ASMJIT_API void setPriority(Var& var, uint32_t priority) noexcept; | ||||
| 
 | ||||
|   //! Get save-on-unuse `var` property.
 | ||||
|   ASMJIT_API bool getSaveOnUnuse(Var& var) const noexcept; | ||||
|   //! Set save-on-unuse `var` property to `value`.
 | ||||
|   ASMJIT_API void setSaveOnUnuse(Var& var, bool value) noexcept; | ||||
| 
 | ||||
|   //! Rename variable `var` to `name`.
 | ||||
|   //!
 | ||||
|   //! NOTE: Only new name will appear in the logger.
 | ||||
|   ASMJIT_API void rename(Var& var, const char* fmt, ...) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Stack]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Create a new memory chunk allocated on the current function's stack.
 | ||||
|   virtual Error _newStack(BaseMem* mem, uint32_t size, uint32_t alignment, const char* name) noexcept = 0; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Const]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Put data to a constant-pool and get a memory reference to it.
 | ||||
|   virtual Error _newConst(BaseMem* mem, uint32_t scope, const void* data, size_t size) noexcept = 0; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Code-Generation features, used by \ref hasFeature() and \ref setFeature().
 | ||||
|   uint32_t _features; | ||||
|   //! Maximum count of nodes to look ahead when allocating/spilling
 | ||||
|   //! registers.
 | ||||
|   uint32_t _maxLookAhead; | ||||
| 
 | ||||
|   //! Options affecting the next instruction.
 | ||||
|   uint32_t _instOptions; | ||||
|   //! Processing token generator.
 | ||||
|   //!
 | ||||
|   //! Used to get a unique token that is then used to process `HLNode`s. See
 | ||||
|   //! `Compiler::_getUniqueToken()` for more details.
 | ||||
|   uint32_t _tokenGenerator; | ||||
| 
 | ||||
|   //! Flow id added to each node created (used only by `Context)`.
 | ||||
|   uint32_t _nodeFlowId; | ||||
|   //! Flags added to each node created (used only by `Context)`.
 | ||||
|   uint32_t _nodeFlags; | ||||
| 
 | ||||
|   //! Variable mapping (translates incoming VarType into target).
 | ||||
|   const uint8_t* _targetVarMapping; | ||||
| 
 | ||||
|   //! First node.
 | ||||
|   HLNode* _firstNode; | ||||
|   //! Last node.
 | ||||
|   HLNode* _lastNode; | ||||
| 
 | ||||
|   //! Current node.
 | ||||
|   HLNode* _cursor; | ||||
|   //! Current function.
 | ||||
|   HLFunc* _func; | ||||
| 
 | ||||
|   //! General purpose zone allocator.
 | ||||
|   Zone _zoneAllocator; | ||||
|   //! Variable zone.
 | ||||
|   Zone _varAllocator; | ||||
|   //! String/data zone.
 | ||||
|   Zone _stringAllocator; | ||||
|   //! Local constant pool zone.
 | ||||
|   Zone _constAllocator; | ||||
| 
 | ||||
|   //! VarData list.
 | ||||
|   PodVector<VarData*> _varList; | ||||
| 
 | ||||
|   //! Local constant pool, flushed at the end of each function.
 | ||||
|   ConstPool _localConstPool; | ||||
|   //! Global constant pool, flushed at the end of the compilation.
 | ||||
|   ConstPool _globalConstPool; | ||||
| 
 | ||||
|   //! Label to start of the local constant pool.
 | ||||
|   Label _localConstPoolLabel; | ||||
|   //! Label to start of the global constant pool.
 | ||||
|   Label _globalConstPoolLabel; | ||||
| }; | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [Defined-Later]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| ASMJIT_INLINE HLNode::HLNode(Compiler* compiler, uint32_t type) noexcept { | ||||
|   _prev = nullptr; | ||||
|   _next = nullptr; | ||||
|   _type = static_cast<uint8_t>(type); | ||||
|   _opCount = 0; | ||||
|   _flags = static_cast<uint16_t>(compiler->_nodeFlags); | ||||
|   _flowId = compiler->_nodeFlowId; | ||||
|   _tokenId = 0; | ||||
|   _comment = nullptr; | ||||
|   _map = nullptr; | ||||
|   _liveness = nullptr; | ||||
|   _state = nullptr; | ||||
| } | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // !ASMJIT_DISABLE_COMPILER
 | ||||
| #endif // _ASMJIT_BASE_COMPILER_H
 | ||||
							
								
								
									
										653
									
								
								DynamicHooks/thirdparty/AsmJit/base/compilercontext.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										653
									
								
								DynamicHooks/thirdparty/AsmJit/base/compilercontext.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,653 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #include "../build.h" | ||||
| #if !defined(ASMJIT_DISABLE_COMPILER) | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/compilercontext_p.h" | ||||
| #include "../base/utils.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Context - Construction / Destruction]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Context::Context(Compiler* compiler) : | ||||
|   _compiler(compiler), | ||||
|   _zoneAllocator(8192 - Zone::kZoneOverhead), | ||||
|   _traceNode(nullptr), | ||||
|   _varMapToVaListOffset(0) { | ||||
| 
 | ||||
|   Context::reset(); | ||||
| } | ||||
| Context::~Context() {} | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Context - Reset]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void Context::reset(bool releaseMemory) { | ||||
|   _zoneAllocator.reset(releaseMemory); | ||||
| 
 | ||||
|   _func = nullptr; | ||||
|   _start = nullptr; | ||||
|   _end = nullptr; | ||||
|   _extraBlock = nullptr; | ||||
|   _stop = nullptr; | ||||
| 
 | ||||
|   _unreachableList.reset(); | ||||
|   _returningList.reset(); | ||||
|   _jccList.reset(); | ||||
|   _contextVd.reset(releaseMemory); | ||||
| 
 | ||||
|   _memVarCells = nullptr; | ||||
|   _memStackCells = nullptr; | ||||
| 
 | ||||
|   _mem1ByteVarsUsed = 0; | ||||
|   _mem2ByteVarsUsed = 0; | ||||
|   _mem4ByteVarsUsed = 0; | ||||
|   _mem8ByteVarsUsed = 0; | ||||
|   _mem16ByteVarsUsed = 0; | ||||
|   _mem32ByteVarsUsed = 0; | ||||
|   _mem64ByteVarsUsed = 0; | ||||
|   _memStackCellsUsed = 0; | ||||
| 
 | ||||
|   _memMaxAlign = 0; | ||||
|   _memVarTotal = 0; | ||||
|   _memStackTotal = 0; | ||||
|   _memAllTotal = 0; | ||||
|   _annotationLength = 12; | ||||
| 
 | ||||
|   _state = nullptr; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Context - Mem]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| static ASMJIT_INLINE uint32_t BaseContext_getDefaultAlignment(uint32_t size) { | ||||
|   if (size > 32) | ||||
|     return 64; | ||||
|   else if (size > 16) | ||||
|     return 32; | ||||
|   else if (size > 8) | ||||
|     return 16; | ||||
|   else if (size > 4) | ||||
|     return 8; | ||||
|   else if (size > 2) | ||||
|     return 4; | ||||
|   else if (size > 1) | ||||
|     return 2; | ||||
|   else | ||||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| VarCell* Context::_newVarCell(VarData* vd) { | ||||
|   ASMJIT_ASSERT(vd->_memCell == nullptr); | ||||
| 
 | ||||
|   VarCell* cell; | ||||
|   uint32_t size = vd->getSize(); | ||||
| 
 | ||||
|   if (vd->isStack()) { | ||||
|     cell = _newStackCell(size, vd->getAlignment()); | ||||
| 
 | ||||
|     if (cell == nullptr) | ||||
|       return nullptr; | ||||
|   } | ||||
|   else { | ||||
|     cell = static_cast<VarCell*>(_zoneAllocator.alloc(sizeof(VarCell))); | ||||
|     if (cell == nullptr) | ||||
|       goto _NoMemory; | ||||
| 
 | ||||
|     cell->_next = _memVarCells; | ||||
|     _memVarCells = cell; | ||||
| 
 | ||||
|     cell->_offset = 0; | ||||
|     cell->_size = size; | ||||
|     cell->_alignment = size; | ||||
| 
 | ||||
|     _memMaxAlign = Utils::iMax<uint32_t>(_memMaxAlign, size); | ||||
|     _memVarTotal += size; | ||||
| 
 | ||||
|     switch (size) { | ||||
|       case  1: _mem1ByteVarsUsed++ ; break; | ||||
|       case  2: _mem2ByteVarsUsed++ ; break; | ||||
|       case  4: _mem4ByteVarsUsed++ ; break; | ||||
|       case  8: _mem8ByteVarsUsed++ ; break; | ||||
|       case 16: _mem16ByteVarsUsed++; break; | ||||
|       case 32: _mem32ByteVarsUsed++; break; | ||||
|       case 64: _mem64ByteVarsUsed++; break; | ||||
| 
 | ||||
|       default: | ||||
|         ASMJIT_NOT_REACHED(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   vd->_memCell = cell; | ||||
|   return cell; | ||||
| 
 | ||||
| _NoMemory: | ||||
|   _compiler->setLastError(kErrorNoHeapMemory); | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| VarCell* Context::_newStackCell(uint32_t size, uint32_t alignment) { | ||||
|   VarCell* cell = static_cast<VarCell*>(_zoneAllocator.alloc(sizeof(VarCell))); | ||||
|   if (cell == nullptr) | ||||
|     goto _NoMemory; | ||||
| 
 | ||||
|   if (alignment == 0) | ||||
|     alignment = BaseContext_getDefaultAlignment(size); | ||||
| 
 | ||||
|   if (alignment > 64) | ||||
|     alignment = 64; | ||||
| 
 | ||||
|   ASMJIT_ASSERT(Utils::isPowerOf2(alignment)); | ||||
|   size = Utils::alignTo<uint32_t>(size, alignment); | ||||
| 
 | ||||
|   // Insert it sorted according to the alignment and size.
 | ||||
|   { | ||||
|     VarCell** pPrev = &_memStackCells; | ||||
|     VarCell* cur = *pPrev; | ||||
| 
 | ||||
|     while (cur != nullptr) { | ||||
|       if ((cur->getAlignment() > alignment) || | ||||
|           (cur->getAlignment() == alignment && cur->getSize() > size)) { | ||||
|         pPrev = &cur->_next; | ||||
|         cur = *pPrev; | ||||
|         continue; | ||||
|       } | ||||
| 
 | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|     cell->_next = cur; | ||||
|     cell->_offset = 0; | ||||
|     cell->_size = size; | ||||
|     cell->_alignment = alignment; | ||||
| 
 | ||||
|     *pPrev = cell; | ||||
|     _memStackCellsUsed++; | ||||
| 
 | ||||
|     _memMaxAlign = Utils::iMax<uint32_t>(_memMaxAlign, alignment); | ||||
|     _memStackTotal += size; | ||||
|   } | ||||
| 
 | ||||
|   return cell; | ||||
| 
 | ||||
| _NoMemory: | ||||
|   _compiler->setLastError(kErrorNoHeapMemory); | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| Error Context::resolveCellOffsets() { | ||||
|   VarCell* varCell = _memVarCells; | ||||
|   VarCell* stackCell = _memStackCells; | ||||
| 
 | ||||
|   uint32_t stackAlignment = 0; | ||||
|   if (stackCell != nullptr) | ||||
|     stackAlignment = stackCell->getAlignment(); | ||||
| 
 | ||||
|   uint32_t pos64 = 0; | ||||
|   uint32_t pos32 = pos64 + _mem64ByteVarsUsed * 64; | ||||
|   uint32_t pos16 = pos32 + _mem32ByteVarsUsed * 32; | ||||
|   uint32_t pos8  = pos16 + _mem16ByteVarsUsed * 16; | ||||
|   uint32_t pos4  = pos8  + _mem8ByteVarsUsed  * 8 ; | ||||
|   uint32_t pos2  = pos4  + _mem4ByteVarsUsed  * 4 ; | ||||
|   uint32_t pos1  = pos2  + _mem2ByteVarsUsed  * 2 ; | ||||
| 
 | ||||
|   uint32_t stackPos = pos1 + _mem1ByteVarsUsed; | ||||
| 
 | ||||
|   uint32_t gapAlignment = stackAlignment; | ||||
|   uint32_t gapSize = 0; | ||||
| 
 | ||||
|   // TODO: Not used!
 | ||||
|   if (gapAlignment) | ||||
|     Utils::alignDiff(stackPos, gapAlignment); | ||||
|   stackPos += gapSize; | ||||
| 
 | ||||
|   uint32_t gapPos = stackPos; | ||||
|   uint32_t allTotal = stackPos; | ||||
| 
 | ||||
|   // Vars - Allocated according to alignment/width.
 | ||||
|   while (varCell != nullptr) { | ||||
|     uint32_t size = varCell->getSize(); | ||||
|     uint32_t offset = 0; | ||||
| 
 | ||||
|     switch (size) { | ||||
|       case  1: offset = pos1 ; pos1  += 1 ; break; | ||||
|       case  2: offset = pos2 ; pos2  += 2 ; break; | ||||
|       case  4: offset = pos4 ; pos4  += 4 ; break; | ||||
|       case  8: offset = pos8 ; pos8  += 8 ; break; | ||||
|       case 16: offset = pos16; pos16 += 16; break; | ||||
|       case 32: offset = pos32; pos32 += 32; break; | ||||
|       case 64: offset = pos64; pos64 += 64; break; | ||||
| 
 | ||||
|       default: | ||||
|         ASMJIT_NOT_REACHED(); | ||||
|     } | ||||
| 
 | ||||
|     varCell->setOffset(static_cast<int32_t>(offset)); | ||||
|     varCell = varCell->_next; | ||||
|   } | ||||
| 
 | ||||
|   // Stack - Allocated according to alignment/width.
 | ||||
|   while (stackCell != nullptr) { | ||||
|     uint32_t size = stackCell->getSize(); | ||||
|     uint32_t alignment = stackCell->getAlignment(); | ||||
|     uint32_t offset; | ||||
| 
 | ||||
|     // Try to fill the gap between variables/stack first.
 | ||||
|     if (size <= gapSize && alignment <= gapAlignment) { | ||||
|       offset = gapPos; | ||||
| 
 | ||||
|       gapSize -= size; | ||||
|       gapPos -= size; | ||||
| 
 | ||||
|       if (alignment < gapAlignment) | ||||
|         gapAlignment = alignment; | ||||
|     } | ||||
|     else { | ||||
|       offset = stackPos; | ||||
| 
 | ||||
|       stackPos += size; | ||||
|       allTotal += size; | ||||
|     } | ||||
| 
 | ||||
|     stackCell->setOffset(offset); | ||||
|     stackCell = stackCell->_next; | ||||
|   } | ||||
| 
 | ||||
|   _memAllTotal = allTotal; | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Context - RemoveUnreachableCode]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error Context::removeUnreachableCode() { | ||||
|   Compiler* compiler = getCompiler(); | ||||
| 
 | ||||
|   PodList<HLNode*>::Link* link = _unreachableList.getFirst(); | ||||
|   HLNode* stop = getStop(); | ||||
| 
 | ||||
|   while (link != nullptr) { | ||||
|     HLNode* node = link->getValue(); | ||||
|     if (node != nullptr && node->getPrev() != nullptr && node != stop) { | ||||
|       // Locate all unreachable nodes.
 | ||||
|       HLNode* first = node; | ||||
|       do { | ||||
|         if (node->isFetched()) | ||||
|           break; | ||||
|         node = node->getNext(); | ||||
|       } while (node != stop); | ||||
| 
 | ||||
|       // Remove unreachable nodes that are neither informative nor directives.
 | ||||
|       if (node != first) { | ||||
|         HLNode* end = node; | ||||
|         node = first; | ||||
| 
 | ||||
|         // NOTE: The strategy is as follows:
 | ||||
|         // 1. The algorithm removes everything until it finds a first label.
 | ||||
|         // 2. After the first label is found it removes only removable nodes.
 | ||||
|         bool removeEverything = true; | ||||
|         do { | ||||
|           HLNode* next = node->getNext(); | ||||
|           bool remove = node->isRemovable(); | ||||
| 
 | ||||
|           if (!remove) { | ||||
|             if (node->isLabel()) | ||||
|               removeEverything = false; | ||||
|             remove = removeEverything; | ||||
|           } | ||||
| 
 | ||||
|           if (remove) { | ||||
|             ASMJIT_TSEC({ | ||||
|               this->_traceNode(this, node, "[REMOVED UNREACHABLE] "); | ||||
|             }); | ||||
|             compiler->removeNode(node); | ||||
|           } | ||||
| 
 | ||||
|           node = next; | ||||
|         } while (node != end); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     link = link->getNext(); | ||||
|   } | ||||
| 
 | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Context - Liveness Analysis]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! \internal
 | ||||
| struct LivenessTarget { | ||||
|   //! Previous target.
 | ||||
|   LivenessTarget* prev; | ||||
| 
 | ||||
|   //! Target node.
 | ||||
|   HLLabel* node; | ||||
|   //! Jumped from.
 | ||||
|   HLJump* from; | ||||
| }; | ||||
| 
 | ||||
| Error Context::livenessAnalysis() { | ||||
|   uint32_t bLen = static_cast<uint32_t>( | ||||
|     ((_contextVd.getLength() + BitArray::kEntityBits - 1) / BitArray::kEntityBits)); | ||||
| 
 | ||||
|   // No variables.
 | ||||
|   if (bLen == 0) | ||||
|     return kErrorOk; | ||||
| 
 | ||||
|   HLFunc* func = getFunc(); | ||||
|   HLJump* from = nullptr; | ||||
| 
 | ||||
|   LivenessTarget* ltCur = nullptr; | ||||
|   LivenessTarget* ltUnused = nullptr; | ||||
| 
 | ||||
|   PodList<HLNode*>::Link* retPtr = _returningList.getFirst(); | ||||
|   ASMJIT_ASSERT(retPtr != nullptr); | ||||
| 
 | ||||
|   HLNode* node = retPtr->getValue(); | ||||
| 
 | ||||
|   size_t varMapToVaListOffset = _varMapToVaListOffset; | ||||
|   BitArray* bCur = newBits(bLen); | ||||
| 
 | ||||
|   if (bCur == nullptr) | ||||
|     goto _NoMemory; | ||||
| 
 | ||||
|   // Allocate bits for code visited first time.
 | ||||
| _OnVisit: | ||||
|   for (;;) { | ||||
|     if (node->hasLiveness()) { | ||||
|       if (bCur->_addBitsDelSource(node->getLiveness(), bCur, bLen)) | ||||
|         goto _OnPatch; | ||||
|       else | ||||
|         goto _OnDone; | ||||
|     } | ||||
| 
 | ||||
|     BitArray* bTmp = copyBits(bCur, bLen); | ||||
|     if (bTmp == nullptr) | ||||
|       goto _NoMemory; | ||||
| 
 | ||||
|     node->setLiveness(bTmp); | ||||
|     VarMap* map = node->getMap(); | ||||
| 
 | ||||
|     if (map != nullptr) { | ||||
|       uint32_t vaCount = map->getVaCount(); | ||||
|       VarAttr* vaList = reinterpret_cast<VarAttr*>(((uint8_t*)map) + varMapToVaListOffset); | ||||
| 
 | ||||
|       for (uint32_t i = 0; i < vaCount; i++) { | ||||
|         VarAttr* va = &vaList[i]; | ||||
|         VarData* vd = va->getVd(); | ||||
| 
 | ||||
|         uint32_t flags = va->getFlags(); | ||||
|         uint32_t localId = vd->getLocalId(); | ||||
| 
 | ||||
|         if ((flags & kVarAttrWAll) && !(flags & kVarAttrRAll)) { | ||||
|           // Write-Only.
 | ||||
|           bTmp->setBit(localId); | ||||
|           bCur->delBit(localId); | ||||
|         } | ||||
|         else { | ||||
|           // Read-Only or Read/Write.
 | ||||
|           bTmp->setBit(localId); | ||||
|           bCur->setBit(localId); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (node->getType() == HLNode::kTypeLabel) | ||||
|       goto _OnTarget; | ||||
| 
 | ||||
|     if (node == func) | ||||
|       goto _OnDone; | ||||
| 
 | ||||
|     ASMJIT_ASSERT(node->getPrev()); | ||||
|     node = node->getPrev(); | ||||
|   } | ||||
| 
 | ||||
|   // Patch already generated liveness bits.
 | ||||
| _OnPatch: | ||||
|   for (;;) { | ||||
|     ASMJIT_ASSERT(node->hasLiveness()); | ||||
|     BitArray* bNode = node->getLiveness(); | ||||
| 
 | ||||
|     if (!bNode->_addBitsDelSource(bCur, bLen)) | ||||
|       goto _OnDone; | ||||
| 
 | ||||
|     if (node->getType() == HLNode::kTypeLabel) | ||||
|       goto _OnTarget; | ||||
| 
 | ||||
|     if (node == func) | ||||
|       goto _OnDone; | ||||
| 
 | ||||
|     node = node->getPrev(); | ||||
|   } | ||||
| 
 | ||||
| _OnTarget: | ||||
|   if (static_cast<HLLabel*>(node)->getNumRefs() != 0) { | ||||
|     // Push a new LivenessTarget onto the stack if needed.
 | ||||
|     if (ltCur == nullptr || ltCur->node != node) { | ||||
|       // Allocate a new LivenessTarget object (from pool or zone).
 | ||||
|       LivenessTarget* ltTmp = ltUnused; | ||||
| 
 | ||||
|       if (ltTmp != nullptr) { | ||||
|         ltUnused = ltUnused->prev; | ||||
|       } | ||||
|       else { | ||||
|         ltTmp = _zoneAllocator.allocT<LivenessTarget>( | ||||
|           sizeof(LivenessTarget) - sizeof(BitArray) + bLen * sizeof(uintptr_t)); | ||||
| 
 | ||||
|         if (ltTmp == nullptr) | ||||
|           goto _NoMemory; | ||||
|       } | ||||
| 
 | ||||
|       // Initialize and make current - ltTmp->from will be set later on.
 | ||||
|       ltTmp->prev = ltCur; | ||||
|       ltTmp->node = static_cast<HLLabel*>(node); | ||||
|       ltCur = ltTmp; | ||||
| 
 | ||||
|       from = static_cast<HLLabel*>(node)->getFrom(); | ||||
|       ASMJIT_ASSERT(from != nullptr); | ||||
|     } | ||||
|     else { | ||||
|       from = ltCur->from; | ||||
|       goto _OnJumpNext; | ||||
|     } | ||||
| 
 | ||||
|     // Visit/Patch.
 | ||||
|     do { | ||||
|       ltCur->from = from; | ||||
|       bCur->copyBits(node->getLiveness(), bLen); | ||||
| 
 | ||||
|       if (!from->hasLiveness()) { | ||||
|         node = from; | ||||
|         goto _OnVisit; | ||||
|       } | ||||
| 
 | ||||
|       // Issue #25: Moved '_OnJumpNext' here since it's important to patch
 | ||||
|       // code again if there are more live variables than before.
 | ||||
| _OnJumpNext: | ||||
|       if (bCur->delBits(from->getLiveness(), bLen)) { | ||||
|         node = from; | ||||
|         goto _OnPatch; | ||||
|       } | ||||
| 
 | ||||
|       from = from->getJumpNext(); | ||||
|     } while (from != nullptr); | ||||
| 
 | ||||
|     // Pop the current LivenessTarget from the stack.
 | ||||
|     { | ||||
|       LivenessTarget* ltTmp = ltCur; | ||||
| 
 | ||||
|       ltCur = ltCur->prev; | ||||
|       ltTmp->prev = ltUnused; | ||||
|       ltUnused = ltTmp; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   bCur->copyBits(node->getLiveness(), bLen); | ||||
|   node = node->getPrev(); | ||||
| 
 | ||||
|   if (node->isJmp() || !node->isFetched()) | ||||
|     goto _OnDone; | ||||
| 
 | ||||
|   if (!node->hasLiveness()) | ||||
|     goto _OnVisit; | ||||
| 
 | ||||
|   if (bCur->delBits(node->getLiveness(), bLen)) | ||||
|     goto _OnPatch; | ||||
| 
 | ||||
| _OnDone: | ||||
|   if (ltCur != nullptr) { | ||||
|     node = ltCur->node; | ||||
|     from = ltCur->from; | ||||
| 
 | ||||
|     goto _OnJumpNext; | ||||
|   } | ||||
| 
 | ||||
|   retPtr = retPtr->getNext(); | ||||
|   if (retPtr != nullptr) { | ||||
|     node = retPtr->getValue(); | ||||
|     goto _OnVisit; | ||||
|   } | ||||
| 
 | ||||
|   return kErrorOk; | ||||
| 
 | ||||
| _NoMemory: | ||||
|   return setLastError(kErrorNoHeapMemory); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Context - Annotate]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error Context::formatInlineComment(StringBuilder& dst, HLNode* node) { | ||||
| #if !defined(ASMJIT_DISABLE_LOGGER) | ||||
|   if (node->getComment()) | ||||
|     dst.appendString(node->getComment()); | ||||
| 
 | ||||
|   if (node->hasLiveness()) { | ||||
|     if (dst.getLength() < _annotationLength) | ||||
|       dst.appendChars(' ', _annotationLength - dst.getLength()); | ||||
| 
 | ||||
|     uint32_t vdCount = static_cast<uint32_t>(_contextVd.getLength()); | ||||
|     size_t offset = dst.getLength() + 1; | ||||
| 
 | ||||
|     dst.appendChar('['); | ||||
|     dst.appendChars(' ', vdCount); | ||||
|     dst.appendChar(']'); | ||||
| 
 | ||||
|     BitArray* liveness = node->getLiveness(); | ||||
|     VarMap* map = node->getMap(); | ||||
| 
 | ||||
|     uint32_t i; | ||||
|     for (i = 0; i < vdCount; i++) { | ||||
|       if (liveness->getBit(i)) | ||||
|         dst.getData()[offset + i] = '.'; | ||||
|     } | ||||
| 
 | ||||
|     if (map != nullptr) { | ||||
|       uint32_t vaCount = map->getVaCount(); | ||||
|       VarAttr* vaList = reinterpret_cast<VarAttr*>(((uint8_t*)map) + _varMapToVaListOffset); | ||||
| 
 | ||||
|       for (i = 0; i < vaCount; i++) { | ||||
|         VarAttr* va = &vaList[i]; | ||||
|         VarData* vd = va->getVd(); | ||||
| 
 | ||||
|         uint32_t flags = va->getFlags(); | ||||
|         char c = 'u'; | ||||
| 
 | ||||
|         if ( (flags & kVarAttrRAll) && !(flags & kVarAttrWAll)) c = 'r'; | ||||
|         if (!(flags & kVarAttrRAll) &&  (flags & kVarAttrWAll)) c = 'w'; | ||||
|         if ( (flags & kVarAttrRAll) &&  (flags & kVarAttrWAll)) c = 'x'; | ||||
| 
 | ||||
|         // Uppercase if unused.
 | ||||
|         if ((flags & kVarAttrUnuse)) | ||||
|           c -= 'a' - 'A'; | ||||
| 
 | ||||
|         ASMJIT_ASSERT(offset + vd->getLocalId() < dst.getLength()); | ||||
|         dst._data[offset + vd->getLocalId()] = c; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| #endif // !ASMJIT_DISABLE_LOGGER
 | ||||
| 
 | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Context - Cleanup]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void Context::cleanup() { | ||||
|   VarData** array = _contextVd.getData(); | ||||
|   size_t length = _contextVd.getLength(); | ||||
| 
 | ||||
|   for (size_t i = 0; i < length; i++) { | ||||
|     VarData* vd = array[i]; | ||||
|     vd->resetLocalId(); | ||||
|     vd->resetRegIndex(); | ||||
|   } | ||||
| 
 | ||||
|   _contextVd.reset(false); | ||||
|   _extraBlock = nullptr; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Context - CompileFunc]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error Context::compile(HLFunc* func) { | ||||
|   HLNode* end = func->getEnd(); | ||||
|   HLNode* stop = end->getNext(); | ||||
| 
 | ||||
|   _func = func; | ||||
|   _stop = stop; | ||||
|   _extraBlock = end; | ||||
| 
 | ||||
|   ASMJIT_PROPAGATE_ERROR(fetch()); | ||||
|   ASMJIT_PROPAGATE_ERROR(removeUnreachableCode()); | ||||
|   ASMJIT_PROPAGATE_ERROR(livenessAnalysis()); | ||||
| 
 | ||||
|   Compiler* compiler = getCompiler(); | ||||
| 
 | ||||
| #if !defined(ASMJIT_DISABLE_LOGGER) | ||||
|   if (compiler->getAssembler()->hasLogger()) | ||||
|     ASMJIT_PROPAGATE_ERROR(annotate()); | ||||
| #endif // !ASMJIT_DISABLE_LOGGER
 | ||||
| 
 | ||||
|   ASMJIT_PROPAGATE_ERROR(translate()); | ||||
| 
 | ||||
|   // We alter the compiler cursor, because it doesn't make sense to reference
 | ||||
|   // it after compilation - some nodes may disappear and it's forbidden to add
 | ||||
|   // new code after the compilation is done.
 | ||||
|   compiler->_setCursor(nullptr); | ||||
| 
 | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // !ASMJIT_DISABLE_COMPILER
 | ||||
							
								
								
									
										901
									
								
								DynamicHooks/thirdparty/AsmJit/base/compilercontext_p.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										901
									
								
								DynamicHooks/thirdparty/AsmJit/base/compilercontext_p.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,901 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_BASE_COMPILERCONTEXT_P_H | ||||
| #define _ASMJIT_BASE_COMPILERCONTEXT_P_H | ||||
| 
 | ||||
| #include "../build.h" | ||||
| #if !defined(ASMJIT_DISABLE_COMPILER) | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/compiler.h" | ||||
| #include "../base/podvector.h" | ||||
| #include "../base/zone.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| //! \addtogroup asmjit_base
 | ||||
| //! \{
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::VarAttrFlags]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! Variable attribute flags.
 | ||||
| ASMJIT_ENUM(VarAttrFlags) { | ||||
|   //! Read from register.
 | ||||
|   kVarAttrRReg = 0x00000001, | ||||
|   //! Write to register.
 | ||||
|   kVarAttrWReg = 0x00000002, | ||||
|   //! Read/Write from/to register.
 | ||||
|   kVarAttrXReg = 0x00000003, | ||||
| 
 | ||||
|   //! Read from memory.
 | ||||
|   kVarAttrRMem = 0x00000004, | ||||
|   //! Write to memory.
 | ||||
|   kVarAttrWMem = 0x00000008, | ||||
|   //! Read/Write from/to memory.
 | ||||
|   kVarAttrXMem = 0x0000000C, | ||||
| 
 | ||||
|   //! Register allocator can decide if input will be in register or memory.
 | ||||
|   kVarAttrRDecide = 0x00000010, | ||||
|   //! Register allocator can decide if output will be in register or memory.
 | ||||
|   kVarAttrWDecide = 0x00000020, | ||||
|   //! Register allocator can decide if in/out will be in register or memory.
 | ||||
|   kVarAttrXDecide = 0x00000030, | ||||
| 
 | ||||
|   //! Variable is converted to other type/class on the input.
 | ||||
|   kVarAttrRConv = 0x00000040, | ||||
|   //! Variable is converted from other type/class on the output.
 | ||||
|   kVarAttrWConv = 0x00000080, | ||||
|   //! Combination of `kVarAttrRConv` and `kVarAttrWConv`.
 | ||||
|   kVarAttrXConv = 0x000000C0, | ||||
| 
 | ||||
|   //! Variable is a function call operand.
 | ||||
|   kVarAttrRCall = 0x00000100, | ||||
|   //! Variable is a function argument passed in register.
 | ||||
|   kVarAttrRFunc = 0x00000200, | ||||
|   //! Variable is a function return value passed in register.
 | ||||
|   kVarAttrWFunc = 0x00000400, | ||||
| 
 | ||||
|   //! Variable should be spilled.
 | ||||
|   kVarAttrSpill = 0x00000800, | ||||
|   //! Variable should be unused at the end of the instruction/node.
 | ||||
|   kVarAttrUnuse = 0x00001000, | ||||
| 
 | ||||
|   //! All in-flags.
 | ||||
|   kVarAttrRAll = kVarAttrRReg | kVarAttrRMem | kVarAttrRDecide | kVarAttrRCall | kVarAttrRFunc, | ||||
|   //! All out-flags.
 | ||||
|   kVarAttrWAll = kVarAttrWReg | kVarAttrWMem | kVarAttrWDecide | kVarAttrWFunc, | ||||
| 
 | ||||
|   //! Variable is already allocated on the input.
 | ||||
|   kVarAttrAllocRDone = 0x00400000, | ||||
|   //! Variable is already allocated on the output.
 | ||||
|   kVarAttrAllocWDone = 0x00800000, | ||||
| 
 | ||||
|   kVarAttrX86GpbLo = 0x10000000, | ||||
|   kVarAttrX86GpbHi = 0x20000000, | ||||
|   kVarAttrX86Fld4  = 0x40000000, | ||||
|   kVarAttrX86Fld8  = 0x80000000 | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::VarHint]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! Variable hint (used by `Compiler)`.
 | ||||
| //!
 | ||||
| //! \sa Compiler.
 | ||||
| ASMJIT_ENUM(VarHint) { | ||||
|   //! Alloc variable.
 | ||||
|   kVarHintAlloc = 0, | ||||
|   //! Spill variable.
 | ||||
|   kVarHintSpill = 1, | ||||
|   //! Save variable if modified.
 | ||||
|   kVarHintSave = 2, | ||||
|   //! Save variable if modified and mark it as unused.
 | ||||
|   kVarHintSaveAndUnuse = 3, | ||||
|   //! Mark variable as unused.
 | ||||
|   kVarHintUnuse = 4 | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::kVarState]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // TODO: Rename `kVarState` or `VarState`.
 | ||||
| 
 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! State of variable.
 | ||||
| //!
 | ||||
| //! NOTE: Variable states are used only during register allocation.
 | ||||
| ASMJIT_ENUM(kVarState) { | ||||
|   //! Variable is currently not used.
 | ||||
|   kVarStateNone = 0, | ||||
|   //! Variable is currently allocated in register.
 | ||||
|   kVarStateReg = 1, | ||||
|   //! Variable is currently allocated in memory (or has been spilled).
 | ||||
|   kVarStateMem = 2 | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::VarCell]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| struct VarCell { | ||||
|   ASMJIT_NO_COPY(VarCell) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get cell offset.
 | ||||
|   ASMJIT_INLINE int32_t getOffset() const { return _offset; } | ||||
|   //! Set cell offset.
 | ||||
|   ASMJIT_INLINE void setOffset(int32_t offset) { _offset = offset; } | ||||
| 
 | ||||
|   //! Get cell size.
 | ||||
|   ASMJIT_INLINE uint32_t getSize() const { return _size; } | ||||
|   //! Set cell size.
 | ||||
|   ASMJIT_INLINE void setSize(uint32_t size) { _size = size; } | ||||
| 
 | ||||
|   //! Get cell alignment.
 | ||||
|   ASMJIT_INLINE uint32_t getAlignment() const { return _alignment; } | ||||
|   //! Set cell alignment.
 | ||||
|   ASMJIT_INLINE void setAlignment(uint32_t alignment) { _alignment = alignment; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Next active cell.
 | ||||
|   VarCell* _next; | ||||
| 
 | ||||
|   //! Offset, relative to base-offset.
 | ||||
|   int32_t _offset; | ||||
|   //! Size.
 | ||||
|   uint32_t _size; | ||||
|   //! Alignment.
 | ||||
|   uint32_t _alignment; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::VarData]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! HL variable data (base).
 | ||||
| struct VarData { | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors - Base]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get variable name.
 | ||||
|   ASMJIT_INLINE const char* getName() const { return _name; } | ||||
|   //! Get variable id.
 | ||||
|   ASMJIT_INLINE uint32_t getId() const { return _id; } | ||||
|   //! Get variable type.
 | ||||
|   ASMJIT_INLINE uint32_t getType() const { return _type; } | ||||
|   //! Get variable class.
 | ||||
|   ASMJIT_INLINE uint32_t getClass() const { return _class; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors - LocalId]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get whether the variable has a local id.
 | ||||
|   ASMJIT_INLINE bool hasLocalId() const { return _localId != kInvalidValue; } | ||||
|   //! Get a variable's local id.
 | ||||
|   ASMJIT_INLINE uint32_t getLocalId() const { return _localId; } | ||||
|   //! Set a variable's local id.
 | ||||
|   ASMJIT_INLINE void setLocalId(uint32_t localId) { _localId = localId; } | ||||
|   //! Reset a variable's local id.
 | ||||
|   ASMJIT_INLINE void resetLocalId() { _localId = kInvalidValue; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors - Priority]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get variable priority, used by compiler to decide which variable to spill.
 | ||||
|   ASMJIT_INLINE uint32_t getPriority() const { return _priority; } | ||||
|   //! Set variable priority.
 | ||||
|   ASMJIT_INLINE void setPriority(uint32_t priority) { | ||||
|     ASMJIT_ASSERT(priority <= 0xFF); | ||||
|     _priority = static_cast<uint8_t>(priority); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors - State]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get variable state, only used by `Context`.
 | ||||
|   ASMJIT_INLINE uint32_t getState() const { return _state; } | ||||
|   //! Set variable state, only used by `Context`.
 | ||||
|   ASMJIT_INLINE void setState(uint32_t state) { | ||||
|     ASMJIT_ASSERT(state <= 0xFF); | ||||
|     _state = static_cast<uint8_t>(state); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors - RegIndex]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get register index.
 | ||||
|   ASMJIT_INLINE uint32_t getRegIndex() const { return _regIndex; } | ||||
|   //! Set register index.
 | ||||
|   ASMJIT_INLINE void setRegIndex(uint32_t regIndex) { | ||||
|     ASMJIT_ASSERT(regIndex <= kInvalidReg); | ||||
|     _regIndex = static_cast<uint8_t>(regIndex); | ||||
|   } | ||||
|   //! Reset register index.
 | ||||
|   ASMJIT_INLINE void resetRegIndex() { | ||||
|     _regIndex = static_cast<uint8_t>(kInvalidReg); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors - HomeIndex/Mask]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get home registers mask.
 | ||||
|   ASMJIT_INLINE uint32_t getHomeMask() const { return _homeMask; } | ||||
|   //! Add a home register index to the home registers mask.
 | ||||
|   ASMJIT_INLINE void addHomeIndex(uint32_t regIndex) { _homeMask |= Utils::mask(regIndex); } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors - Flags]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get variable flags.
 | ||||
|   ASMJIT_INLINE uint32_t getFlags() const { return _flags; } | ||||
| 
 | ||||
|   //! Get whether the VarData is only memory allocated on the stack.
 | ||||
|   ASMJIT_INLINE bool isStack() const { return static_cast<bool>(_isStack); } | ||||
|   //! Get whether the variable is a function argument passed through memory.
 | ||||
|   ASMJIT_INLINE bool isMemArg() const { return static_cast<bool>(_isMemArg); } | ||||
| 
 | ||||
|   //! Get variable content can be calculated by a simple instruction.
 | ||||
|   ASMJIT_INLINE bool isCalculated() const { return static_cast<bool>(_isCalculated); } | ||||
|   //! Get whether to save variable when it's unused (spill).
 | ||||
|   ASMJIT_INLINE bool saveOnUnuse() const { return static_cast<bool>(_saveOnUnuse); } | ||||
| 
 | ||||
|   //! Get whether the variable was changed.
 | ||||
|   ASMJIT_INLINE bool isModified() const { return static_cast<bool>(_modified); } | ||||
|   //! Set whether the variable was changed.
 | ||||
|   ASMJIT_INLINE void setModified(bool modified) { _modified = modified; } | ||||
| 
 | ||||
|   //! Get variable alignment.
 | ||||
|   ASMJIT_INLINE uint32_t getAlignment() const { return _alignment; } | ||||
|   //! Get variable size.
 | ||||
|   ASMJIT_INLINE uint32_t getSize() const { return _size; } | ||||
| 
 | ||||
|   //! Get home memory offset.
 | ||||
|   ASMJIT_INLINE int32_t getMemOffset() const { return _memOffset; } | ||||
|   //! Set home memory offset.
 | ||||
|   ASMJIT_INLINE void setMemOffset(int32_t offset) { _memOffset = offset; } | ||||
| 
 | ||||
|   //! Get home memory cell.
 | ||||
|   ASMJIT_INLINE VarCell* getMemCell() const { return _memCell; } | ||||
|   //! Set home memory cell.
 | ||||
|   ASMJIT_INLINE void setMemCell(VarCell* cell) { _memCell = cell; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors - Temporary Usage]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get temporary VarAttr.
 | ||||
|   ASMJIT_INLINE VarAttr* getVa() const { return _va; } | ||||
|   //! Set temporary VarAttr.
 | ||||
|   ASMJIT_INLINE void setVa(VarAttr* va) { _va = va; } | ||||
|   //! Reset temporary VarAttr.
 | ||||
|   ASMJIT_INLINE void resetVa() { _va = nullptr; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Variable name.
 | ||||
|   const char* _name; | ||||
| 
 | ||||
|   //! Variable id.
 | ||||
|   uint32_t _id; | ||||
|   //! Variable's local id (initially `kInvalidValue`).
 | ||||
|   uint32_t _localId; | ||||
| 
 | ||||
|   //! Variable type.
 | ||||
|   uint8_t _type; | ||||
|   //! Variable class.
 | ||||
|   uint8_t _class; | ||||
|   //! Variable flags.
 | ||||
|   uint8_t _flags; | ||||
|   //! Variable priority.
 | ||||
|   uint8_t _priority; | ||||
| 
 | ||||
|   //! Variable state (connected with actual `VarState)`.
 | ||||
|   uint8_t _state; | ||||
|   //! Actual register index (only used by `Context)`, during translate.
 | ||||
|   uint8_t _regIndex; | ||||
| 
 | ||||
|   //! Whether the variable is only used as memory allocated on the stack.
 | ||||
|   uint8_t _isStack : 1; | ||||
|   //! Whether the variable is a function argument passed through memory.
 | ||||
|   uint8_t _isMemArg : 1; | ||||
|   //! Whether variable content can be calculated by a simple instruction.
 | ||||
|   //!
 | ||||
|   //! This is used mainly by MMX and SSE2 code. This flag indicates that
 | ||||
|   //! register allocator should never reserve memory for this variable, because
 | ||||
|   //! the content can be generated by a single instruction (for example PXOR).
 | ||||
|   uint8_t _isCalculated : 1; | ||||
|   //! Save on unuse (at end of the variable scope).
 | ||||
|   uint8_t _saveOnUnuse : 1; | ||||
|   //! Whether variable was changed (connected with actual `VarState)`.
 | ||||
|   uint8_t _modified : 1; | ||||
|   //! \internal
 | ||||
|   uint8_t _reserved0 : 3; | ||||
|   //! Variable natural alignment.
 | ||||
|   uint8_t _alignment; | ||||
| 
 | ||||
|   //! Variable size.
 | ||||
|   uint32_t _size; | ||||
| 
 | ||||
|   //! Mask of all registers variable has been allocated to.
 | ||||
|   uint32_t _homeMask; | ||||
| 
 | ||||
|   //! Home memory offset.
 | ||||
|   int32_t _memOffset; | ||||
|   //! Home memory cell, used by `Context` (initially nullptr).
 | ||||
|   VarCell* _memCell; | ||||
| 
 | ||||
|   //! Register read access statistics.
 | ||||
|   uint32_t rReadCount; | ||||
|   //! Register write access statistics.
 | ||||
|   uint32_t rWriteCount; | ||||
| 
 | ||||
|   //! Memory read statistics.
 | ||||
|   uint32_t mReadCount; | ||||
|   //! Memory write statistics.
 | ||||
|   uint32_t mWriteCount; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members - Temporary Usage]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   // These variables are only used during register allocation. They are
 | ||||
|   // initialized by init() phase and reset by cleanup() phase.
 | ||||
| 
 | ||||
|   union { | ||||
|     //! Temporary link to VarAttr* used by the `Context` used in
 | ||||
|     //! various phases, but always set back to nullptr when finished.
 | ||||
|     //!
 | ||||
|     //! This temporary data is designed to be used by algorithms that need to
 | ||||
|     //! store some data into variables themselves during compilation. But it's
 | ||||
|     //! expected that after variable is compiled & translated the data is set
 | ||||
|     //! back to zero/null. Initial value is nullptr.
 | ||||
|     VarAttr* _va; | ||||
| 
 | ||||
|     //! \internal
 | ||||
|     //!
 | ||||
|     //! Same as `_va` just provided as `uintptr_t`.
 | ||||
|     uintptr_t _vaUInt; | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::VarAttr]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| struct VarAttr { | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Setup]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE void setup(VarData* vd, uint32_t flags = 0, uint32_t inRegs = 0, uint32_t allocableRegs = 0) { | ||||
|     _vd = vd; | ||||
|     _flags = flags; | ||||
|     _varCount = 0; | ||||
|     _inRegIndex = kInvalidReg; | ||||
|     _outRegIndex = kInvalidReg; | ||||
|     _reserved = 0; | ||||
|     _inRegs = inRegs; | ||||
|     _allocableRegs = allocableRegs; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get VarData.
 | ||||
|   ASMJIT_INLINE VarData* getVd() const { return _vd; } | ||||
|   //! Set VarData.
 | ||||
|   ASMJIT_INLINE void setVd(VarData* vd) { _vd = vd; } | ||||
| 
 | ||||
|   //! Get flags.
 | ||||
|   ASMJIT_INLINE uint32_t getFlags() const { return _flags; } | ||||
|   //! Set flags.
 | ||||
|   ASMJIT_INLINE void setFlags(uint32_t flags) { _flags = flags; } | ||||
| 
 | ||||
|   //! Get whether `flag` is on.
 | ||||
|   ASMJIT_INLINE bool hasFlag(uint32_t flag) { return (_flags & flag) != 0; } | ||||
|   //! Add `flags`.
 | ||||
|   ASMJIT_INLINE void orFlags(uint32_t flags) { _flags |= flags; } | ||||
|   //! Mask `flags`.
 | ||||
|   ASMJIT_INLINE void andFlags(uint32_t flags) { _flags &= flags; } | ||||
|   //! Clear `flags`.
 | ||||
|   ASMJIT_INLINE void andNotFlags(uint32_t flags) { _flags &= ~flags; } | ||||
| 
 | ||||
|   //! Get how many times the variable is used by the instruction/node.
 | ||||
|   ASMJIT_INLINE uint32_t getVarCount() const { return _varCount; } | ||||
|   //! Set how many times the variable is used by the instruction/node.
 | ||||
|   ASMJIT_INLINE void setVarCount(uint32_t count) { _varCount = static_cast<uint8_t>(count); } | ||||
|   //! Add how many times the variable is used by the instruction/node.
 | ||||
|   ASMJIT_INLINE void addVarCount(uint32_t count = 1) { _varCount += static_cast<uint8_t>(count); } | ||||
| 
 | ||||
|   //! Get whether the variable has to be allocated in a specific input register.
 | ||||
|   ASMJIT_INLINE uint32_t hasInRegIndex() const { return _inRegIndex != kInvalidReg; } | ||||
|   //! Get the input register index or `kInvalidReg`.
 | ||||
|   ASMJIT_INLINE uint32_t getInRegIndex() const { return _inRegIndex; } | ||||
|   //! Set the input register index.
 | ||||
|   ASMJIT_INLINE void setInRegIndex(uint32_t index) { _inRegIndex = static_cast<uint8_t>(index); } | ||||
|   //! Reset the input register index.
 | ||||
|   ASMJIT_INLINE void resetInRegIndex() { _inRegIndex = kInvalidReg; } | ||||
| 
 | ||||
|   //! Get whether the variable has to be allocated in a specific output register.
 | ||||
|   ASMJIT_INLINE uint32_t hasOutRegIndex() const { return _outRegIndex != kInvalidReg; } | ||||
|   //! Get the output register index or `kInvalidReg`.
 | ||||
|   ASMJIT_INLINE uint32_t getOutRegIndex() const { return _outRegIndex; } | ||||
|   //! Set the output register index.
 | ||||
|   ASMJIT_INLINE void setOutRegIndex(uint32_t index) { _outRegIndex = static_cast<uint8_t>(index); } | ||||
|   //! Reset the output register index.
 | ||||
|   ASMJIT_INLINE void resetOutRegIndex() { _outRegIndex = kInvalidReg; } | ||||
| 
 | ||||
|   //! Get whether the mandatory input registers are in used.
 | ||||
|   ASMJIT_INLINE bool hasInRegs() const { return _inRegs != 0; } | ||||
|   //! Get mandatory input registers (mask).
 | ||||
|   ASMJIT_INLINE uint32_t getInRegs() const { return _inRegs; } | ||||
|   //! Set mandatory input registers (mask).
 | ||||
|   ASMJIT_INLINE void setInRegs(uint32_t mask) { _inRegs = mask; } | ||||
|   //! Add mandatory input registers (mask).
 | ||||
|   ASMJIT_INLINE void addInRegs(uint32_t mask) { _inRegs |= mask; } | ||||
|   //! And mandatory input registers (mask).
 | ||||
|   ASMJIT_INLINE void andInRegs(uint32_t mask) { _inRegs &= mask; } | ||||
|   //! Clear mandatory input registers (mask).
 | ||||
|   ASMJIT_INLINE void delInRegs(uint32_t mask) { _inRegs &= ~mask; } | ||||
| 
 | ||||
|   //! Get allocable input registers (mask).
 | ||||
|   ASMJIT_INLINE uint32_t getAllocableRegs() const { return _allocableRegs; } | ||||
|   //! Set allocable input registers (mask).
 | ||||
|   ASMJIT_INLINE void setAllocableRegs(uint32_t mask) { _allocableRegs = mask; } | ||||
|   //! Add allocable input registers (mask).
 | ||||
|   ASMJIT_INLINE void addAllocableRegs(uint32_t mask) { _allocableRegs |= mask; } | ||||
|   //! And allocable input registers (mask).
 | ||||
|   ASMJIT_INLINE void andAllocableRegs(uint32_t mask) { _allocableRegs &= mask; } | ||||
|   //! Clear allocable input registers (mask).
 | ||||
|   ASMJIT_INLINE void delAllocableRegs(uint32_t mask) { _allocableRegs &= ~mask; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Operator Overload]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE VarAttr& operator=(const VarAttr& other) { | ||||
|     ::memcpy(this, &other, sizeof(VarAttr)); | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   VarData* _vd; | ||||
|   //! Flags.
 | ||||
|   uint32_t _flags; | ||||
| 
 | ||||
|   union { | ||||
|     struct { | ||||
|       //! How many times the variable is used by the instruction/node.
 | ||||
|       uint8_t _varCount; | ||||
|       //! Input register index or `kInvalidReg` if it's not given.
 | ||||
|       //!
 | ||||
|       //! Even if the input register index is not given (i.e. it may by any
 | ||||
|       //! register), register allocator should assign an index that will be
 | ||||
|       //! used to persist a variable into this specific index. It's helpful
 | ||||
|       //! in situations where one variable has to be allocated in multiple
 | ||||
|       //! registers to determine the register which will be persistent.
 | ||||
|       uint8_t _inRegIndex; | ||||
|       //! Output register index or `kInvalidReg` if it's not given.
 | ||||
|       //!
 | ||||
|       //! Typically `kInvalidReg` if variable is only used on input.
 | ||||
|       uint8_t _outRegIndex; | ||||
|       //! \internal
 | ||||
|       uint8_t _reserved; | ||||
|     }; | ||||
| 
 | ||||
|     //! \internal
 | ||||
|     //!
 | ||||
|     //! Packed data #0.
 | ||||
|     uint32_t _packed; | ||||
|   }; | ||||
| 
 | ||||
|   //! Mandatory input registers.
 | ||||
|   //!
 | ||||
|   //! Mandatory input registers are required by the instruction even if
 | ||||
|   //! there are duplicates. This schema allows us to allocate one variable
 | ||||
|   //! in one or more register when needed. Required mostly by instructions
 | ||||
|   //! that have implicit register operands (imul, cpuid, ...) and function
 | ||||
|   //! call.
 | ||||
|   uint32_t _inRegs; | ||||
| 
 | ||||
|   //! Allocable input registers.
 | ||||
|   //!
 | ||||
|   //! Optional input registers is a mask of all allocable registers for a given
 | ||||
|   //! variable where we have to pick one of them. This mask is usually not used
 | ||||
|   //! when _inRegs is set. If both masks are used then the register
 | ||||
|   //! allocator tries first to find an intersection between these and allocates
 | ||||
|   //! an extra slot if not found.
 | ||||
|   uint32_t _allocableRegs; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::VarMap]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Variables' map related to a single node (instruction / other node).
 | ||||
| struct VarMap { | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get count of variables (all).
 | ||||
|   ASMJIT_INLINE uint32_t getVaCount() const { | ||||
|     return _vaCount; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Variables count.
 | ||||
|   uint32_t _vaCount; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::VarState]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Variables' state.
 | ||||
| struct VarState {}; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Context]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! Code generation context is the logic behind `Compiler`. The context is
 | ||||
| //! used to compile the code stored in `Compiler`.
 | ||||
| struct Context { | ||||
|   ASMJIT_NO_COPY(Context) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   Context(Compiler* compiler); | ||||
|   virtual ~Context(); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Reset]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Reset the whole context.
 | ||||
|   virtual void reset(bool releaseMemory = false); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get compiler.
 | ||||
|   ASMJIT_INLINE Compiler* getCompiler() const { return _compiler; } | ||||
| 
 | ||||
|   //! Get function.
 | ||||
|   ASMJIT_INLINE HLFunc* getFunc() const { return _func; } | ||||
|   //! Get stop node.
 | ||||
|   ASMJIT_INLINE HLNode* getStop() const { return _stop; } | ||||
| 
 | ||||
|   //! Get start of the current scope.
 | ||||
|   ASMJIT_INLINE HLNode* getStart() const { return _start; } | ||||
|   //! Get end of the current scope.
 | ||||
|   ASMJIT_INLINE HLNode* getEnd() const { return _end; } | ||||
| 
 | ||||
|   //! Get extra block.
 | ||||
|   ASMJIT_INLINE HLNode* getExtraBlock() const { return _extraBlock; } | ||||
|   //! Set extra block.
 | ||||
|   ASMJIT_INLINE void setExtraBlock(HLNode* node) { _extraBlock = node; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Error]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get the last error code.
 | ||||
|   ASMJIT_INLINE Error getLastError() const { | ||||
|     return getCompiler()->getLastError(); | ||||
|   } | ||||
| 
 | ||||
|   //! Set the last error code and propagate it through the error handler.
 | ||||
|   ASMJIT_INLINE Error setLastError(Error error, const char* message = nullptr) { | ||||
|     return getCompiler()->setLastError(error, message); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [State]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get current state.
 | ||||
|   ASMJIT_INLINE VarState* getState() const { return _state; } | ||||
| 
 | ||||
|   //! Load current state from `target` state.
 | ||||
|   virtual void loadState(VarState* src) = 0; | ||||
| 
 | ||||
|   //! Save current state, returning new `VarState` instance.
 | ||||
|   virtual VarState* saveState() = 0; | ||||
| 
 | ||||
|   //! Change the current state to `target` state.
 | ||||
|   virtual void switchState(VarState* src) = 0; | ||||
| 
 | ||||
|   //! Change the current state to the intersection of two states `a` and `b`.
 | ||||
|   virtual void intersectStates(VarState* a, VarState* b) = 0; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Context]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE Error _registerContextVar(VarData* vd) { | ||||
|     if (vd->hasLocalId()) | ||||
|       return kErrorOk; | ||||
| 
 | ||||
|     uint32_t cid = static_cast<uint32_t>(_contextVd.getLength()); | ||||
|     ASMJIT_PROPAGATE_ERROR(_contextVd.append(vd)); | ||||
| 
 | ||||
|     vd->setLocalId(cid); | ||||
|     return kErrorOk; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Mem]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   VarCell* _newVarCell(VarData* vd); | ||||
|   VarCell* _newStackCell(uint32_t size, uint32_t alignment); | ||||
| 
 | ||||
|   ASMJIT_INLINE VarCell* getVarCell(VarData* vd) { | ||||
|     VarCell* cell = vd->getMemCell(); | ||||
|     return cell ? cell : _newVarCell(vd); | ||||
|   } | ||||
| 
 | ||||
|   virtual Error resolveCellOffsets(); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Bits]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE BitArray* newBits(uint32_t len) { | ||||
|     return static_cast<BitArray*>( | ||||
|       _zoneAllocator.allocZeroed(static_cast<size_t>(len) * BitArray::kEntitySize)); | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE BitArray* copyBits(const BitArray* src, uint32_t len) { | ||||
|     return static_cast<BitArray*>( | ||||
|       _zoneAllocator.dup(src, static_cast<size_t>(len) * BitArray::kEntitySize)); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Fetch]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Fetch.
 | ||||
|   //!
 | ||||
|   //! Fetch iterates over all nodes and gathers information about all variables
 | ||||
|   //! used. The process generates information required by register allocator,
 | ||||
|   //! variable liveness analysis and translator.
 | ||||
|   virtual Error fetch() = 0; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Unreachable Code]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Add unreachable-flow data to the unreachable flow list.
 | ||||
|   ASMJIT_INLINE Error addUnreachableNode(HLNode* node) { | ||||
|     PodList<HLNode*>::Link* link = _zoneAllocator.allocT<PodList<HLNode*>::Link>(); | ||||
|     if (link == nullptr) | ||||
|       return setLastError(kErrorNoHeapMemory); | ||||
| 
 | ||||
|     link->setValue(node); | ||||
|     _unreachableList.append(link); | ||||
| 
 | ||||
|     return kErrorOk; | ||||
|   } | ||||
| 
 | ||||
|   //! Remove unreachable code.
 | ||||
|   virtual Error removeUnreachableCode(); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Code-Flow]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Add returning node (i.e. node that returns and where liveness analysis
 | ||||
|   //! should start).
 | ||||
|   ASMJIT_INLINE Error addReturningNode(HLNode* node) { | ||||
|     PodList<HLNode*>::Link* link = _zoneAllocator.allocT<PodList<HLNode*>::Link>(); | ||||
|     if (link == nullptr) | ||||
|       return setLastError(kErrorNoHeapMemory); | ||||
| 
 | ||||
|     link->setValue(node); | ||||
|     _returningList.append(link); | ||||
| 
 | ||||
|     return kErrorOk; | ||||
|   } | ||||
| 
 | ||||
|   //! Add jump-flow data to the jcc flow list.
 | ||||
|   ASMJIT_INLINE Error addJccNode(HLNode* node) { | ||||
|     PodList<HLNode*>::Link* link = _zoneAllocator.allocT<PodList<HLNode*>::Link>(); | ||||
|     if (link == nullptr) | ||||
|       return setLastError(kErrorNoHeapMemory); | ||||
| 
 | ||||
|     link->setValue(node); | ||||
|     _jccList.append(link); | ||||
| 
 | ||||
|     return kErrorOk; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Analyze]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Perform variable liveness analysis.
 | ||||
|   //!
 | ||||
|   //! Analysis phase iterates over nodes in reverse order and generates a bit
 | ||||
|   //! array describing variables that are alive at every node in the function.
 | ||||
|   //! When the analysis start all variables are assumed dead. When a read or
 | ||||
|   //! read/write operations of a variable is detected the variable becomes
 | ||||
|   //! alive; when only write operation is detected the variable becomes dead.
 | ||||
|   //!
 | ||||
|   //! When a label is found all jumps to that label are followed and analysis
 | ||||
|   //! repeats until all variables are resolved.
 | ||||
|   virtual Error livenessAnalysis(); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Annotate]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   virtual Error annotate() = 0; | ||||
|   virtual Error formatInlineComment(StringBuilder& dst, HLNode* node); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Translate]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Translate code by allocating registers and handling state changes.
 | ||||
|   virtual Error translate() = 0; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Cleanup]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   virtual void cleanup(); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Compile]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   virtual Error compile(HLFunc* func); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Serialize]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   virtual Error serialize(Assembler* assembler, HLNode* start, HLNode* stop) = 0; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Compiler.
 | ||||
|   Compiler* _compiler; | ||||
|   //! Function.
 | ||||
|   HLFunc* _func; | ||||
| 
 | ||||
|   //! Zone allocator.
 | ||||
|   Zone _zoneAllocator; | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   typedef void (ASMJIT_CDECL* TraceNodeFunc)(Context* self, HLNode* node_, const char* prefix); | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Only non-NULL when ASMJIT_TRACE is enabled.
 | ||||
|   TraceNodeFunc _traceNode; | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Offset (how many bytes to add) to `VarMap` to get `VarAttr` array. Used
 | ||||
|   //! by liveness analysis shared across all backends. This is needed because
 | ||||
|   //! `VarMap` is a base class for a specialized version that liveness analysis
 | ||||
|   //! doesn't use, it just needs `VarAttr` array.
 | ||||
|   uint32_t _varMapToVaListOffset; | ||||
| 
 | ||||
|   //! Start of the current active scope.
 | ||||
|   HLNode* _start; | ||||
|   //! End of the current active scope.
 | ||||
|   HLNode* _end; | ||||
| 
 | ||||
|   //! Node that is used to insert extra code after the function body.
 | ||||
|   HLNode* _extraBlock; | ||||
|   //! Stop node.
 | ||||
|   HLNode* _stop; | ||||
| 
 | ||||
|   //! Unreachable nodes.
 | ||||
|   PodList<HLNode*> _unreachableList; | ||||
|   //! Returning nodes.
 | ||||
|   PodList<HLNode*> _returningList; | ||||
|   //! Jump nodes.
 | ||||
|   PodList<HLNode*> _jccList; | ||||
| 
 | ||||
|   //! All variables used by the current function.
 | ||||
|   PodVector<VarData*> _contextVd; | ||||
| 
 | ||||
|   //! Memory used to spill variables.
 | ||||
|   VarCell* _memVarCells; | ||||
|   //! Memory used to alloc memory on the stack.
 | ||||
|   VarCell* _memStackCells; | ||||
| 
 | ||||
|   //! Count of 1-byte cells.
 | ||||
|   uint32_t _mem1ByteVarsUsed; | ||||
|   //! Count of 2-byte cells.
 | ||||
|   uint32_t _mem2ByteVarsUsed; | ||||
|   //! Count of 4-byte cells.
 | ||||
|   uint32_t _mem4ByteVarsUsed; | ||||
|   //! Count of 8-byte cells.
 | ||||
|   uint32_t _mem8ByteVarsUsed; | ||||
|   //! Count of 16-byte cells.
 | ||||
|   uint32_t _mem16ByteVarsUsed; | ||||
|   //! Count of 32-byte cells.
 | ||||
|   uint32_t _mem32ByteVarsUsed; | ||||
|   //! Count of 64-byte cells.
 | ||||
|   uint32_t _mem64ByteVarsUsed; | ||||
|   //! Count of stack memory cells.
 | ||||
|   uint32_t _memStackCellsUsed; | ||||
| 
 | ||||
|   //! Maximum memory alignment used by the function.
 | ||||
|   uint32_t _memMaxAlign; | ||||
|   //! Count of bytes used by variables.
 | ||||
|   uint32_t _memVarTotal; | ||||
|   //! Count of bytes used by stack.
 | ||||
|   uint32_t _memStackTotal; | ||||
|   //! Count of bytes used by variables and stack after alignment.
 | ||||
|   uint32_t _memAllTotal; | ||||
| 
 | ||||
|   //! Default lenght of annotated instruction.
 | ||||
|   uint32_t _annotationLength; | ||||
| 
 | ||||
|   //! Current state (used by register allocator).
 | ||||
|   VarState* _state; | ||||
| }; | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // !ASMJIT_DISABLE_COMPILER
 | ||||
| #endif // _ASMJIT_BASE_COMPILERCONTEXT_P_H
 | ||||
							
								
								
									
										679
									
								
								DynamicHooks/thirdparty/AsmJit/base/compilerfunc.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										679
									
								
								DynamicHooks/thirdparty/AsmJit/base/compilerfunc.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,679 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_BASE_COMPILERFUNC_H | ||||
| #define _ASMJIT_BASE_COMPILERFUNC_H | ||||
| 
 | ||||
| #include "../build.h" | ||||
| #if !defined(ASMJIT_DISABLE_COMPILER) | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/operand.h" | ||||
| #include "../base/utils.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| //! \addtogroup asmjit_base
 | ||||
| //! \{
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::FuncHint]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Function hints.
 | ||||
| //!
 | ||||
| //! For a platform specific calling conventions, see:
 | ||||
| //!   - `X86FuncHint` - X86/X64 function hints.
 | ||||
| ASMJIT_ENUM(FuncHint) { | ||||
|   //! Generate a naked function by omitting its prolog and epilog (default true).
 | ||||
|   //!
 | ||||
|   //! Naked functions should always result in less code required for function's
 | ||||
|   //! prolog and epilog. In addition, on X86/64 naked functions save one register
 | ||||
|   //! (ebp or rbp), which can be used by the function instead.
 | ||||
|   kFuncHintNaked = 0, | ||||
| 
 | ||||
|   //! Generate a compact function prolog/epilog if possible (default true).
 | ||||
|   //!
 | ||||
|   //! X86/X64 Specific
 | ||||
|   //! ----------------
 | ||||
|   //!
 | ||||
|   //! Use shorter, but possible slower prolog/epilog sequence to save/restore
 | ||||
|   //! registers. At the moment this only enables emitting `leave` in function's
 | ||||
|   //! epilog to make the code shorter, however, the counterpart `enter` is not
 | ||||
|   //! used in function's prolog for performance reasons.
 | ||||
|   kFuncHintCompact = 1, | ||||
| 
 | ||||
|   //! Emit `emms` instruction in the function's epilog.
 | ||||
|   kFuncHintX86Emms = 17, | ||||
|   //! Emit `sfence` instruction in the function's epilog.
 | ||||
|   kFuncHintX86SFence = 18, | ||||
|   //! Emit `lfence` instruction in the function's epilog.
 | ||||
|   kFuncHintX86LFence = 19 | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::FuncFlags]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Function flags.
 | ||||
| ASMJIT_ENUM(FuncFlags) { | ||||
|   //! Whether the function is using naked (minimal) prolog / epilog.
 | ||||
|   kFuncFlagIsNaked = 0x00000001, | ||||
| 
 | ||||
|   //! Whether an another function is called from this function.
 | ||||
|   kFuncFlagIsCaller = 0x00000002, | ||||
| 
 | ||||
|   //! Whether the stack is not aligned to the required stack alignment,
 | ||||
|   //! thus it has to be aligned manually.
 | ||||
|   kFuncFlagIsStackMisaligned = 0x00000004, | ||||
| 
 | ||||
|   //! Whether the stack pointer is adjusted by the stack size needed
 | ||||
|   //! to save registers and function variables.
 | ||||
|   //!
 | ||||
|   //! X86/X64 Specific
 | ||||
|   //! ----------------
 | ||||
|   //!
 | ||||
|   //! Stack pointer (ESP/RSP) is adjusted by 'sub' instruction in prolog and by
 | ||||
|   //! 'add' instruction in epilog (only if function is not naked). If function
 | ||||
|   //! needs to perform manual stack alignment more instructions are used to
 | ||||
|   //! adjust the stack (like "and zsp, -Alignment").
 | ||||
|   kFuncFlagIsStackAdjusted = 0x00000008, | ||||
| 
 | ||||
|   //! Whether the function is finished using `Compiler::endFunc()`.
 | ||||
|   kFuncFlagIsFinished = 0x80000000, | ||||
| 
 | ||||
|   //! Whether to emit `leave` instead of two instructions in case that the
 | ||||
|   //! function saves and restores the frame pointer.
 | ||||
|   kFuncFlagX86Leave = 0x00010000, | ||||
| 
 | ||||
|   //! Whether it's required to move arguments to a new stack location,
 | ||||
|   //! because of manual aligning.
 | ||||
|   kFuncFlagX86MoveArgs = 0x00040000, | ||||
| 
 | ||||
|   //! Whether to emit `emms` instruction in epilog (auto-detected).
 | ||||
|   kFuncFlagX86Emms = 0x01000000, | ||||
| 
 | ||||
|   //! Whether to emit `sfence` instruction in epilog (auto-detected).
 | ||||
|   //!
 | ||||
|   //! `kFuncFlagX86SFence` with `kFuncFlagX86LFence` results in emitting `mfence`.
 | ||||
|   kFuncFlagX86SFence = 0x02000000, | ||||
| 
 | ||||
|   //! Whether to emit `lfence` instruction in epilog (auto-detected).
 | ||||
|   //!
 | ||||
|   //! `kFuncFlagX86SFence` with `kFuncFlagX86LFence` results in emitting `mfence`.
 | ||||
|   kFuncFlagX86LFence = 0x04000000 | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::FuncDir]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Function arguments direction.
 | ||||
| ASMJIT_ENUM(FuncDir) { | ||||
|   //! Arguments are passed left to right.
 | ||||
|   //!
 | ||||
|   //! This arguments direction is unusual in C, however it's used in Pascal.
 | ||||
|   kFuncDirLTR = 0, | ||||
| 
 | ||||
|   //! Arguments are passed right ro left
 | ||||
|   //!
 | ||||
|   //! This is the default argument direction in C.
 | ||||
|   kFuncDirRTL = 1 | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::FuncMisc]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| enum { | ||||
|   //! Function doesn't have variable number of arguments (`...`) (default).
 | ||||
|   kFuncNoVarArgs = 0xFF, | ||||
|   //! Invalid stack offset in function or function parameter.
 | ||||
|   kFuncStackInvalid = -1 | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::FuncArgIndex]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Function argument index (lo/hi).
 | ||||
| ASMJIT_ENUM(FuncArgIndex) { | ||||
|   //! Maxumum number of function arguments supported by AsmJit.
 | ||||
|   kFuncArgCount = 16, | ||||
|   //! Extended maximum number of arguments (used internally).
 | ||||
|   kFuncArgCountLoHi = kFuncArgCount * 2, | ||||
| 
 | ||||
|   //! Index to the LO part of function argument (default).
 | ||||
|   //!
 | ||||
|   //! This value is typically omitted and added only if there is HI argument
 | ||||
|   //! accessed.
 | ||||
|   kFuncArgLo = 0, | ||||
| 
 | ||||
|   //! Index to the HI part of function argument.
 | ||||
|   //!
 | ||||
|   //! HI part of function argument depends on target architecture. On x86 it's
 | ||||
|   //! typically used to transfer 64-bit integers (they form a pair of 32-bit
 | ||||
|   //! integers).
 | ||||
|   kFuncArgHi = kFuncArgCount | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::FuncRet]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Function return value (lo/hi) specification.
 | ||||
| ASMJIT_ENUM(FuncRet) { | ||||
|   //! Index to the LO part of function return value.
 | ||||
|   kFuncRetLo = 0, | ||||
|   //! Index to the HI part of function return value.
 | ||||
|   kFuncRetHi = 1 | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::TypeId]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Function builder's `void` type.
 | ||||
| struct Void {}; | ||||
| 
 | ||||
| //! Function builder's `int8_t` type.
 | ||||
| struct Int8Type {}; | ||||
| //! Function builder's `uint8_t` type.
 | ||||
| struct UInt8Type {}; | ||||
| 
 | ||||
| //! Function builder's `int16_t` type.
 | ||||
| struct Int16Type {}; | ||||
| //! Function builder's `uint16_t` type.
 | ||||
| struct UInt16Type {}; | ||||
| 
 | ||||
| //! Function builder's `int32_t` type.
 | ||||
| struct Int32Type {}; | ||||
| //! Function builder's `uint32_t` type.
 | ||||
| struct UInt32Type {}; | ||||
| 
 | ||||
| //! Function builder's `int64_t` type.
 | ||||
| struct Int64Type {}; | ||||
| //! Function builder's `uint64_t` type.
 | ||||
| struct UInt64Type {}; | ||||
| 
 | ||||
| //! Function builder's `intptr_t` type.
 | ||||
| struct IntPtrType {}; | ||||
| //! Function builder's `uintptr_t` type.
 | ||||
| struct UIntPtrType {}; | ||||
| 
 | ||||
| //! Function builder's `float` type.
 | ||||
| struct FloatType {}; | ||||
| //! Function builder's `double` type.
 | ||||
| struct DoubleType {}; | ||||
| 
 | ||||
| #if !defined(ASMJIT_DOCGEN) | ||||
| template<typename T> | ||||
| struct TypeId { | ||||
|   // Let it fail here if `T` was not specialized.
 | ||||
| }; | ||||
| 
 | ||||
| template<typename T> | ||||
| struct TypeId<T*> { | ||||
|   enum { kId = kVarTypeIntPtr }; | ||||
| }; | ||||
| 
 | ||||
| template<typename T> | ||||
| struct TypeIdOfInt { | ||||
|   enum { kId = (sizeof(T) == 1) ? (int)(IntTraits<T>::kIsSigned ? kVarTypeInt8  : kVarTypeUInt8 ) : | ||||
|                (sizeof(T) == 2) ? (int)(IntTraits<T>::kIsSigned ? kVarTypeInt16 : kVarTypeUInt16) : | ||||
|                (sizeof(T) == 4) ? (int)(IntTraits<T>::kIsSigned ? kVarTypeInt32 : kVarTypeUInt32) : | ||||
|                (sizeof(T) == 8) ? (int)(IntTraits<T>::kIsSigned ? kVarTypeInt64 : kVarTypeUInt64) : (int)kInvalidVar | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| #define ASMJIT_TYPE_ID(T, ID) \ | ||||
|   template<> struct TypeId<T> { enum { kId = ID }; } | ||||
| 
 | ||||
| ASMJIT_TYPE_ID(void              , kInvalidVar); | ||||
| ASMJIT_TYPE_ID(signed char       , TypeIdOfInt<signed char>::kId); | ||||
| ASMJIT_TYPE_ID(unsigned char     , TypeIdOfInt<unsigned char>::kId); | ||||
| ASMJIT_TYPE_ID(short             , TypeIdOfInt<short>::kId); | ||||
| ASMJIT_TYPE_ID(unsigned short    , TypeIdOfInt<unsigned short>::kId); | ||||
| ASMJIT_TYPE_ID(int               , TypeIdOfInt<int>::kId); | ||||
| ASMJIT_TYPE_ID(unsigned int      , TypeIdOfInt<unsigned int>::kId); | ||||
| ASMJIT_TYPE_ID(long              , TypeIdOfInt<long>::kId); | ||||
| ASMJIT_TYPE_ID(unsigned long     , TypeIdOfInt<unsigned long>::kId); | ||||
| ASMJIT_TYPE_ID(float             , kVarTypeFp32); | ||||
| ASMJIT_TYPE_ID(double            , kVarTypeFp64); | ||||
| 
 | ||||
| #if ASMJIT_CC_HAS_NATIVE_CHAR | ||||
| ASMJIT_TYPE_ID(char              , TypeIdOfInt<char>::kId); | ||||
| #endif | ||||
| #if ASMJIT_CC_HAS_NATIVE_WCHAR_T | ||||
| ASMJIT_TYPE_ID(wchar_t           , TypeIdOfInt<wchar_t>::kId); | ||||
| #endif | ||||
| #if ASMJIT_CC_HAS_NATIVE_CHAR16_T | ||||
| ASMJIT_TYPE_ID(char16_t          , TypeIdOfInt<char16_t>::kId); | ||||
| #endif | ||||
| #if ASMJIT_CC_HAS_NATIVE_CHAR32_T | ||||
| ASMJIT_TYPE_ID(char32_t          , TypeIdOfInt<char32_t>::kId); | ||||
| #endif | ||||
| 
 | ||||
| #if ASMJIT_CC_MSC && !ASMJIT_CC_MSC_GE(16, 0, 0) | ||||
| ASMJIT_TYPE_ID(__int64           , TypeIdOfInt<__int64>::kId); | ||||
| ASMJIT_TYPE_ID(unsigned __int64  , TypeIdOfInt<unsigned __int64>::kId); | ||||
| #else | ||||
| ASMJIT_TYPE_ID(long long         , TypeIdOfInt<long long>::kId); | ||||
| ASMJIT_TYPE_ID(unsigned long long, TypeIdOfInt<unsigned long long>::kId); | ||||
| #endif | ||||
| 
 | ||||
| ASMJIT_TYPE_ID(Void              , kInvalidVar); | ||||
| ASMJIT_TYPE_ID(Int8Type          , kVarTypeInt8); | ||||
| ASMJIT_TYPE_ID(UInt8Type         , kVarTypeUInt8); | ||||
| ASMJIT_TYPE_ID(Int16Type         , kVarTypeInt16); | ||||
| ASMJIT_TYPE_ID(UInt16Type        , kVarTypeUInt16); | ||||
| ASMJIT_TYPE_ID(Int32Type         , kVarTypeInt32); | ||||
| ASMJIT_TYPE_ID(UInt32Type        , kVarTypeUInt32); | ||||
| ASMJIT_TYPE_ID(Int64Type         , kVarTypeInt64); | ||||
| ASMJIT_TYPE_ID(UInt64Type        , kVarTypeUInt64); | ||||
| ASMJIT_TYPE_ID(IntPtrType        , kVarTypeIntPtr); | ||||
| ASMJIT_TYPE_ID(UIntPtrType       , kVarTypeUIntPtr); | ||||
| ASMJIT_TYPE_ID(FloatType         , kVarTypeFp32); | ||||
| ASMJIT_TYPE_ID(DoubleType        , kVarTypeFp64); | ||||
| #endif // !ASMJIT_DOCGEN
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::FuncInOut]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Function in/out - argument or return value translated from `FuncPrototype`.
 | ||||
| struct FuncInOut { | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE uint32_t getVarType() const noexcept { return _varType; } | ||||
| 
 | ||||
|   ASMJIT_INLINE bool hasRegIndex() const noexcept { return _regIndex != kInvalidReg; } | ||||
|   ASMJIT_INLINE uint32_t getRegIndex() const noexcept { return _regIndex; } | ||||
| 
 | ||||
|   ASMJIT_INLINE bool hasStackOffset() const noexcept { return _stackOffset != kFuncStackInvalid; } | ||||
|   ASMJIT_INLINE int32_t getStackOffset() const noexcept { return static_cast<int32_t>(_stackOffset); } | ||||
| 
 | ||||
|   //! Get whether the argument / return value is assigned.
 | ||||
|   ASMJIT_INLINE bool isSet() const noexcept { | ||||
|     return (_regIndex != kInvalidReg) | (_stackOffset != kFuncStackInvalid); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Reset]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Reset the function argument to "unassigned state".
 | ||||
|   ASMJIT_INLINE void reset() noexcept { _packed = 0xFFFFFFFFU; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   union { | ||||
|     struct { | ||||
|       //! Variable type, see \ref VarType.
 | ||||
|       uint8_t _varType; | ||||
|       //! Register index if argument / return value is a register.
 | ||||
|       uint8_t _regIndex; | ||||
|       //! Stack offset if argument / return value is on the stack.
 | ||||
|       int16_t _stackOffset; | ||||
|     }; | ||||
| 
 | ||||
|     //! All members packed into single 32-bit integer.
 | ||||
|     uint32_t _packed; | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::FuncPrototype]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Function prototype.
 | ||||
| //!
 | ||||
| //! Function prototype contains information about function return type, count
 | ||||
| //! of arguments and their types. Function prototype is a low level structure
 | ||||
| //! which doesn't contain platform specific or calling convention specific
 | ||||
| //! information. Function prototype is used to create a `FuncDecl`.
 | ||||
| struct FuncPrototype { | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Setup]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Setup the prototype.
 | ||||
|   ASMJIT_INLINE void setup( | ||||
|     uint32_t callConv, | ||||
|     uint32_t ret, | ||||
|     const uint32_t* args, uint32_t numArgs) noexcept { | ||||
| 
 | ||||
|     ASMJIT_ASSERT(callConv <= 0xFF); | ||||
|     ASMJIT_ASSERT(numArgs <= 0xFF); | ||||
| 
 | ||||
|     _callConv = static_cast<uint8_t>(callConv); | ||||
|     _varArgs = kFuncNoVarArgs; | ||||
|     _numArgs = static_cast<uint8_t>(numArgs); | ||||
|     _reserved = 0; | ||||
| 
 | ||||
|     _ret = ret; | ||||
|     _args = args; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get the function's calling convention.
 | ||||
|   ASMJIT_INLINE uint32_t getCallConv() const noexcept { return _callConv; } | ||||
|   //! Get the variable arguments `...` index, `kFuncNoVarArgs` if none.
 | ||||
|   ASMJIT_INLINE uint32_t getVarArgs() const noexcept { return _varArgs; } | ||||
|   //! Get the number of function arguments.
 | ||||
|   ASMJIT_INLINE uint32_t getNumArgs() const noexcept { return _numArgs; } | ||||
| 
 | ||||
|   //! Get the return value type.
 | ||||
|   ASMJIT_INLINE uint32_t getRet() const noexcept { return _ret; } | ||||
|   //! Get the type of the argument at index `i`.
 | ||||
|   ASMJIT_INLINE uint32_t getArg(uint32_t i) const noexcept { | ||||
|     ASMJIT_ASSERT(i < _numArgs); | ||||
|     return _args[i]; | ||||
|   } | ||||
|   //! Get the array of function arguments' types.
 | ||||
|   ASMJIT_INLINE const uint32_t* getArgs() const noexcept { return _args; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   uint8_t _callConv; | ||||
|   uint8_t _varArgs; | ||||
|   uint8_t _numArgs; | ||||
|   uint8_t _reserved; | ||||
| 
 | ||||
|   uint32_t _ret; | ||||
|   const uint32_t* _args; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::FuncBuilderX]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // TODO: Rename to `DynamicFuncBuilder`
 | ||||
| //! Custom function builder for up to 32 function arguments.
 | ||||
| struct FuncBuilderX : public FuncPrototype { | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE FuncBuilderX(uint32_t callConv = kCallConvHost) noexcept { | ||||
|     setup(callConv, kInvalidVar, _builderArgList, 0); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE void setCallConv(uint32_t callConv) noexcept { | ||||
|     ASMJIT_ASSERT(callConv <= 0xFF); | ||||
|     _callConv = static_cast<uint8_t>(callConv); | ||||
|   } | ||||
| 
 | ||||
|   //! Set the return type to `retType`.
 | ||||
|   ASMJIT_INLINE void setRet(uint32_t retType) noexcept { | ||||
|     _ret = retType; | ||||
|   } | ||||
|   //! Set the return type based on `T`.
 | ||||
|   template<typename T> | ||||
|   ASMJIT_INLINE void setRetT() noexcept { setRet(TypeId<T>::kId); } | ||||
| 
 | ||||
|   //! Set the argument at index `i` to the `type`
 | ||||
|   ASMJIT_INLINE void setArg(uint32_t i, uint32_t type) noexcept { | ||||
|     ASMJIT_ASSERT(i < _numArgs); | ||||
|     _builderArgList[i] = type; | ||||
|   } | ||||
|   //! Set the argument at index `i` to the type based on `T`.
 | ||||
|   template<typename T> | ||||
|   ASMJIT_INLINE void setArgT(uint32_t i) noexcept { setArg(i, TypeId<T>::kId); } | ||||
| 
 | ||||
|   //! Append an argument of `type` to the function prototype.
 | ||||
|   ASMJIT_INLINE void addArg(uint32_t type) noexcept { | ||||
|     ASMJIT_ASSERT(_numArgs < kFuncArgCount); | ||||
|     _builderArgList[_numArgs++] = type; | ||||
|   } | ||||
|   //! Append an argument of type based on `T` to the function prototype.
 | ||||
|   template<typename T> | ||||
|   ASMJIT_INLINE void addArgT() noexcept { addArg(TypeId<T>::kId); } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   uint32_t _builderArgList[kFuncArgCount]; | ||||
| }; | ||||
| 
 | ||||
| //! \internal
 | ||||
| #define T(_Type_) TypeId<_Type_>::kId | ||||
| 
 | ||||
| //! Function prototype (no args).
 | ||||
| template<typename RET> | ||||
| struct FuncBuilder0 : public FuncPrototype { | ||||
|   ASMJIT_INLINE FuncBuilder0(uint32_t callConv = kCallConvHost) noexcept { | ||||
|     setup(callConv, T(RET), nullptr, 0); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| //! Function prototype (1 argument).
 | ||||
| template<typename RET, typename P0> | ||||
| struct FuncBuilder1 : public FuncPrototype { | ||||
|   ASMJIT_INLINE FuncBuilder1(uint32_t callConv = kCallConvHost) noexcept { | ||||
|     static const uint32_t args[] = { T(P0) }; | ||||
|     setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| //! Function prototype (2 arguments).
 | ||||
| template<typename RET, typename P0, typename P1> | ||||
| struct FuncBuilder2 : public FuncPrototype { | ||||
|   ASMJIT_INLINE FuncBuilder2(uint32_t callConv = kCallConvHost) noexcept { | ||||
|     static const uint32_t args[] = { T(P0), T(P1) }; | ||||
|     setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| //! Function prototype (3 arguments).
 | ||||
| template<typename RET, typename P0, typename P1, typename P2> | ||||
| struct FuncBuilder3 : public FuncPrototype { | ||||
|   ASMJIT_INLINE FuncBuilder3(uint32_t callConv = kCallConvHost) noexcept { | ||||
|     static const uint32_t args[] = { T(P0), T(P1), T(P2) }; | ||||
|     setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| //! Function prototype (4 arguments).
 | ||||
| template<typename RET, typename P0, typename P1, typename P2, typename P3> | ||||
| struct FuncBuilder4 : public FuncPrototype { | ||||
|   ASMJIT_INLINE FuncBuilder4(uint32_t callConv = kCallConvHost) noexcept { | ||||
|     static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3) }; | ||||
|     setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| //! Function prototype (5 arguments).
 | ||||
| template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4> | ||||
| struct FuncBuilder5 : public FuncPrototype { | ||||
|   ASMJIT_INLINE FuncBuilder5(uint32_t callConv = kCallConvHost) noexcept { | ||||
|     static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4) }; | ||||
|     setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| //! Function prototype (6 arguments).
 | ||||
| template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5> | ||||
| struct FuncBuilder6 : public FuncPrototype { | ||||
|   ASMJIT_INLINE FuncBuilder6(uint32_t callConv = kCallConvHost) noexcept { | ||||
|     static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5) }; | ||||
|     setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| //! Function prototype (7 arguments).
 | ||||
| template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6> | ||||
| struct FuncBuilder7 : public FuncPrototype { | ||||
|   ASMJIT_INLINE FuncBuilder7(uint32_t callConv = kCallConvHost) noexcept { | ||||
|     static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6) }; | ||||
|     setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| //! Function prototype (8 arguments).
 | ||||
| template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7> | ||||
| struct FuncBuilder8 : public FuncPrototype { | ||||
|   ASMJIT_INLINE FuncBuilder8(uint32_t callConv = kCallConvHost) noexcept { | ||||
|     static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6), T(P7) }; | ||||
|     setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| //! Function prototype (9 arguments).
 | ||||
| template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8> | ||||
| struct FuncBuilder9 : public FuncPrototype { | ||||
|   ASMJIT_INLINE FuncBuilder9(uint32_t callConv = kCallConvHost) noexcept { | ||||
|     static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6), T(P7), T(P8) }; | ||||
|     setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| //! Function prototype (10 arguments).
 | ||||
| template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9> | ||||
| struct FuncBuilder10 : public FuncPrototype { | ||||
|   ASMJIT_INLINE FuncBuilder10(uint32_t callConv = kCallConvHost) noexcept { | ||||
|     static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6), T(P7), T(P8), T(P9) }; | ||||
|     setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); | ||||
|   } | ||||
| }; | ||||
| #undef T | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::FuncDecl]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Function declaration.
 | ||||
| struct FuncDecl { | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors - Calling Convention]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get the function's calling convention, see `CallConv`.
 | ||||
|   ASMJIT_INLINE uint32_t getCallConv() const noexcept { return _callConv; } | ||||
| 
 | ||||
|   //! Get whether the callee pops the stack.
 | ||||
|   ASMJIT_INLINE uint32_t getCalleePopsStack() const noexcept { return _calleePopsStack; } | ||||
| 
 | ||||
|   //! Get direction of arguments passed on the stack.
 | ||||
|   //!
 | ||||
|   //! Direction should be always `kFuncDirRTL`.
 | ||||
|   //!
 | ||||
|   //! NOTE: This is related to used calling convention, it's not affected by
 | ||||
|   //! number of function arguments or their types.
 | ||||
|   ASMJIT_INLINE uint32_t getArgsDirection() const noexcept { return _argsDirection; } | ||||
| 
 | ||||
|   //! Get stack size needed for function arguments passed on the stack.
 | ||||
|   ASMJIT_INLINE uint32_t getArgStackSize() const noexcept { return _argStackSize; } | ||||
|   //! Get size of "Red Zone".
 | ||||
|   ASMJIT_INLINE uint32_t getRedZoneSize() const noexcept { return _redZoneSize; } | ||||
|   //! Get size of "Spill Zone".
 | ||||
|   ASMJIT_INLINE uint32_t getSpillZoneSize() const noexcept { return _spillZoneSize; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors - Arguments and Return]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get whether the function has a return value.
 | ||||
|   ASMJIT_INLINE bool hasRet() const noexcept { return _retCount != 0; } | ||||
|   //! Get count of function return values.
 | ||||
|   ASMJIT_INLINE uint32_t getRetCount() const noexcept { return _retCount; } | ||||
| 
 | ||||
|   //! Get function return value.
 | ||||
|   ASMJIT_INLINE FuncInOut& getRet(uint32_t index = kFuncRetLo) noexcept { return _rets[index]; } | ||||
|   //! Get function return value.
 | ||||
|   ASMJIT_INLINE const FuncInOut& getRet(uint32_t index = kFuncRetLo) const noexcept { return _rets[index]; } | ||||
| 
 | ||||
|   //! Get the number of function arguments.
 | ||||
|   ASMJIT_INLINE uint32_t getNumArgs() const noexcept { return _numArgs; } | ||||
| 
 | ||||
|   //! Get function arguments array.
 | ||||
|   ASMJIT_INLINE FuncInOut* getArgs() noexcept { return _args; } | ||||
|   //! Get function arguments array (const).
 | ||||
|   ASMJIT_INLINE const FuncInOut* getArgs() const noexcept { return _args; } | ||||
| 
 | ||||
|   //! Get function argument at index `index`.
 | ||||
|   ASMJIT_INLINE FuncInOut& getArg(size_t index) noexcept { | ||||
|     ASMJIT_ASSERT(index < kFuncArgCountLoHi); | ||||
|     return _args[index]; | ||||
|   } | ||||
| 
 | ||||
|   //! Get function argument at index `index`.
 | ||||
|   ASMJIT_INLINE const FuncInOut& getArg(size_t index) const noexcept { | ||||
|     ASMJIT_ASSERT(index < kFuncArgCountLoHi); | ||||
|     return _args[index]; | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE void resetArg(size_t index) noexcept { | ||||
|     ASMJIT_ASSERT(index < kFuncArgCountLoHi); | ||||
|     _args[index].reset(); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Calling convention.
 | ||||
|   uint8_t _callConv; | ||||
|   //! Whether a callee pops stack.
 | ||||
|   uint8_t _calleePopsStack : 1; | ||||
|   //! Direction for arguments passed on the stack, see `FuncDir`.
 | ||||
|   uint8_t _argsDirection : 1; | ||||
|   //! Reserved #0 (alignment).
 | ||||
|   uint8_t _reserved0 : 6; | ||||
| 
 | ||||
|   //! Number of function arguments.
 | ||||
|   uint8_t _numArgs; | ||||
|   //! Number of function return values.
 | ||||
|   uint8_t _retCount; | ||||
| 
 | ||||
|   //! Count of bytes consumed by arguments on the stack (aligned).
 | ||||
|   uint32_t _argStackSize; | ||||
| 
 | ||||
|   //! Size of "Red Zone".
 | ||||
|   //!
 | ||||
|   //! NOTE: Used by AMD64-ABI (128 bytes).
 | ||||
|   uint16_t _redZoneSize; | ||||
| 
 | ||||
|   //! Size of "Spill Zone".
 | ||||
|   //!
 | ||||
|   //! NOTE: Used by WIN64-ABI (32 bytes).
 | ||||
|   uint16_t _spillZoneSize; | ||||
| 
 | ||||
|   //! Function arguments (LO & HI) mapped to physical registers and stack.
 | ||||
|   FuncInOut _args[kFuncArgCountLoHi]; | ||||
| 
 | ||||
|   //! Function return value(s).
 | ||||
|   FuncInOut _rets[2]; | ||||
| }; | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // !ASMJIT_DISABLE_COMPILER
 | ||||
| #endif // _ASMJIT_BASE_COMPILERFUNC_H
 | ||||
							
								
								
									
										523
									
								
								DynamicHooks/thirdparty/AsmJit/base/constpool.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										523
									
								
								DynamicHooks/thirdparty/AsmJit/base/constpool.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,523 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/constpool.h" | ||||
| #include "../base/utils.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // Binary tree code is based on Julienne Walker's "Andersson Binary Trees"
 | ||||
| // article and implementation. However, only three operations are implemented -
 | ||||
| // get, insert and traverse.
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::ConstPool::Tree - Ops]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! Remove left horizontal links.
 | ||||
| static ASMJIT_INLINE ConstPool::Node* ConstPoolTree_skewNode(ConstPool::Node* node) noexcept { | ||||
|   ConstPool::Node* link = node->_link[0]; | ||||
|   uint32_t level = node->_level; | ||||
| 
 | ||||
|   if (level != 0 && link != nullptr && link->_level == level) { | ||||
|     node->_link[0] = link->_link[1]; | ||||
|     link->_link[1] = node; | ||||
| 
 | ||||
|     node = link; | ||||
|   } | ||||
| 
 | ||||
|   return node; | ||||
| } | ||||
| 
 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! Remove consecutive horizontal links.
 | ||||
| static ASMJIT_INLINE ConstPool::Node* ConstPoolTree_splitNode(ConstPool::Node* node) noexcept { | ||||
|   ConstPool::Node* link = node->_link[1]; | ||||
|   uint32_t level = node->_level; | ||||
| 
 | ||||
|   if (level != 0 && link != nullptr && link->_link[1] != nullptr && link->_link[1]->_level == level) { | ||||
|     node->_link[1] = link->_link[0]; | ||||
|     link->_link[0] = node; | ||||
| 
 | ||||
|     node = link; | ||||
|     node->_level++; | ||||
|   } | ||||
| 
 | ||||
|   return node; | ||||
| } | ||||
| 
 | ||||
| ConstPool::Node* ConstPool::Tree::get(const void* data) noexcept { | ||||
|   ConstPool::Node* node = _root; | ||||
|   size_t dataSize = _dataSize; | ||||
| 
 | ||||
|   while (node != nullptr) { | ||||
|     int c = ::memcmp(node->getData(), data, dataSize); | ||||
|     if (c == 0) | ||||
|       return node; | ||||
|     node = node->_link[c < 0]; | ||||
|   } | ||||
| 
 | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| void ConstPool::Tree::put(ConstPool::Node* newNode) noexcept { | ||||
|   size_t dataSize = _dataSize; | ||||
| 
 | ||||
|   _length++; | ||||
|   if (_root == nullptr) { | ||||
|     _root = newNode; | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   ConstPool::Node* node = _root; | ||||
|   ConstPool::Node* stack[kHeightLimit]; | ||||
| 
 | ||||
|   unsigned int top = 0; | ||||
|   unsigned int dir; | ||||
| 
 | ||||
|   // Find a spot and save the stack.
 | ||||
|   for (;;) { | ||||
|     stack[top++] = node; | ||||
|     dir = ::memcmp(node->getData(), newNode->getData(), dataSize) < 0; | ||||
| 
 | ||||
|     ConstPool::Node* link = node->_link[dir]; | ||||
|     if (link == nullptr) | ||||
|       break; | ||||
| 
 | ||||
|     node = link; | ||||
|   } | ||||
| 
 | ||||
|   // Link and rebalance.
 | ||||
|   node->_link[dir] = newNode; | ||||
| 
 | ||||
|   while (top > 0) { | ||||
|     // Which child?
 | ||||
|     node = stack[--top]; | ||||
| 
 | ||||
|     if (top != 0) { | ||||
|       dir = stack[top - 1]->_link[1] == node; | ||||
|     } | ||||
| 
 | ||||
|     node = ConstPoolTree_skewNode(node); | ||||
|     node = ConstPoolTree_splitNode(node); | ||||
| 
 | ||||
|     // Fix the parent.
 | ||||
|     if (top != 0) | ||||
|       stack[top - 1]->_link[dir] = node; | ||||
|     else | ||||
|       _root = node; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::ConstPool - Construction / Destruction]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| ConstPool::ConstPool(Zone* zone) noexcept { | ||||
|   _zone = zone; | ||||
| 
 | ||||
|   size_t dataSize = 1; | ||||
|   for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) { | ||||
|     _tree[i].setDataSize(dataSize); | ||||
|     _gaps[i] = nullptr; | ||||
|     dataSize <<= 1; | ||||
|   } | ||||
| 
 | ||||
|   _gapPool = nullptr; | ||||
|   _size = 0; | ||||
|   _alignment = 0; | ||||
| } | ||||
| 
 | ||||
| ConstPool::~ConstPool() noexcept {} | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::ConstPool - Reset]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void ConstPool::reset() noexcept { | ||||
|   for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) { | ||||
|     _tree[i].reset(); | ||||
|     _gaps[i] = nullptr; | ||||
|   } | ||||
| 
 | ||||
|   _gapPool = nullptr; | ||||
|   _size = 0; | ||||
|   _alignment = 0; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::ConstPool - Ops]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| static ASMJIT_INLINE ConstPool::Gap* ConstPool_allocGap(ConstPool* self) noexcept { | ||||
|   ConstPool::Gap* gap = self->_gapPool; | ||||
|   if (gap == nullptr) | ||||
|     return self->_zone->allocT<ConstPool::Gap>(); | ||||
| 
 | ||||
|   self->_gapPool = gap->_next; | ||||
|   return gap; | ||||
| } | ||||
| 
 | ||||
| static ASMJIT_INLINE void ConstPool_freeGap(ConstPool* self,  ConstPool::Gap* gap) noexcept { | ||||
|   gap->_next = self->_gapPool; | ||||
|   self->_gapPool = gap; | ||||
| } | ||||
| 
 | ||||
| static void ConstPool_addGap(ConstPool* self, size_t offset, size_t length) noexcept { | ||||
|   ASMJIT_ASSERT(length > 0); | ||||
| 
 | ||||
|   while (length > 0) { | ||||
|     size_t gapIndex; | ||||
|     size_t gapLength; | ||||
| 
 | ||||
|     if (length >= 16 && Utils::isAligned<size_t>(offset, 16)) { | ||||
|       gapIndex = ConstPool::kIndex16; | ||||
|       gapLength = 16; | ||||
|     } | ||||
|     else if (length >= 8 && Utils::isAligned<size_t>(offset, 8)) { | ||||
|       gapIndex = ConstPool::kIndex8; | ||||
|       gapLength = 8; | ||||
|     } | ||||
|     else if (length >= 4 && Utils::isAligned<size_t>(offset, 4)) { | ||||
|       gapIndex = ConstPool::kIndex4; | ||||
|       gapLength = 4; | ||||
|     } | ||||
|     else if (length >= 2 && Utils::isAligned<size_t>(offset, 2)) { | ||||
|       gapIndex = ConstPool::kIndex2; | ||||
|       gapLength = 2; | ||||
|     } | ||||
|     else { | ||||
|       gapIndex = ConstPool::kIndex1; | ||||
|       gapLength = 1; | ||||
|     } | ||||
| 
 | ||||
|     // We don't have to check for errors here, if this failed nothing really
 | ||||
|     // happened (just the gap won't be visible) and it will fail again at
 | ||||
|     // place where checking will cause kErrorNoHeapMemory.
 | ||||
|     ConstPool::Gap* gap = ConstPool_allocGap(self); | ||||
|     if (gap == nullptr) | ||||
|       return; | ||||
| 
 | ||||
|     gap->_next = self->_gaps[gapIndex]; | ||||
|     self->_gaps[gapIndex] = gap; | ||||
| 
 | ||||
|     gap->_offset = offset; | ||||
|     gap->_length = gapLength; | ||||
| 
 | ||||
|     offset += gapLength; | ||||
|     length -= gapLength; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept { | ||||
|   size_t treeIndex; | ||||
| 
 | ||||
|   if (size == 32) | ||||
|     treeIndex = kIndex32; | ||||
|   else if (size == 16) | ||||
|     treeIndex = kIndex16; | ||||
|   else if (size == 8) | ||||
|     treeIndex = kIndex8; | ||||
|   else if (size == 4) | ||||
|     treeIndex = kIndex4; | ||||
|   else if (size == 2) | ||||
|     treeIndex = kIndex2; | ||||
|   else if (size == 1) | ||||
|     treeIndex = kIndex1; | ||||
|   else | ||||
|     return kErrorInvalidArgument; | ||||
| 
 | ||||
|   ConstPool::Node* node = _tree[treeIndex].get(data); | ||||
|   if (node != nullptr) { | ||||
|     dstOffset = node->_offset; | ||||
|     return kErrorOk; | ||||
|   } | ||||
| 
 | ||||
|   // Before incrementing the current offset try if there is a gap that can
 | ||||
|   // be used for the requested data.
 | ||||
|   size_t offset = ~static_cast<size_t>(0); | ||||
|   size_t gapIndex = treeIndex; | ||||
| 
 | ||||
|   while (gapIndex != kIndexCount - 1) { | ||||
|     ConstPool::Gap* gap = _gaps[treeIndex]; | ||||
| 
 | ||||
|     // Check if there is a gap.
 | ||||
|     if (gap != nullptr) { | ||||
|       size_t gapOffset = gap->_offset; | ||||
|       size_t gapLength = gap->_length; | ||||
| 
 | ||||
|       // Destroy the gap for now.
 | ||||
|       _gaps[treeIndex] = gap->_next; | ||||
|       ConstPool_freeGap(this, gap); | ||||
| 
 | ||||
|       offset = gapOffset; | ||||
|       ASMJIT_ASSERT(Utils::isAligned<size_t>(offset, size)); | ||||
| 
 | ||||
|       gapLength -= size; | ||||
|       if (gapLength > 0) | ||||
|         ConstPool_addGap(this, gapOffset, gapLength); | ||||
|     } | ||||
| 
 | ||||
|     gapIndex++; | ||||
|   } | ||||
| 
 | ||||
|   if (offset == ~static_cast<size_t>(0)) { | ||||
|     // Get how many bytes have to be skipped so the address is aligned accordingly
 | ||||
|     // to the 'size'.
 | ||||
|     size_t diff = Utils::alignDiff<size_t>(_size, size); | ||||
| 
 | ||||
|     if (diff != 0) { | ||||
|       ConstPool_addGap(this, _size, diff); | ||||
|       _size += diff; | ||||
|     } | ||||
| 
 | ||||
|     offset = _size; | ||||
|     _size += size; | ||||
|   } | ||||
| 
 | ||||
|   // Add the initial node to the right index.
 | ||||
|   node = ConstPool::Tree::_newNode(_zone, data, size, offset, false); | ||||
|   if (node == nullptr) | ||||
|     return kErrorNoHeapMemory; | ||||
| 
 | ||||
|   _tree[treeIndex].put(node); | ||||
|   _alignment = Utils::iMax<size_t>(_alignment, size); | ||||
| 
 | ||||
|   dstOffset = offset; | ||||
| 
 | ||||
|   // Now create a bunch of shared constants that are based on the data pattern.
 | ||||
|   // We stop at size 4, it probably doesn't make sense to split constants down
 | ||||
|   // to 1 byte.
 | ||||
|   size_t pCount = 1; | ||||
|   while (size > 4) { | ||||
|     size >>= 1; | ||||
|     pCount <<= 1; | ||||
| 
 | ||||
|     ASMJIT_ASSERT(treeIndex != 0); | ||||
|     treeIndex--; | ||||
| 
 | ||||
|     const uint8_t* pData = static_cast<const uint8_t*>(data); | ||||
|     for (size_t i = 0; i < pCount; i++, pData += size) { | ||||
|       node = _tree[treeIndex].get(pData); | ||||
| 
 | ||||
|       if (node != nullptr) | ||||
|         continue; | ||||
| 
 | ||||
|       node = ConstPool::Tree::_newNode(_zone, pData, size, offset + (i * size), true); | ||||
|       _tree[treeIndex].put(node); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::ConstPool - Reset]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| struct ConstPoolFill { | ||||
|   ASMJIT_INLINE ConstPoolFill(uint8_t* dst, size_t dataSize) noexcept : | ||||
|     _dst(dst), | ||||
|     _dataSize(dataSize) {} | ||||
| 
 | ||||
|   ASMJIT_INLINE void visit(const ConstPool::Node* node) noexcept { | ||||
|     if (!node->_shared) | ||||
|       ::memcpy(_dst + node->_offset, node->getData(), _dataSize); | ||||
|   } | ||||
| 
 | ||||
|   uint8_t* _dst; | ||||
|   size_t _dataSize; | ||||
| }; | ||||
| 
 | ||||
| void ConstPool::fill(void* dst) const noexcept { | ||||
|   // Clears possible gaps, asmjit should never emit garbage to the output.
 | ||||
|   ::memset(dst, 0, _size); | ||||
| 
 | ||||
|   ConstPoolFill filler(static_cast<uint8_t*>(dst), 1); | ||||
|   for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) { | ||||
|     _tree[i].iterate(filler); | ||||
|     filler._dataSize <<= 1; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::ConstPool - Test]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #if defined(ASMJIT_TEST) | ||||
| UNIT(base_constpool) { | ||||
|   Zone zone(32384 - Zone::kZoneOverhead); | ||||
|   ConstPool pool(&zone); | ||||
| 
 | ||||
|   uint32_t i; | ||||
|   uint32_t kCount = 1000000; | ||||
| 
 | ||||
|   INFO("Adding %u constants to the pool.", kCount); | ||||
|   { | ||||
|     size_t prevOffset; | ||||
|     size_t curOffset; | ||||
|     uint64_t c = ASMJIT_UINT64_C(0x0101010101010101); | ||||
| 
 | ||||
|     EXPECT(pool.add(&c, 8, prevOffset) == kErrorOk, | ||||
|       "pool.add() - Returned error."); | ||||
|     EXPECT(prevOffset == 0, | ||||
|       "pool.add() - First constant should have zero offset."); | ||||
| 
 | ||||
|     for (i = 1; i < kCount; i++) { | ||||
|       c++; | ||||
|       EXPECT(pool.add(&c, 8, curOffset) == kErrorOk, | ||||
|         "pool.add() - Returned error."); | ||||
|       EXPECT(prevOffset + 8 == curOffset, | ||||
|         "pool.add() - Returned incorrect curOffset."); | ||||
|       EXPECT(pool.getSize() == (i + 1) * 8, | ||||
|         "pool.getSize() - Reported incorrect size."); | ||||
|       prevOffset = curOffset; | ||||
|     } | ||||
| 
 | ||||
|     EXPECT(pool.getAlignment() == 8, | ||||
|       "pool.getAlignment() - Expected 8-byte alignment."); | ||||
|   } | ||||
| 
 | ||||
|   INFO("Retrieving %u constants from the pool.", kCount); | ||||
|   { | ||||
|     uint64_t c = ASMJIT_UINT64_C(0x0101010101010101); | ||||
| 
 | ||||
|     for (i = 0; i < kCount; i++) { | ||||
|       size_t offset; | ||||
|       EXPECT(pool.add(&c, 8, offset) == kErrorOk, | ||||
|         "pool.add() - Returned error."); | ||||
|       EXPECT(offset == i * 8, | ||||
|         "pool.add() - Should have reused constant."); | ||||
|       c++; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   INFO("Checking if the constants were split into 4-byte patterns."); | ||||
|   { | ||||
|     uint32_t c = 0x01010101; | ||||
|     for (i = 0; i < kCount; i++) { | ||||
|       size_t offset; | ||||
|       EXPECT(pool.add(&c, 4, offset) == kErrorOk, | ||||
|         "pool.add() - Returned error."); | ||||
|       EXPECT(offset == i * 8, | ||||
|         "pool.add() - Should reuse existing constant."); | ||||
|       c++; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   INFO("Adding 2 byte constant to misalign the current offset."); | ||||
|   { | ||||
|     uint16_t c = 0xFFFF; | ||||
|     size_t offset; | ||||
| 
 | ||||
|     EXPECT(pool.add(&c, 2, offset) == kErrorOk, | ||||
|       "pool.add() - Returned error."); | ||||
|     EXPECT(offset == kCount * 8, | ||||
|       "pool.add() - Didn't return expected position."); | ||||
|     EXPECT(pool.getAlignment() == 8, | ||||
|       "pool.getAlignment() - Expected 8-byte alignment."); | ||||
|   } | ||||
| 
 | ||||
|   INFO("Adding 8 byte constant to check if pool gets aligned again."); | ||||
|   { | ||||
|     uint64_t c = ASMJIT_UINT64_C(0xFFFFFFFFFFFFFFFF); | ||||
|     size_t offset; | ||||
| 
 | ||||
|     EXPECT(pool.add(&c, 8, offset) == kErrorOk, | ||||
|       "pool.add() - Returned error."); | ||||
|     EXPECT(offset == kCount * 8 + 8, | ||||
|       "pool.add() - Didn't return aligned offset."); | ||||
|   } | ||||
| 
 | ||||
|   INFO("Adding 2 byte constant to verify the gap is filled."); | ||||
|   { | ||||
|     uint16_t c = 0xFFFE; | ||||
|     size_t offset; | ||||
| 
 | ||||
|     EXPECT(pool.add(&c, 2, offset) == kErrorOk, | ||||
|       "pool.add() - Returned error."); | ||||
|     EXPECT(offset == kCount * 8 + 2, | ||||
|       "pool.add() - Didn't fill the gap."); | ||||
|     EXPECT(pool.getAlignment() == 8, | ||||
|       "pool.getAlignment() - Expected 8-byte alignment."); | ||||
|   } | ||||
| 
 | ||||
|   INFO("Checking reset functionality."); | ||||
|   { | ||||
|     pool.reset(); | ||||
| 
 | ||||
|     EXPECT(pool.getSize() == 0, | ||||
|       "pool.getSize() - Expected pool size to be zero."); | ||||
|     EXPECT(pool.getAlignment() == 0, | ||||
|       "pool.getSize() - Expected pool alignment to be zero."); | ||||
|   } | ||||
| 
 | ||||
|   INFO("Checking pool alignment when combined constants are added."); | ||||
|   { | ||||
|     uint8_t bytes[32] = { 0 }; | ||||
|     size_t offset; | ||||
| 
 | ||||
|     pool.add(bytes, 1, offset); | ||||
| 
 | ||||
|     EXPECT(pool.getSize() == 1, | ||||
|       "pool.getSize() - Expected pool size to be 1 byte."); | ||||
|     EXPECT(pool.getAlignment() == 1, | ||||
|       "pool.getSize() - Expected pool alignment to be 1 byte."); | ||||
|     EXPECT(offset == 0, | ||||
|       "pool.getSize() - Expected offset returned to be zero."); | ||||
| 
 | ||||
|     pool.add(bytes, 2, offset); | ||||
| 
 | ||||
|     EXPECT(pool.getSize() == 4, | ||||
|       "pool.getSize() - Expected pool size to be 4 bytes."); | ||||
|     EXPECT(pool.getAlignment() == 2, | ||||
|       "pool.getSize() - Expected pool alignment to be 2 bytes."); | ||||
|     EXPECT(offset == 2, | ||||
|       "pool.getSize() - Expected offset returned to be 2."); | ||||
| 
 | ||||
|     pool.add(bytes, 4, offset); | ||||
| 
 | ||||
|     EXPECT(pool.getSize() == 8, | ||||
|       "pool.getSize() - Expected pool size to be 8 bytes."); | ||||
|     EXPECT(pool.getAlignment() == 4, | ||||
|       "pool.getSize() - Expected pool alignment to be 4 bytes."); | ||||
|     EXPECT(offset == 4, | ||||
|       "pool.getSize() - Expected offset returned to be 4."); | ||||
| 
 | ||||
|     pool.add(bytes, 4, offset); | ||||
| 
 | ||||
|     EXPECT(pool.getSize() == 8, | ||||
|       "pool.getSize() - Expected pool size to be 8 bytes."); | ||||
|     EXPECT(pool.getAlignment() == 4, | ||||
|       "pool.getSize() - Expected pool alignment to be 4 bytes."); | ||||
|     EXPECT(offset == 4, | ||||
|       "pool.getSize() - Expected offset returned to be 8."); | ||||
| 
 | ||||
|     pool.add(bytes, 32, offset); | ||||
|     EXPECT(pool.getSize() == 64, | ||||
|       "pool.getSize() - Expected pool size to be 64 bytes."); | ||||
|     EXPECT(pool.getAlignment() == 32, | ||||
|       "pool.getSize() - Expected pool alignment to be 32 bytes."); | ||||
|     EXPECT(offset == 32, | ||||
|       "pool.getSize() - Expected offset returned to be 32."); | ||||
|   } | ||||
| } | ||||
| #endif // ASMJIT_TEST
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
							
								
								
									
										283
									
								
								DynamicHooks/thirdparty/AsmJit/base/constpool.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								DynamicHooks/thirdparty/AsmJit/base/constpool.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,283 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_BASE_CONSTPOOL_H | ||||
| #define _ASMJIT_BASE_CONSTPOOL_H | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/zone.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| //! \addtogroup asmjit_base
 | ||||
| //! \{
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::ConstPool]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Constant pool.
 | ||||
| class ConstPool { | ||||
|  public: | ||||
|   ASMJIT_NO_COPY(ConstPool) | ||||
| 
 | ||||
|   enum { | ||||
|     kIndex1 = 0, | ||||
|     kIndex2 = 1, | ||||
|     kIndex4 = 2, | ||||
|     kIndex8 = 3, | ||||
|     kIndex16 = 4, | ||||
|     kIndex32 = 5, | ||||
|     kIndexCount = 6 | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Gap]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Zone-allocated const-pool gap.
 | ||||
|   struct Gap { | ||||
|     //! Link to the next gap
 | ||||
|     Gap* _next; | ||||
|     //! Offset of the gap.
 | ||||
|     size_t _offset; | ||||
|     //! Remaining bytes of the gap (basically a gap size).
 | ||||
|     size_t _length; | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Node]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Zone-allocated const-pool node.
 | ||||
|   struct Node { | ||||
|     // --------------------------------------------------------------------------
 | ||||
|     // [Accessors]
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     ASMJIT_INLINE void* getData() const noexcept { | ||||
|       return static_cast<void*>(const_cast<ConstPool::Node*>(this) + 1); | ||||
|     } | ||||
| 
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
|     // [Members]
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     //! Left/Right nodes.
 | ||||
|     Node* _link[2]; | ||||
|     //! Horizontal level for balance.
 | ||||
|     uint32_t _level : 31; | ||||
|     //! Whether this constant is shared with another.
 | ||||
|     uint32_t _shared : 1; | ||||
|     //! Data offset from the beginning of the pool.
 | ||||
|     uint32_t _offset; | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Tree]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! Zone-allocated const-pool tree.
 | ||||
|   struct Tree { | ||||
|     enum { | ||||
|       //! Maximum tree height == log2(1 << 64).
 | ||||
|       kHeightLimit = 64 | ||||
|     }; | ||||
| 
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
|     // [Construction / Destruction]
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     ASMJIT_INLINE Tree(size_t dataSize = 0) noexcept | ||||
|       : _root(nullptr), | ||||
|         _length(0), | ||||
|         _dataSize(dataSize) {} | ||||
|     ASMJIT_INLINE ~Tree() {} | ||||
| 
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
|     // [Reset]
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     ASMJIT_INLINE void reset() noexcept { | ||||
|       _root = nullptr; | ||||
|       _length = 0; | ||||
|     } | ||||
| 
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
|     // [Accessors]
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; } | ||||
|     ASMJIT_INLINE size_t getLength() const noexcept { return _length; } | ||||
| 
 | ||||
|     ASMJIT_INLINE void setDataSize(size_t dataSize) noexcept { | ||||
|       ASMJIT_ASSERT(isEmpty()); | ||||
|       _dataSize = dataSize; | ||||
|     } | ||||
| 
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
|     // [Ops]
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     ASMJIT_API Node* get(const void* data) noexcept; | ||||
|     ASMJIT_API void put(Node* node) noexcept; | ||||
| 
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
|     // [Iterate]
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     template<typename Visitor> | ||||
|     ASMJIT_INLINE void iterate(Visitor& visitor) const noexcept { | ||||
|       Node* node = const_cast<Node*>(_root); | ||||
|       if (node == nullptr) | ||||
|         return; | ||||
| 
 | ||||
|       Node* stack[kHeightLimit]; | ||||
|       size_t top = 0; | ||||
| 
 | ||||
|       for (;;) { | ||||
|         Node* left = node->_link[0]; | ||||
|         if (left != nullptr) { | ||||
|           ASMJIT_ASSERT(top != kHeightLimit); | ||||
|           stack[top++] = node; | ||||
| 
 | ||||
|           node = left; | ||||
|           continue; | ||||
|         } | ||||
| 
 | ||||
| L_Visit: | ||||
|         visitor.visit(node); | ||||
|         node = node->_link[1]; | ||||
|         if (node != nullptr) | ||||
|           continue; | ||||
| 
 | ||||
|         if (top == 0) | ||||
|           return; | ||||
| 
 | ||||
|         node = stack[--top]; | ||||
|         goto L_Visit; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
|     // [Helpers]
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     static ASMJIT_INLINE Node* _newNode(Zone* zone, const void* data, size_t size, size_t offset, bool shared) noexcept { | ||||
|       Node* node = zone->allocT<Node>(sizeof(Node) + size); | ||||
|       if (node == nullptr) | ||||
|         return nullptr; | ||||
| 
 | ||||
|       node->_link[0] = nullptr; | ||||
|       node->_link[1] = nullptr; | ||||
|       node->_level = 1; | ||||
|       node->_shared = shared; | ||||
|       node->_offset = static_cast<uint32_t>(offset); | ||||
| 
 | ||||
|       ::memcpy(node->getData(), data, size); | ||||
|       return node; | ||||
|     } | ||||
| 
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
|     // [Members]
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     //! Root of the tree
 | ||||
|     Node* _root; | ||||
|     //! Length of the tree (count of nodes).
 | ||||
|     size_t _length; | ||||
|     //! Size of the data.
 | ||||
|     size_t _dataSize; | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_API ConstPool(Zone* zone) noexcept; | ||||
|   ASMJIT_API ~ConstPool() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Reset]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_API void reset() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Ops]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get whether the constant-pool is empty.
 | ||||
|   ASMJIT_INLINE bool isEmpty() const noexcept { return _size == 0; } | ||||
|   //! Get the size of the constant-pool in bytes.
 | ||||
|   ASMJIT_INLINE size_t getSize() const noexcept { return _size; } | ||||
|   //! Get minimum alignment.
 | ||||
|   ASMJIT_INLINE size_t getAlignment() const noexcept { return _alignment; } | ||||
| 
 | ||||
|   //! Add a constant to the constant pool.
 | ||||
|   //!
 | ||||
|   //! The constant must have known size, which is 1, 2, 4, 8, 16 or 32 bytes.
 | ||||
|   //! The constant is added to the pool only if it doesn't not exist, otherwise
 | ||||
|   //! cached value is returned.
 | ||||
|   //!
 | ||||
|   //! AsmJit is able to subdivide added constants, so for example if you add
 | ||||
|   //! 8-byte constant 0x1122334455667788 it will create the following slots:
 | ||||
|   //!
 | ||||
|   //!   8-byte: 0x1122334455667788
 | ||||
|   //!   4-byte: 0x11223344, 0x55667788
 | ||||
|   //!
 | ||||
|   //! The reason is that when combining MMX/SSE/AVX code some patterns are used
 | ||||
|   //! frequently. However, AsmJit is not able to reallocate a constant that has
 | ||||
|   //! been already added. For example if you try to add 4-byte constant and then
 | ||||
|   //! 8-byte constant having the same 4-byte pattern as the previous one, two
 | ||||
|   //! independent slots will be generated by the pool.
 | ||||
|   ASMJIT_API Error add(const void* data, size_t size, size_t& dstOffset) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Fill]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Fill the destination with the constants from the pool.
 | ||||
|   ASMJIT_API void fill(void* dst) const noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Zone allocator.
 | ||||
|   Zone* _zone; | ||||
|   //! Tree per size.
 | ||||
|   Tree _tree[kIndexCount]; | ||||
|   //! Gaps per size.
 | ||||
|   Gap* _gaps[kIndexCount]; | ||||
|   //! Gaps pool
 | ||||
|   Gap* _gapPool; | ||||
| 
 | ||||
|   //! Size of the pool (in bytes).
 | ||||
|   size_t _size; | ||||
|   //! Alignemnt.
 | ||||
|   size_t _alignment; | ||||
| }; | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_BASE_CONSTPOOL_H
 | ||||
							
								
								
									
										374
									
								
								DynamicHooks/thirdparty/AsmJit/base/containers.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										374
									
								
								DynamicHooks/thirdparty/AsmJit/base/containers.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,374 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/containers.h" | ||||
| #include "../base/utils.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::StringBuilder - Construction / Destruction]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // Should be placed in read-only memory.
 | ||||
| static const char StringBuilder_empty[4] = { 0 }; | ||||
| 
 | ||||
| StringBuilder::StringBuilder() noexcept | ||||
|   : _data(const_cast<char*>(StringBuilder_empty)), | ||||
|     _length(0), | ||||
|     _capacity(0), | ||||
|     _canFree(false) {} | ||||
| 
 | ||||
| StringBuilder::~StringBuilder() noexcept { | ||||
|   if (_canFree) | ||||
|     ASMJIT_FREE(_data); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::StringBuilder - Prepare / Reserve]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| char* StringBuilder::prepare(uint32_t op, size_t len) noexcept { | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Set]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   if (op == kStringOpSet) { | ||||
|     // We don't care here, but we can't return a NULL pointer since it indicates
 | ||||
|     // failure in memory allocation.
 | ||||
|     if (len == 0) { | ||||
|       if (_data != StringBuilder_empty) | ||||
|         _data[0] = 0; | ||||
| 
 | ||||
|       _length = 0; | ||||
|       return _data; | ||||
|     } | ||||
| 
 | ||||
|     if (_capacity < len) { | ||||
|       if (len >= IntTraits<size_t>::maxValue() - sizeof(intptr_t) * 2) | ||||
|         return nullptr; | ||||
| 
 | ||||
|       size_t to = Utils::alignTo<size_t>(len, sizeof(intptr_t)); | ||||
|       if (to < 256 - sizeof(intptr_t)) | ||||
|         to = 256 - sizeof(intptr_t); | ||||
| 
 | ||||
|       char* newData = static_cast<char*>(ASMJIT_ALLOC(to + sizeof(intptr_t))); | ||||
|       if (newData == nullptr) { | ||||
|         clear(); | ||||
|         return nullptr; | ||||
|       } | ||||
| 
 | ||||
|       if (_canFree) | ||||
|         ASMJIT_FREE(_data); | ||||
| 
 | ||||
|       _data = newData; | ||||
|       _capacity = to + sizeof(intptr_t) - 1; | ||||
|       _canFree = true; | ||||
|     } | ||||
| 
 | ||||
|     _data[len] = 0; | ||||
|     _length = len; | ||||
| 
 | ||||
|     ASMJIT_ASSERT(_length <= _capacity); | ||||
|     return _data; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Append]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   else { | ||||
|     // We don't care here, but we can't return a nullptr pointer since it indicates
 | ||||
|     // failure in memory allocation.
 | ||||
|     if (len == 0) | ||||
|       return _data + _length; | ||||
| 
 | ||||
|     // Overflow.
 | ||||
|     if (IntTraits<size_t>::maxValue() - sizeof(intptr_t) * 2 - _length < len) | ||||
|       return nullptr; | ||||
| 
 | ||||
|     size_t after = _length + len; | ||||
|     if (_capacity < after) { | ||||
|       size_t to = _capacity; | ||||
| 
 | ||||
|       if (to < 256) | ||||
|         to = 256; | ||||
| 
 | ||||
|       while (to < 1024 * 1024 && to < after) | ||||
|         to *= 2; | ||||
| 
 | ||||
|       if (to < after) { | ||||
|         to = after; | ||||
|         if (to < (IntTraits<size_t>::maxValue() - 1024 * 32)) | ||||
|           to = Utils::alignTo<size_t>(to, 1024 * 32); | ||||
|       } | ||||
| 
 | ||||
|       to = Utils::alignTo<size_t>(to, sizeof(intptr_t)); | ||||
|       char* newData = static_cast<char*>(ASMJIT_ALLOC(to + sizeof(intptr_t))); | ||||
| 
 | ||||
|       if (newData == nullptr) | ||||
|         return nullptr; | ||||
| 
 | ||||
|       ::memcpy(newData, _data, _length); | ||||
|       if (_canFree) | ||||
|         ASMJIT_FREE(_data); | ||||
| 
 | ||||
|       _data = newData; | ||||
|       _capacity = to + sizeof(intptr_t) - 1; | ||||
|       _canFree = true; | ||||
|     } | ||||
| 
 | ||||
|     char* ret = _data + _length; | ||||
|     _data[after] = 0; | ||||
|     _length = after; | ||||
| 
 | ||||
|     ASMJIT_ASSERT(_length <= _capacity); | ||||
|     return ret; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| bool StringBuilder::reserve(size_t to) noexcept { | ||||
|   if (_capacity >= to) | ||||
|     return true; | ||||
| 
 | ||||
|   if (to >= IntTraits<size_t>::maxValue() - sizeof(intptr_t) * 2) | ||||
|     return false; | ||||
| 
 | ||||
|   to = Utils::alignTo<size_t>(to, sizeof(intptr_t)); | ||||
| 
 | ||||
|   char* newData = static_cast<char*>(ASMJIT_ALLOC(to + sizeof(intptr_t))); | ||||
|   if (newData == nullptr) | ||||
|     return false; | ||||
| 
 | ||||
|   ::memcpy(newData, _data, _length + 1); | ||||
|   if (_canFree) | ||||
|     ASMJIT_FREE(_data); | ||||
| 
 | ||||
|   _data = newData; | ||||
|   _capacity = to + sizeof(intptr_t) - 1; | ||||
|   _canFree = true; | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::StringBuilder - Clear]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void StringBuilder::clear() noexcept { | ||||
|   if (_data != StringBuilder_empty) | ||||
|     _data[0] = 0; | ||||
|   _length = 0; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::StringBuilder - Methods]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| bool StringBuilder::_opString(uint32_t op, const char* str, size_t len) noexcept { | ||||
|   if (len == kInvalidIndex) | ||||
|     len = str != nullptr ? ::strlen(str) : static_cast<size_t>(0); | ||||
| 
 | ||||
|   char* p = prepare(op, len); | ||||
|   if (p == nullptr) | ||||
|     return false; | ||||
| 
 | ||||
|   ::memcpy(p, str, len); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool StringBuilder::_opChar(uint32_t op, char c) noexcept { | ||||
|   char* p = prepare(op, 1); | ||||
|   if (p == nullptr) | ||||
|     return false; | ||||
| 
 | ||||
|   *p = c; | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool StringBuilder::_opChars(uint32_t op, char c, size_t len) noexcept { | ||||
|   char* p = prepare(op, len); | ||||
|   if (p == nullptr) | ||||
|     return false; | ||||
| 
 | ||||
|   ::memset(p, c, len); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| static const char StringBuilder_numbers[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | ||||
| 
 | ||||
| bool StringBuilder::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, uint32_t flags) noexcept { | ||||
|   if (base < 2 || base > 36) | ||||
|     base = 10; | ||||
| 
 | ||||
|   char buf[128]; | ||||
|   char* p = buf + ASMJIT_ARRAY_SIZE(buf); | ||||
| 
 | ||||
|   uint64_t orig = i; | ||||
|   char sign = '\0'; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Sign]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   if ((flags & kStringFormatSigned) != 0 && static_cast<int64_t>(i) < 0) { | ||||
|     i = static_cast<uint64_t>(-static_cast<int64_t>(i)); | ||||
|     sign = '-'; | ||||
|   } | ||||
|   else if ((flags & kStringFormatShowSign) != 0) { | ||||
|     sign = '+'; | ||||
|   } | ||||
|   else if ((flags & kStringFormatShowSpace) != 0) { | ||||
|     sign = ' '; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Number]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   do { | ||||
|     uint64_t d = i / base; | ||||
|     uint64_t r = i % base; | ||||
| 
 | ||||
|     *--p = StringBuilder_numbers[r]; | ||||
|     i = d; | ||||
|   } while (i); | ||||
| 
 | ||||
|   size_t numberLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Alternate Form]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   if ((flags & kStringFormatAlternate) != 0) { | ||||
|     if (base == 8) { | ||||
|       if (orig != 0) | ||||
|         *--p = '0'; | ||||
|     } | ||||
|     if (base == 16) { | ||||
|       *--p = 'x'; | ||||
|       *--p = '0'; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Width]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   if (sign != 0) | ||||
|     *--p = sign; | ||||
| 
 | ||||
|   if (width > 256) | ||||
|     width = 256; | ||||
| 
 | ||||
|   if (width <= numberLength) | ||||
|     width = 0; | ||||
|   else | ||||
|     width -= numberLength; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // Write]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   size_t prefixLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p) - numberLength; | ||||
|   char* data = prepare(op, prefixLength + width + numberLength); | ||||
| 
 | ||||
|   if (data == nullptr) | ||||
|     return false; | ||||
| 
 | ||||
|   ::memcpy(data, p, prefixLength); | ||||
|   data += prefixLength; | ||||
| 
 | ||||
|   ::memset(data, '0', width); | ||||
|   data += width; | ||||
| 
 | ||||
|   ::memcpy(data, p + prefixLength, numberLength); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool StringBuilder::_opHex(uint32_t op, const void* data, size_t len) noexcept { | ||||
|   if (len >= IntTraits<size_t>::maxValue() / 2) | ||||
|     return false; | ||||
| 
 | ||||
|   char* dst = prepare(op, len * 2); | ||||
|   if (dst == nullptr) | ||||
|     return false; | ||||
| 
 | ||||
|   const char* src = static_cast<const char*>(data); | ||||
|   for (size_t i = 0; i < len; i++, dst += 2, src += 1) | ||||
|   { | ||||
|     dst[0] = StringBuilder_numbers[(src[0] >> 4) & 0xF]; | ||||
|     dst[1] = StringBuilder_numbers[(src[0]     ) & 0xF]; | ||||
|   } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool StringBuilder::_opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept { | ||||
|   char buf[1024]; | ||||
| 
 | ||||
|   vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap); | ||||
|   buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0'; | ||||
| 
 | ||||
|   return _opString(op, buf); | ||||
| } | ||||
| 
 | ||||
| bool StringBuilder::setFormat(const char* fmt, ...) noexcept { | ||||
|   bool result; | ||||
| 
 | ||||
|   va_list ap; | ||||
|   va_start(ap, fmt); | ||||
|   result = _opVFormat(kStringOpSet, fmt, ap); | ||||
|   va_end(ap); | ||||
| 
 | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| bool StringBuilder::appendFormat(const char* fmt, ...) noexcept { | ||||
|   bool result; | ||||
| 
 | ||||
|   va_list ap; | ||||
|   va_start(ap, fmt); | ||||
|   result = _opVFormat(kStringOpAppend, fmt, ap); | ||||
|   va_end(ap); | ||||
| 
 | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| bool StringBuilder::eq(const char* str, size_t len) const noexcept { | ||||
|   const char* aData = _data; | ||||
|   const char* bData = str; | ||||
| 
 | ||||
|   size_t aLength = _length; | ||||
|   size_t bLength = len; | ||||
| 
 | ||||
|   if (bLength == kInvalidIndex) { | ||||
|     size_t i; | ||||
|     for (i = 0; i < aLength; i++) { | ||||
|       if (aData[i] != bData[i] || bData[i] == 0) | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return bData[i] == 0; | ||||
|   } | ||||
|   else { | ||||
|     if (aLength != bLength) | ||||
|       return false; | ||||
| 
 | ||||
|     return ::memcmp(aData, bData, aLength) == 0; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
							
								
								
									
										550
									
								
								DynamicHooks/thirdparty/AsmJit/base/containers.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										550
									
								
								DynamicHooks/thirdparty/AsmJit/base/containers.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,550 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_BASE_CONTAINERS_H | ||||
| #define _ASMJIT_BASE_CONTAINERS_H | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/globals.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| //! \addtogroup asmjit_base
 | ||||
| //! \{
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::BitArray]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Fixed size bit-array.
 | ||||
| //!
 | ||||
| //! Used by variable liveness analysis.
 | ||||
| struct BitArray { | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Enums]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   enum { | ||||
|     kEntitySize = static_cast<int>(sizeof(uintptr_t)), | ||||
|     kEntityBits = kEntitySize * 8 | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE uintptr_t getBit(uint32_t index) const noexcept { | ||||
|     return (data[index / kEntityBits] >> (index % kEntityBits)) & 1; | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE void setBit(uint32_t index) noexcept { | ||||
|     data[index / kEntityBits] |= static_cast<uintptr_t>(1) << (index % kEntityBits); | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE void delBit(uint32_t index) noexcept { | ||||
|     data[index / kEntityBits] &= ~(static_cast<uintptr_t>(1) << (index % kEntityBits)); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Interface]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Copy bits from `s0`, returns `true` if at least one bit is set in `s0`.
 | ||||
|   ASMJIT_INLINE bool copyBits(const BitArray* s0, uint32_t len) noexcept { | ||||
|     uintptr_t r = 0; | ||||
|     for (uint32_t i = 0; i < len; i++) { | ||||
|       uintptr_t t = s0->data[i]; | ||||
|       data[i] = t; | ||||
|       r |= t; | ||||
|     } | ||||
|     return r != 0; | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE bool addBits(const BitArray* s0, uint32_t len) noexcept { | ||||
|     return addBits(this, s0, len); | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE bool addBits(const BitArray* s0, const BitArray* s1, uint32_t len) noexcept { | ||||
|     uintptr_t r = 0; | ||||
|     for (uint32_t i = 0; i < len; i++) { | ||||
|       uintptr_t t = s0->data[i] | s1->data[i]; | ||||
|       data[i] = t; | ||||
|       r |= t; | ||||
|     } | ||||
|     return r != 0; | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE bool andBits(const BitArray* s1, uint32_t len) noexcept { | ||||
|     return andBits(this, s1, len); | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE bool andBits(const BitArray* s0, const BitArray* s1, uint32_t len) noexcept { | ||||
|     uintptr_t r = 0; | ||||
|     for (uint32_t i = 0; i < len; i++) { | ||||
|       uintptr_t t = s0->data[i] & s1->data[i]; | ||||
|       data[i] = t; | ||||
|       r |= t; | ||||
|     } | ||||
|     return r != 0; | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE bool delBits(const BitArray* s1, uint32_t len) noexcept { | ||||
|     return delBits(this, s1, len); | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE bool delBits(const BitArray* s0, const BitArray* s1, uint32_t len) noexcept { | ||||
|     uintptr_t r = 0; | ||||
|     for (uint32_t i = 0; i < len; i++) { | ||||
|       uintptr_t t = s0->data[i] & ~s1->data[i]; | ||||
|       data[i] = t; | ||||
|       r |= t; | ||||
|     } | ||||
|     return r != 0; | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE bool _addBitsDelSource(BitArray* s1, uint32_t len) noexcept { | ||||
|     return _addBitsDelSource(this, s1, len); | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE bool _addBitsDelSource(const BitArray* s0, BitArray* s1, uint32_t len) noexcept { | ||||
|     uintptr_t r = 0; | ||||
|     for (uint32_t i = 0; i < len; i++) { | ||||
|       uintptr_t a = s0->data[i]; | ||||
|       uintptr_t b = s1->data[i]; | ||||
| 
 | ||||
|       this->data[i] = a | b; | ||||
|       b &= ~a; | ||||
| 
 | ||||
|       s1->data[i] = b; | ||||
|       r |= b; | ||||
|     } | ||||
|     return r != 0; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   uintptr_t data[1]; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::PodList<T>]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! \internal
 | ||||
| template <typename T> | ||||
| class PodList { | ||||
|  public: | ||||
|   ASMJIT_NO_COPY(PodList<T>) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Link]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   struct Link { | ||||
|     // --------------------------------------------------------------------------
 | ||||
|     // [Accessors]
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     //! Get next node.
 | ||||
|     ASMJIT_INLINE Link* getNext() const noexcept { return _next; } | ||||
| 
 | ||||
|     //! Get value.
 | ||||
|     ASMJIT_INLINE T getValue() const noexcept { return _value; } | ||||
|     //! Set value to `value`.
 | ||||
|     ASMJIT_INLINE void setValue(const T& value) noexcept { _value = value; } | ||||
| 
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
|     // [Members]
 | ||||
|     // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     Link* _next; | ||||
|     T _value; | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE PodList() noexcept : _first(nullptr), _last(nullptr) {} | ||||
|   ASMJIT_INLINE ~PodList() noexcept {} | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Data]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE bool isEmpty() const noexcept { return _first != nullptr; } | ||||
| 
 | ||||
|   ASMJIT_INLINE Link* getFirst() const noexcept { return _first; } | ||||
|   ASMJIT_INLINE Link* getLast() const noexcept { return _last; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Ops]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE void reset() noexcept { | ||||
|     _first = nullptr; | ||||
|     _last = nullptr; | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE void prepend(Link* link) noexcept { | ||||
|     link->_next = _first; | ||||
|     if (_first == nullptr) | ||||
|       _last = link; | ||||
|     _first = link; | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE void append(Link* link) noexcept { | ||||
|     link->_next = nullptr; | ||||
|     if (_first == nullptr) | ||||
|       _first = link; | ||||
|     else | ||||
|       _last->_next = link; | ||||
|     _last = link; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   Link* _first; | ||||
|   Link* _last; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::StringBuilder]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! String builder.
 | ||||
| //!
 | ||||
| //! String builder was designed to be able to build a string using append like
 | ||||
| //! operation to append numbers, other strings, or signle characters. It can
 | ||||
| //! allocate it's own buffer or use a buffer created on the stack.
 | ||||
| //!
 | ||||
| //! String builder contains method specific to AsmJit functionality, used for
 | ||||
| //! logging or HTML output.
 | ||||
| class StringBuilder { | ||||
|  public: | ||||
|   ASMJIT_NO_COPY(StringBuilder) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Enums]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! String operation.
 | ||||
|   ASMJIT_ENUM(StringOp) { | ||||
|     //! Replace the current string by a given content.
 | ||||
|     kStringOpSet = 0, | ||||
|     //! Append a given content to the current string.
 | ||||
|     kStringOpAppend = 1 | ||||
|   }; | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! String format flags.
 | ||||
|   ASMJIT_ENUM(StringFormatFlags) { | ||||
|     kStringFormatShowSign  = 0x00000001, | ||||
|     kStringFormatShowSpace = 0x00000002, | ||||
|     kStringFormatAlternate = 0x00000004, | ||||
|     kStringFormatSigned    = 0x80000000 | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_API StringBuilder() noexcept; | ||||
|   ASMJIT_API ~StringBuilder() noexcept; | ||||
| 
 | ||||
|   ASMJIT_INLINE StringBuilder(const _NoInit&) noexcept {} | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get string builder capacity.
 | ||||
|   ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; } | ||||
|   //! Get length.
 | ||||
|   ASMJIT_INLINE size_t getLength() const noexcept { return _length; } | ||||
| 
 | ||||
|   //! Get null-terminated string data.
 | ||||
|   ASMJIT_INLINE char* getData() noexcept { return _data; } | ||||
|   //! Get null-terminated string data (const).
 | ||||
|   ASMJIT_INLINE const char* getData() const noexcept { return _data; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Prepare / Reserve]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Prepare to set/append.
 | ||||
|   ASMJIT_API char* prepare(uint32_t op, size_t len) noexcept; | ||||
| 
 | ||||
|   //! Reserve `to` bytes in string builder.
 | ||||
|   ASMJIT_API bool reserve(size_t to) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Clear]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Clear the content in String builder.
 | ||||
|   ASMJIT_API void clear() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Op]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_API bool _opString(uint32_t op, const char* str, size_t len = kInvalidIndex) noexcept; | ||||
|   ASMJIT_API bool _opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept; | ||||
|   ASMJIT_API bool _opChar(uint32_t op, char c) noexcept; | ||||
|   ASMJIT_API bool _opChars(uint32_t op, char c, size_t len) noexcept; | ||||
|   ASMJIT_API bool _opNumber(uint32_t op, uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept; | ||||
|   ASMJIT_API bool _opHex(uint32_t op, const void* data, size_t len) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Set]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Replace the current content by `str` of `len`.
 | ||||
|   ASMJIT_INLINE bool setString(const char* str, size_t len = kInvalidIndex) noexcept { | ||||
|     return _opString(kStringOpSet, str, len); | ||||
|   } | ||||
| 
 | ||||
|   //! Replace the current content by formatted string `fmt`.
 | ||||
|   ASMJIT_INLINE bool setVFormat(const char* fmt, va_list ap) noexcept { | ||||
|     return _opVFormat(kStringOpSet, fmt, ap); | ||||
|   } | ||||
| 
 | ||||
|   //! Replace the current content by formatted string `fmt`.
 | ||||
|   ASMJIT_API bool setFormat(const char* fmt, ...) noexcept; | ||||
| 
 | ||||
|   //! Replace the current content by `c` character.
 | ||||
|   ASMJIT_INLINE bool setChar(char c) noexcept { | ||||
|     return _opChar(kStringOpSet, c); | ||||
|   } | ||||
| 
 | ||||
|   //! Replace the current content by `c` of `len`.
 | ||||
|   ASMJIT_INLINE bool setChars(char c, size_t len) noexcept { | ||||
|     return _opChars(kStringOpSet, c, len); | ||||
|   } | ||||
| 
 | ||||
|   //! Replace the current content by formatted integer `i`.
 | ||||
|   ASMJIT_INLINE bool setInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { | ||||
|     return _opNumber(kStringOpSet, i, base, width, flags | kStringFormatSigned); | ||||
|   } | ||||
| 
 | ||||
|   //! Replace the current content by formatted integer `i`.
 | ||||
|   ASMJIT_INLINE bool setUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { | ||||
|     return _opNumber(kStringOpSet, i, base, width, flags); | ||||
|   } | ||||
| 
 | ||||
|   //! Replace the current content by the given `data` converted to a HEX string.
 | ||||
|   ASMJIT_INLINE bool setHex(const void* data, size_t len) noexcept { | ||||
|     return _opHex(kStringOpSet, data, len); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Append]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Append `str` of `len`.
 | ||||
|   ASMJIT_INLINE bool appendString(const char* str, size_t len = kInvalidIndex) noexcept { | ||||
|     return _opString(kStringOpAppend, str, len); | ||||
|   } | ||||
| 
 | ||||
|   //! Append a formatted string `fmt` to the current content.
 | ||||
|   ASMJIT_INLINE bool appendVFormat(const char* fmt, va_list ap) noexcept { | ||||
|     return _opVFormat(kStringOpAppend, fmt, ap); | ||||
|   } | ||||
| 
 | ||||
|   //! Append a formatted string `fmt` to the current content.
 | ||||
|   ASMJIT_API bool appendFormat(const char* fmt, ...) noexcept; | ||||
| 
 | ||||
|   //! Append `c` character.
 | ||||
|   ASMJIT_INLINE bool appendChar(char c) noexcept { | ||||
|     return _opChar(kStringOpAppend, c); | ||||
|   } | ||||
| 
 | ||||
|   //! Append `c` of `len`.
 | ||||
|   ASMJIT_INLINE bool appendChars(char c, size_t len) noexcept { | ||||
|     return _opChars(kStringOpAppend, c, len); | ||||
|   } | ||||
| 
 | ||||
|   //! Append `i`.
 | ||||
|   ASMJIT_INLINE bool appendInt(int64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { | ||||
|     return _opNumber(kStringOpAppend, static_cast<uint64_t>(i), base, width, flags | kStringFormatSigned); | ||||
|   } | ||||
| 
 | ||||
|   //! Append `i`.
 | ||||
|   ASMJIT_INLINE bool appendUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { | ||||
|     return _opNumber(kStringOpAppend, i, base, width, flags); | ||||
|   } | ||||
| 
 | ||||
|   //! Append the given `data` converted to a HEX string.
 | ||||
|   ASMJIT_INLINE bool appendHex(const void* data, size_t len) noexcept { | ||||
|     return _opHex(kStringOpAppend, data, len); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [_Append]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Append `str` of `len`, inlined, without buffer overflow check.
 | ||||
|   ASMJIT_INLINE void _appendString(const char* str, size_t len = kInvalidIndex) noexcept { | ||||
|     // len should be a constant if we are inlining.
 | ||||
|     if (len == kInvalidIndex) { | ||||
|       char* p = &_data[_length]; | ||||
| 
 | ||||
|       while (*str) { | ||||
|         ASMJIT_ASSERT(p < _data + _capacity); | ||||
|         *p++ = *str++; | ||||
|       } | ||||
| 
 | ||||
|       *p = '\0'; | ||||
|       _length = (size_t)(p - _data); | ||||
|     } | ||||
|     else { | ||||
|       ASMJIT_ASSERT(_capacity - _length >= len); | ||||
| 
 | ||||
|       char* p = &_data[_length]; | ||||
|       char* pEnd = p + len; | ||||
| 
 | ||||
|       while (p < pEnd) | ||||
|         *p++ = *str++; | ||||
| 
 | ||||
|       *p = '\0'; | ||||
|       _length += len; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   //! Append `c` character, inlined, without buffer overflow check.
 | ||||
|   ASMJIT_INLINE void _appendChar(char c) noexcept { | ||||
|     ASMJIT_ASSERT(_capacity - _length >= 1); | ||||
| 
 | ||||
|     _data[_length] = c; | ||||
|     _length++; | ||||
|     _data[_length] = '\0'; | ||||
|   } | ||||
| 
 | ||||
|   //! Append `c` of `len`, inlined, without buffer overflow check.
 | ||||
|   ASMJIT_INLINE void _appendChars(char c, size_t len) noexcept { | ||||
|     ASMJIT_ASSERT(_capacity - _length >= len); | ||||
| 
 | ||||
|     char* p = &_data[_length]; | ||||
|     char* pEnd = p + len; | ||||
| 
 | ||||
|     while (p < pEnd) | ||||
|       *p++ = c; | ||||
| 
 | ||||
|     *p = '\0'; | ||||
|     _length += len; | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE void _appendUInt32(uint32_t i) noexcept { | ||||
|     char buf_[32]; | ||||
| 
 | ||||
|     char* pEnd = buf_ + ASMJIT_ARRAY_SIZE(buf_); | ||||
|     char* pBuf = pEnd; | ||||
| 
 | ||||
|     do { | ||||
|       uint32_t d = i / 10; | ||||
|       uint32_t r = i % 10; | ||||
| 
 | ||||
|       *--pBuf = static_cast<uint8_t>(r + '0'); | ||||
|       i = d; | ||||
|     } while (i); | ||||
| 
 | ||||
|     ASMJIT_ASSERT(_capacity - _length >= (size_t)(pEnd - pBuf)); | ||||
|     char* p = &_data[_length]; | ||||
| 
 | ||||
|     do { | ||||
|       *p++ = *pBuf; | ||||
|     } while (++pBuf != pEnd); | ||||
| 
 | ||||
|     *p = '\0'; | ||||
|     _length = (size_t)(p - _data); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Eq]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Check for equality with other `str` of `len`.
 | ||||
|   ASMJIT_API bool eq(const char* str, size_t len = kInvalidIndex) const noexcept; | ||||
|   //! Check for equality with `other`.
 | ||||
|   ASMJIT_INLINE bool eq(const StringBuilder& other) const noexcept { return eq(other._data); } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Operator Overload]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE bool operator==(const StringBuilder& other) const noexcept { return  eq(other); } | ||||
|   ASMJIT_INLINE bool operator!=(const StringBuilder& other) const noexcept { return !eq(other); } | ||||
| 
 | ||||
|   ASMJIT_INLINE bool operator==(const char* str) const noexcept { return  eq(str); } | ||||
|   ASMJIT_INLINE bool operator!=(const char* str) const noexcept { return !eq(str); } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! String data.
 | ||||
|   char* _data; | ||||
|   //! Length.
 | ||||
|   size_t _length; | ||||
|   //! Capacity.
 | ||||
|   size_t _capacity; | ||||
|   //! Whether the string can be freed.
 | ||||
|   size_t _canFree; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::StringBuilderTmp]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Temporary string builder, has statically allocated `N` bytes.
 | ||||
| template<size_t N> | ||||
| class StringBuilderTmp : public StringBuilder { | ||||
|  public: | ||||
|   ASMJIT_NO_COPY(StringBuilderTmp<N>) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE StringBuilderTmp() noexcept : StringBuilder(NoInit) { | ||||
|     _data = _embeddedData; | ||||
|     _data[0] = 0; | ||||
| 
 | ||||
|     _length = 0; | ||||
|     _capacity = N; | ||||
|     _canFree = false; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Embedded data.
 | ||||
|   char _embeddedData[static_cast<size_t>( | ||||
|     N + 1 + sizeof(intptr_t)) & ~static_cast<size_t>(sizeof(intptr_t) - 1)]; | ||||
| }; | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_BASE_CONTAINERS_H
 | ||||
							
								
								
									
										643
									
								
								DynamicHooks/thirdparty/AsmJit/base/cpuinfo.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										643
									
								
								DynamicHooks/thirdparty/AsmJit/base/cpuinfo.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,643 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/cpuinfo.h" | ||||
| #include "../base/utils.h" | ||||
| 
 | ||||
| #if ASMJIT_OS_POSIX | ||||
| # include <errno.h> | ||||
| # include <sys/statvfs.h> | ||||
| # include <sys/utsname.h> | ||||
| # include <unistd.h> | ||||
| #endif // ASMJIT_OS_POSIX
 | ||||
| 
 | ||||
| #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 | ||||
| # if ASMJIT_CC_MSC_GE(14, 0, 0) | ||||
|  # include <intrin.h>         // Required by `__cpuid()` and `_xgetbv()`.
 | ||||
| # endif // _MSC_VER >= 1400
 | ||||
| #endif | ||||
| 
 | ||||
| #if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 | ||||
| # if ASMJIT_OS_LINUX | ||||
| #  include <sys/auxv.h>       // Required by `getauxval()`.
 | ||||
| # endif | ||||
| #endif | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::CpuInfo - Detect ARM & ARM64]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // ARM information has to be retrieved by the OS (this is how ARM was designed).
 | ||||
| #if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 | ||||
| 
 | ||||
| #if ASMJIT_ARCH_ARM64 | ||||
| static void armPopulateBaseline64Features(CpuInfo* cpuInfo) noexcept { | ||||
|   // Thumb (including all variations) is only supported on ARM32.
 | ||||
| 
 | ||||
|   // ARM64 is based on ARMv8 and newer.
 | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureV6); | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureV7); | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureV8); | ||||
| 
 | ||||
|   // ARM64 comes with these features by default.
 | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureDSP); | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureIDIV); | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureVFP2); | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureVFP3); | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureVFP4); | ||||
| } | ||||
| #endif // ASMJIT_ARCH_ARM64
 | ||||
| 
 | ||||
| #if ASMJIT_OS_WINDOWS | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! Detect ARM CPU features on Windows.
 | ||||
| //!
 | ||||
| //! The detection is based on `IsProcessorFeaturePresent()` API call.
 | ||||
| static void armDetectCpuInfoOnWindows(CpuInfo* cpuInfo) noexcept { | ||||
| #if ASMJIT_ARCH_ARM32 | ||||
|   cpuInfo->setArch(kArchArm32); | ||||
| 
 | ||||
|   // Windows for ARM requires at least ARMv7 with DSP extensions.
 | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureV6); | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureV7); | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureDSP); | ||||
| 
 | ||||
|   // Windows for ARM requires VFP3.
 | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureVFP2); | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureVFP3); | ||||
| 
 | ||||
|   // Windows for ARM requires and uses THUMB2.
 | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB); | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB2); | ||||
| #else | ||||
|   cpuInfo->setArch(kArchArm64); | ||||
|   armPopulateBaseline64Features(cpuInfo); | ||||
| #endif | ||||
| 
 | ||||
|   // Windows for ARM requires NEON.
 | ||||
|   cpuInfo->addFeature(CpuInfo::kArmFeatureNEON); | ||||
| 
 | ||||
|   // Detect additional CPU features by calling `IsProcessorFeaturePresent()`.
 | ||||
|   struct WinPFPMapping { | ||||
|     uint32_t pfpId, featureId; | ||||
|   }; | ||||
| 
 | ||||
|   static const WinPFPMapping mapping[] = { | ||||
|     { PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE , CpuInfo::kArmFeatureVFP4      }, | ||||
|     { PF_ARM_VFP_32_REGISTERS_AVAILABLE  , CpuInfo::kArmFeatureVFP_D32   }, | ||||
|     { PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE, CpuInfo::kArmFeatureIDIV      }, | ||||
|     { PF_ARM_64BIT_LOADSTORE_ATOMIC      , CpuInfo::kArmFeatureAtomics64 } | ||||
|   }; | ||||
| 
 | ||||
|   for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(mapping); i++) | ||||
|     if (::IsProcessorFeaturePresent(mapping[i].pfpId)) | ||||
|       cpuInfo->addFeature(mapping[i].featureId); | ||||
| } | ||||
| #endif // ASMJIT_OS_WINDOWS
 | ||||
| 
 | ||||
| #if ASMJIT_OS_LINUX | ||||
| struct LinuxHWCapMapping { | ||||
|   uint32_t hwcapMask, featureId; | ||||
| }; | ||||
| 
 | ||||
| static void armDetectHWCaps(CpuInfo* cpuInfo, | ||||
|   unsigned long type, const LinuxHWCapMapping* mapping, size_t length) noexcept { | ||||
| 
 | ||||
|   unsigned long mask = getauxval(type); | ||||
|   for (size_t i = 0; i < length; i++) | ||||
|     if ((mask & mapping[i].hwcapMask) == mapping[i].hwcapMask) | ||||
|       cpuInfo->addFeature(mapping[i].featureId); | ||||
| } | ||||
| 
 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! Detect ARM CPU features on Linux.
 | ||||
| //!
 | ||||
| //! The detection is based on `getauxval()`.
 | ||||
| static void armDetectCpuInfoOnLinux(CpuInfo* cpuInfo) noexcept { | ||||
| #if ASMJIT_ARCH_ARM32 | ||||
|   cpuInfo->setArch(kArchArm32); | ||||
| 
 | ||||
|   // `AT_HWCAP` provides ARMv7 (and less) related flags.
 | ||||
|   static const LinuxHWCapMapping hwCapMapping[] = { | ||||
|     { /* HWCAP_VFPv3   */ (1 << 13), CpuInfo::kArmFeatureVFP3      }, | ||||
|     { /* HWCAP_VFPv4   */ (1 << 16), CpuInfo::kArmFeatureVFP4      }, | ||||
|     { /* HWCAP_IDIVA   */ (3 << 17), CpuInfo::kArmFeatureIDIV      }, | ||||
|     { /* HWCAP_VFPD32  */ (1 << 19), CpuInfo::kArmFeatureVFP_D32   }, | ||||
|     { /* HWCAP_NEON    */ (1 << 12), CpuInfo::kArmFeatureNEON      }, | ||||
|     { /* HWCAP_EDSP    */ (1 <<  7), CpuInfo::kArmFeatureDSP       } | ||||
|   }; | ||||
|   armDetectHWCaps(cpuInfo, AT_HWCAP, hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping)); | ||||
| 
 | ||||
|   // VFP3 implies VFP2.
 | ||||
|   if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFP3)) | ||||
|     cpuInfo->addFeature(CpuInfo::kArmFeatureVFP2); | ||||
| 
 | ||||
|   // VFP2 implies ARMv6.
 | ||||
|   if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFP2)) | ||||
|     cpuInfo->addFeature(CpuInfo::kArmFeatureV6); | ||||
| 
 | ||||
|   // VFP3 or NEON implies ARMv7.
 | ||||
|   if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFP3) || | ||||
|       cpuInfo->hasFeature(CpuInfo::kArmFeatureNEON)) | ||||
|     cpuInfo->addFeature(CpuInfo::kArmFeatureV7); | ||||
| 
 | ||||
|   // `AT_HWCAP2` provides ARMv8 related flags.
 | ||||
|   static const LinuxHWCapMapping hwCap2Mapping[] = { | ||||
|     { /* HWCAP2_AES    */ (1 <<  0), CpuInfo::kArmFeatureAES       }, | ||||
|     { /* HWCAP2_CRC32  */ (1 <<  4), CpuInfo::kArmFeatureCRC32     }, | ||||
|     { /* HWCAP2_PMULL  */ (1 <<  1), CpuInfo::kArmFeaturePMULL     }, | ||||
|     { /* HWCAP2_SHA1   */ (1 <<  2), CpuInfo::kArmFeatureSHA1      }, | ||||
|     { /* HWCAP2_SHA2   */ (1 <<  3), CpuInfo::kArmFeatureSHA256    } | ||||
|   }; | ||||
|   armDetectHWCaps(cpuInfo, AT_HWCAP2, hwCap2Mapping, ASMJIT_ARRAY_SIZE(hwCap2Mapping)); | ||||
| 
 | ||||
|   if (cpuInfo->hasFeature(CpuInfo::kArmFeatureAES   ) || | ||||
|       cpuInfo->hasFeature(CpuInfo::kArmFeatureCRC32 ) || | ||||
|       cpuInfo->hasFeature(CpuInfo::kArmFeaturePMULL ) || | ||||
|       cpuInfo->hasFeature(CpuInfo::kArmFeatureSHA1  ) || | ||||
|       cpuInfo->hasFeature(CpuInfo::kArmFeatureSHA256)) { | ||||
|     cpuInfo->addFeature(CpuInfo::kArmFeatureV8); | ||||
|   } | ||||
| #else | ||||
|   cpuInfo->setArch(kArchArm64); | ||||
|   armPopulateBaseline64Features(cpuInfo); | ||||
| 
 | ||||
|   // `AT_HWCAP` provides ARMv8 related flags.
 | ||||
|   static const LinuxHWCapMapping hwCapMapping[] = { | ||||
|     { /* HWCAP_ASIMD   */ (1 <<  1), CpuInfo::kArmFeatureNEON      }, | ||||
|     { /* HWCAP_AES     */ (1 <<  3), CpuInfo::kArmFeatureAES       }, | ||||
|     { /* HWCAP_CRC32   */ (1 <<  7), CpuInfo::kArmFeatureCRC32     }, | ||||
|     { /* HWCAP_PMULL   */ (1 <<  4), CpuInfo::kArmFeaturePMULL     }, | ||||
|     { /* HWCAP_SHA1    */ (1 <<  5), CpuInfo::kArmFeatureSHA1      }, | ||||
|     { /* HWCAP_SHA2    */ (1 <<  6), CpuInfo::kArmFeatureSHA256    } | ||||
|     { /* HWCAP_ATOMICS */ (1 <<  8), CpuInfo::kArmFeatureAtomics64 } | ||||
|   }; | ||||
|   armDetectHWCaps(cpuInfo, AT_HWCAP, hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping)); | ||||
| 
 | ||||
|   // `AT_HWCAP2` is not used at the moment.
 | ||||
| #endif | ||||
| } | ||||
| #endif // ASMJIT_OS_LINUX
 | ||||
| 
 | ||||
| static void armDetectCpuInfo(CpuInfo* cpuInfo) noexcept { | ||||
| #if ASMJIT_OS_WINDOWS | ||||
|   armDetectCpuInfoOnWindows(cpuInfo); | ||||
| #elif ASMJIT_OS_LINUX | ||||
|   armDetectCpuInfoOnLinux(cpuInfo); | ||||
| #else | ||||
| # error "[asmjit] armDetectCpuInfo() - Unsupported OS." | ||||
| #endif | ||||
| } | ||||
| #endif // ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::CpuInfo - Detect X86 & X64]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 | ||||
| 
 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! X86 CPUID result.
 | ||||
| struct CpuIdResult { | ||||
|   uint32_t eax, ebx, ecx, edx; | ||||
| }; | ||||
| 
 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! Content of XCR register, result of XGETBV instruction.
 | ||||
| struct XGetBVResult { | ||||
|   uint32_t eax, edx; | ||||
| }; | ||||
| 
 | ||||
| #if ASMJIT_CC_MSC && !ASMJIT_CC_MSC_GE(15, 0, 30729) && ASMJIT_ARCH_X64 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! HACK: VS2008 or less, 64-bit mode - `__cpuidex` doesn't exist! However,
 | ||||
| //! 64-bit calling convention specifies the first parameter to be passed in
 | ||||
| //! ECX, so we may be lucky if compiler doesn't move the register, otherwise
 | ||||
| //! the result would be wrong.
 | ||||
| static void ASMJIT_NOINLINE void x86CallCpuIdWorkaround(uint32_t inEcx, uint32_t inEax, CpuIdResult* result) noexcept { | ||||
|   __cpuid(reinterpret_cast<int*>(result), inEax); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! Wrapper to call `cpuid` instruction.
 | ||||
| static void ASMJIT_INLINE x86CallCpuId(CpuIdResult* result, uint32_t inEax, uint32_t inEcx = 0) noexcept { | ||||
| #if ASMJIT_CC_MSC && ASMJIT_CC_MSC_GE(15, 0, 30729) | ||||
|   __cpuidex(reinterpret_cast<int*>(result), inEax, inEcx); | ||||
| #elif ASMJIT_CC_MSC && ASMJIT_ARCH_X64 | ||||
|   x86CallCpuIdWorkaround(inEcx, inEax, result); | ||||
| #elif ASMJIT_CC_MSC && ASMJIT_ARCH_X86 | ||||
|   uint32_t paramEax = inEax; | ||||
|   uint32_t paramEcx = inEcx; | ||||
|   uint32_t* out = reinterpret_cast<uint32_t*>(result); | ||||
| 
 | ||||
|   __asm { | ||||
|     mov     eax, paramEax | ||||
|     mov     ecx, paramEcx | ||||
|     mov     edi, out | ||||
|     cpuid | ||||
|     mov     dword ptr[edi +  0], eax | ||||
|     mov     dword ptr[edi +  4], ebx | ||||
|     mov     dword ptr[edi +  8], ecx | ||||
|     mov     dword ptr[edi + 12], edx | ||||
|   } | ||||
| #elif (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && ASMJIT_ARCH_X86 | ||||
|   __asm__ __volatile__( | ||||
|     "mov %%ebx, %%edi\n" | ||||
|     "cpuid\n" | ||||
|     "xchg %%edi, %%ebx\n" | ||||
|       : "=a"(result->eax), | ||||
|         "=D"(result->ebx), | ||||
|         "=c"(result->ecx), | ||||
|         "=d"(result->edx) | ||||
|       : "a"(inEax), | ||||
|         "c"(inEcx) | ||||
|   ); | ||||
| #elif (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && ASMJIT_ARCH_X64 | ||||
|   __asm__ __volatile__( \ | ||||
|     "mov %%rbx, %%rdi\n" | ||||
|     "cpuid\n" | ||||
|     "xchg %%rdi, %%rbx\n" | ||||
|       : "=a"(result->eax), | ||||
|         "=D"(result->ebx), | ||||
|         "=c"(result->ecx), | ||||
|         "=d"(result->edx) | ||||
|       : "a"(inEax), | ||||
|         "c"(inEcx) | ||||
|   ); | ||||
| #else | ||||
| # error "[asmjit] x86CallCpuid() - Unsupported compiler." | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! Wrapper to call `xgetbv` instruction.
 | ||||
| static void x86CallXGetBV(XGetBVResult* result, uint32_t inEcx) noexcept { | ||||
| #if ASMJIT_CC_MSC_GE(16, 0, 40219) // 2010SP1+
 | ||||
|   uint64_t value = _xgetbv(inEcx); | ||||
|   result->eax = static_cast<uint32_t>(value & 0xFFFFFFFFU); | ||||
|   result->edx = static_cast<uint32_t>(value >> 32); | ||||
| #elif ASMJIT_CC_GCC || ASMJIT_CC_CLANG | ||||
|   uint32_t outEax; | ||||
|   uint32_t outEdx; | ||||
| 
 | ||||
|   // Replaced, because the world is not perfect:
 | ||||
|   //   __asm__ __volatile__("xgetbv" : "=a"(outEax), "=d"(outEdx) : "c"(inEcx));
 | ||||
|   __asm__ __volatile__(".byte 0x0F, 0x01, 0xd0" : "=a"(outEax), "=d"(outEdx) : "c"(inEcx)); | ||||
| 
 | ||||
|   result->eax = outEax; | ||||
|   result->edx = outEdx; | ||||
| #else | ||||
|   result->eax = 0; | ||||
|   result->edx = 0; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! Map a 12-byte vendor string returned by `cpuid` into a `CpuInfo::Vendor` ID.
 | ||||
| static uint32_t x86GetCpuVendorID(const char* vendorString) noexcept { | ||||
|   struct VendorData { | ||||
|     uint32_t id; | ||||
|     char text[12]; | ||||
|   }; | ||||
| 
 | ||||
|   static const VendorData vendorList[] = { | ||||
|     { CpuInfo::kVendorIntel , { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l' } }, | ||||
|     { CpuInfo::kVendorAMD   , { 'A', 'u', 't', 'h', 'e', 'n', 't', 'i', 'c', 'A', 'M', 'D' } }, | ||||
|     { CpuInfo::kVendorVIA   , { 'V', 'I', 'A',  0 , 'V', 'I', 'A',  0 , 'V', 'I', 'A',  0  } }, | ||||
|     { CpuInfo::kVendorVIA   , { 'C', 'e', 'n', 't', 'a', 'u', 'r', 'H', 'a', 'u', 'l', 's' } } | ||||
|   }; | ||||
| 
 | ||||
|   uint32_t dw0 = reinterpret_cast<const uint32_t*>(vendorString)[0]; | ||||
|   uint32_t dw1 = reinterpret_cast<const uint32_t*>(vendorString)[1]; | ||||
|   uint32_t dw2 = reinterpret_cast<const uint32_t*>(vendorString)[2]; | ||||
| 
 | ||||
|   for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(vendorList); i++) { | ||||
|     if (dw0 == reinterpret_cast<const uint32_t*>(vendorList[i].text)[0] && | ||||
|         dw1 == reinterpret_cast<const uint32_t*>(vendorList[i].text)[1] && | ||||
|         dw2 == reinterpret_cast<const uint32_t*>(vendorList[i].text)[2]) | ||||
|       return vendorList[i].id; | ||||
|   } | ||||
| 
 | ||||
|   return CpuInfo::kVendorNone; | ||||
| } | ||||
| 
 | ||||
| static ASMJIT_INLINE void x86SimplifyBrandString(char* s) noexcept { | ||||
|   // Used to always clear the current character to ensure that the result
 | ||||
|   // doesn't contain garbage after the new zero terminator.
 | ||||
|   char* d = s; | ||||
| 
 | ||||
|   char prev = 0; | ||||
|   char curr = s[0]; | ||||
|   s[0] = '\0'; | ||||
| 
 | ||||
|   for (;;) { | ||||
|     if (curr == 0) | ||||
|       break; | ||||
| 
 | ||||
|     if (curr == ' ') { | ||||
|       if (prev == '@' || s[1] == ' ' || s[1] == '@') | ||||
|         goto L_Skip; | ||||
|     } | ||||
| 
 | ||||
|     d[0] = curr; | ||||
|     d++; | ||||
|     prev = curr; | ||||
| 
 | ||||
| L_Skip: | ||||
|     curr = *++s; | ||||
|     s[0] = '\0'; | ||||
|   } | ||||
| 
 | ||||
|   d[0] = '\0'; | ||||
| } | ||||
| 
 | ||||
| static void x86DetectCpuInfo(CpuInfo* cpuInfo) noexcept { | ||||
|   uint32_t i, maxId; | ||||
| 
 | ||||
|   CpuIdResult regs; | ||||
|   XGetBVResult xcr0 = { 0, 0 }; | ||||
| 
 | ||||
|   // Architecture is known at compile-time.
 | ||||
|   cpuInfo->setArch(ASMJIT_ARCH_X86 ? kArchX86 : kArchX64); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [CPUID EAX=0x0]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   // Get vendor string/id.
 | ||||
|   x86CallCpuId(®s, 0x0); | ||||
| 
 | ||||
|   maxId = regs.eax; | ||||
|   ::memcpy(cpuInfo->_vendorString + 0, ®s.ebx, 4); | ||||
|   ::memcpy(cpuInfo->_vendorString + 4, ®s.edx, 4); | ||||
|   ::memcpy(cpuInfo->_vendorString + 8, ®s.ecx, 4); | ||||
|   cpuInfo->_vendorId = x86GetCpuVendorID(cpuInfo->_vendorString); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [CPUID EAX=0x1]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   if (maxId >= 0x1) { | ||||
|     // Get feature flags in ECX/EDX and family/model in EAX.
 | ||||
|     x86CallCpuId(®s, 0x1); | ||||
| 
 | ||||
|     // Fill family and model fields.
 | ||||
|     cpuInfo->_family   = (regs.eax >> 8) & 0x0F; | ||||
|     cpuInfo->_model    = (regs.eax >> 4) & 0x0F; | ||||
|     cpuInfo->_stepping = (regs.eax     ) & 0x0F; | ||||
| 
 | ||||
|     // Use extended family and model fields.
 | ||||
|     if (cpuInfo->_family == 0x0F) { | ||||
|       cpuInfo->_family += ((regs.eax >> 20) & 0xFF); | ||||
|       cpuInfo->_model  += ((regs.eax >> 16) & 0x0F) << 4; | ||||
|     } | ||||
| 
 | ||||
|     cpuInfo->_x86Data._processorType        = ((regs.eax >> 12) & 0x03); | ||||
|     cpuInfo->_x86Data._brandIndex           = ((regs.ebx      ) & 0xFF); | ||||
|     cpuInfo->_x86Data._flushCacheLineSize   = ((regs.ebx >>  8) & 0xFF) * 8; | ||||
|     cpuInfo->_x86Data._maxLogicalProcessors = ((regs.ebx >> 16) & 0xFF); | ||||
| 
 | ||||
|     if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE3); | ||||
|     if (regs.ecx & 0x00000002U) cpuInfo->addFeature(CpuInfo::kX86FeaturePCLMULQDQ); | ||||
|     if (regs.ecx & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureMONITOR); | ||||
|     if (regs.ecx & 0x00000200U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSSE3); | ||||
|     if (regs.ecx & 0x00002000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMPXCHG16B); | ||||
|     if (regs.ecx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4_1); | ||||
|     if (regs.ecx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4_2); | ||||
|     if (regs.ecx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMOVBE); | ||||
|     if (regs.ecx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeaturePOPCNT); | ||||
|     if (regs.ecx & 0x02000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAESNI); | ||||
|     if (regs.ecx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVE); | ||||
|     if (regs.ecx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVE_OS); | ||||
|     if (regs.ecx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDRAND); | ||||
|     if (regs.edx & 0x00000010U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDTSC); | ||||
|     if (regs.edx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMPXCHG8B); | ||||
|     if (regs.edx & 0x00008000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMOV); | ||||
|     if (regs.edx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLFLUSH); | ||||
|     if (regs.edx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMMX); | ||||
|     if (regs.edx & 0x01000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFXSR); | ||||
|     if (regs.edx & 0x02000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE) | ||||
|                                         .addFeature(CpuInfo::kX86FeatureMMX2); | ||||
|     if (regs.edx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE) | ||||
|                                         .addFeature(CpuInfo::kX86FeatureSSE2); | ||||
|     if (regs.edx & 0x10000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMT); | ||||
| 
 | ||||
|     // AMD sets multi-threading ON if it has two or more cores.
 | ||||
|     if (cpuInfo->_hwThreadsCount == 1 && cpuInfo->_vendorId == CpuInfo::kVendorAMD && (regs.edx & 0x10000000U)) | ||||
|       cpuInfo->_hwThreadsCount = 2; | ||||
| 
 | ||||
|     // Get the content of XCR0 if supported by CPU and enabled by OS.
 | ||||
|     if ((regs.ecx & 0x0C000000U) == 0x0C000000U) | ||||
|       x86CallXGetBV(&xcr0, 0); | ||||
| 
 | ||||
|     // Detect AVX+.
 | ||||
|     if (regs.ecx & 0x10000000U) { | ||||
|       // - XCR0[2:1] == 11b
 | ||||
|       //   XMM & YMM states need to be enabled by OS.
 | ||||
|       if ((xcr0.eax & 0x00000006U) == 0x00000006U) { | ||||
|         cpuInfo->addFeature(CpuInfo::kX86FeatureAVX); | ||||
| 
 | ||||
|         if (regs.ecx & 0x00004000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFMA3); | ||||
|         if (regs.ecx & 0x20000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureF16C); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [CPUID EAX=0x7 ECX=0x0]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   // Detect new features if the processor supports CPUID-07.
 | ||||
|   bool maybeMPX = false; | ||||
| 
 | ||||
|   if (maxId >= 0x7) { | ||||
|     x86CallCpuId(®s, 0x7); | ||||
| 
 | ||||
|     if (regs.ebx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureFSGSBASE); | ||||
|     if (regs.ebx & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureBMI); | ||||
|     if (regs.ebx & 0x00000010U) cpuInfo->addFeature(CpuInfo::kX86FeatureHLE); | ||||
|     if (regs.ebx & 0x00000080U) cpuInfo->addFeature(CpuInfo::kX86FeatureSMEP); | ||||
|     if (regs.ebx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeatureBMI2); | ||||
|     if (regs.ebx & 0x00000200U) cpuInfo->addFeature(CpuInfo::kX86FeatureERMS); | ||||
|     if (regs.ebx & 0x00000800U) cpuInfo->addFeature(CpuInfo::kX86FeatureRTM); | ||||
|     if (regs.ebx & 0x00004000U) maybeMPX = true; | ||||
|     if (regs.ebx & 0x00040000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDSEED); | ||||
|     if (regs.ebx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureADX); | ||||
|     if (regs.ebx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSMAP); | ||||
|     if (regs.ebx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeaturePCOMMIT); | ||||
|     if (regs.ebx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLFLUSH_OPT); | ||||
|     if (regs.ebx & 0x01000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLWB); | ||||
|     if (regs.ebx & 0x20000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSHA); | ||||
|     if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeaturePREFETCHWT1); | ||||
| 
 | ||||
|     // Detect AVX2.
 | ||||
|     if (cpuInfo->hasFeature(CpuInfo::kX86FeatureAVX)) | ||||
|       if (regs.ebx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX2); | ||||
| 
 | ||||
|     // Detect AVX-512+.
 | ||||
|     if (regs.ebx & 0x00010000U) { | ||||
|       // - XCR0[2:1] == 11b
 | ||||
|       //   XMM/YMM states need to be enabled by OS.
 | ||||
|       // - XCR0[7:5] == 111b
 | ||||
|       //   Upper 256-bit of ZMM0-XMM15 and ZMM16-ZMM31 need to be enabled by the OS.
 | ||||
|       if ((xcr0.eax & 0x000000E6U) == 0x000000E6U) { | ||||
|         cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512F); | ||||
| 
 | ||||
|         if (regs.ebx & 0x00020000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512DQ); | ||||
|         if (regs.ebx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512IFMA); | ||||
|         if (regs.ebx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512PF); | ||||
|         if (regs.ebx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512ER); | ||||
|         if (regs.ebx & 0x10000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512CD); | ||||
|         if (regs.ebx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512BW); | ||||
|         if (regs.ebx & 0x80000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512VL); | ||||
|         if (regs.ecx & 0x00000002U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512VBMI); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [CPUID EAX=0xD, ECX=0x0]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   if (maxId >= 0xD && maybeMPX) { | ||||
|     x86CallCpuId(®s, 0xD); | ||||
| 
 | ||||
|     // Both CPUID result and XCR0 has to be enabled to have support for MPX.
 | ||||
|     if (((regs.eax & xcr0.eax) & 0x00000018U) == 0x00000018U) { | ||||
|       cpuInfo->addFeature(CpuInfo::kX86FeatureMPX); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [CPUID EAX=0x80000000...maxId]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   // Several CPUID calls are required to get the whole branc string. It's easy
 | ||||
|   // to copy one DWORD at a time instead of performing a byte copy.
 | ||||
|   uint32_t* brand = reinterpret_cast<uint32_t*>(cpuInfo->_brandString); | ||||
| 
 | ||||
|   i = maxId = 0x80000000U; | ||||
|   do { | ||||
|     x86CallCpuId(®s, i); | ||||
|     switch (i) { | ||||
|       case 0x80000000U: | ||||
|         maxId = Utils::iMin<uint32_t>(regs.eax, 0x80000004); | ||||
|         break; | ||||
| 
 | ||||
|       case 0x80000001U: | ||||
|         if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureLAHF_SAHF); | ||||
|         if (regs.ecx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureLZCNT); | ||||
|         if (regs.ecx & 0x00000040U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4A); | ||||
|         if (regs.ecx & 0x00000080U) cpuInfo->addFeature(CpuInfo::kX86FeatureMSSE); | ||||
|         if (regs.ecx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeaturePREFETCH); | ||||
|         if (regs.ecx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureTBM); | ||||
|         if (regs.edx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureNX); | ||||
|         if (regs.edx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFXSR_OPT); | ||||
|         if (regs.edx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMMX2); | ||||
|         if (regs.edx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDTSCP); | ||||
|         if (regs.edx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86Feature3DNOW2) | ||||
|                                             .addFeature(CpuInfo::kX86FeatureMMX2); | ||||
|         if (regs.edx & 0x80000000U) cpuInfo->addFeature(CpuInfo::kX86Feature3DNOW); | ||||
| 
 | ||||
|         if (cpuInfo->hasFeature(CpuInfo::kX86FeatureAVX)) { | ||||
|           if (regs.ecx & 0x00000800U) cpuInfo->addFeature(CpuInfo::kX86FeatureXOP); | ||||
|           if (regs.ecx & 0x00010000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFMA4); | ||||
|         } | ||||
|         break; | ||||
| 
 | ||||
|       case 0x80000002U: | ||||
|       case 0x80000003U: | ||||
|       case 0x80000004U: | ||||
|         *brand++ = regs.eax; | ||||
|         *brand++ = regs.ebx; | ||||
|         *brand++ = regs.ecx; | ||||
|         *brand++ = regs.edx; | ||||
|         break; | ||||
| 
 | ||||
|       default: | ||||
|         // Stop the loop, additional features can be detected in the future.
 | ||||
|         i = maxId; | ||||
|         break; | ||||
|     } | ||||
|   } while (i++ < maxId); | ||||
| 
 | ||||
|   // Simplify CPU brand string by removing unnecessary spaces.
 | ||||
|   x86SimplifyBrandString(cpuInfo->_brandString); | ||||
| } | ||||
| #endif // ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::CpuInfo - Detect - HWThreadsCount]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| static uint32_t cpuDetectHWThreadsCount() noexcept { | ||||
| #if ASMJIT_OS_WINDOWS | ||||
|   SYSTEM_INFO info; | ||||
|   ::GetSystemInfo(&info); | ||||
|   return info.dwNumberOfProcessors; | ||||
| #elif ASMJIT_OS_POSIX && defined(_SC_NPROCESSORS_ONLN) | ||||
|   long res = ::sysconf(_SC_NPROCESSORS_ONLN); | ||||
|   if (res <= 0) return 1; | ||||
|   return static_cast<uint32_t>(res); | ||||
| #else | ||||
|   return 1; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::CpuInfo - Detect]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void CpuInfo::detect() noexcept { | ||||
|   reset(); | ||||
| 
 | ||||
|   // Detect the number of hardware threads available.
 | ||||
|   _hwThreadsCount = cpuDetectHWThreadsCount(); | ||||
| 
 | ||||
| #if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 | ||||
|   armDetectCpuInfo(this); | ||||
| #endif // ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
 | ||||
| 
 | ||||
| #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 | ||||
|   x86DetectCpuInfo(this); | ||||
| #endif // ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
 | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::CpuInfo - GetHost]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| struct HostCpuInfo : public CpuInfo { | ||||
|   ASMJIT_INLINE HostCpuInfo() noexcept : CpuInfo() { detect(); } | ||||
| }; | ||||
| 
 | ||||
| const CpuInfo& CpuInfo::getHost() noexcept { | ||||
|   static HostCpuInfo host; | ||||
|   return host; | ||||
| } | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
							
								
								
									
										316
									
								
								DynamicHooks/thirdparty/AsmJit/base/cpuinfo.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										316
									
								
								DynamicHooks/thirdparty/AsmJit/base/cpuinfo.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,316 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_BASE_CPUINFO_H | ||||
| #define _ASMJIT_BASE_CPUINFO_H | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/globals.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| //! \addtogroup asmjit_base
 | ||||
| //! \{
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::CpuInfo]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! CPU information.
 | ||||
| class CpuInfo { | ||||
|  public: | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Vendor]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! CPU vendor ID.
 | ||||
|   ASMJIT_ENUM(Vendor) { | ||||
|     kVendorNone  = 0,                    //!< Generic or unknown.
 | ||||
|     kVendorIntel = 1,                    //!< Intel vendor.
 | ||||
|     kVendorAMD   = 2,                    //!< AMD vendor.
 | ||||
|     kVendorVIA   = 3                     //!< VIA vendor.
 | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [ArmFeatures]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! ARM/ARM64 CPU features.
 | ||||
|   ASMJIT_ENUM(ArmFeatures) { | ||||
|     kArmFeatureV6,                       //!< ARMv6 instruction set.
 | ||||
|     kArmFeatureV7,                       //!< ARMv7 instruction set.
 | ||||
|     kArmFeatureV8,                       //!< ARMv8 instruction set.
 | ||||
|     kArmFeatureTHUMB,                    //!< CPU provides THUMB v1 instruction set (ARM only).
 | ||||
|     kArmFeatureTHUMB2,                   //!< CPU provides THUMB v2 instruction set (ARM only).
 | ||||
|     kArmFeatureVFP2,                     //!< CPU provides VFPv2 instruction set.
 | ||||
|     kArmFeatureVFP3,                     //!< CPU provides VFPv3 instruction set.
 | ||||
|     kArmFeatureVFP4,                     //!< CPU provides VFPv4 instruction set.
 | ||||
|     kArmFeatureVFP_D32,                  //!< CPU provides 32 VFP-D (64-bit) registers.
 | ||||
|     kArmFeatureNEON,                     //!< CPU provides NEON instruction set.
 | ||||
|     kArmFeatureDSP,                      //!< CPU provides DSP extensions.
 | ||||
|     kArmFeatureIDIV,                     //!< CPU provides hardware support for SDIV and UDIV.
 | ||||
|     kArmFeatureAES,                      //!< CPU provides AES instructions (ARM64 only).
 | ||||
|     kArmFeatureCRC32,                    //!< CPU provides CRC32 instructions (ARM64 only).
 | ||||
|     kArmFeaturePMULL,                    //!< CPU provides PMULL instructions (ARM64 only).
 | ||||
|     kArmFeatureSHA1,                     //!< CPU provides SHA1 instructions (ARM64 only).
 | ||||
|     kArmFeatureSHA256,                   //!< CPU provides SHA256 instructions (ARM64 only).
 | ||||
|     kArmFeatureAtomics64,                //!< CPU provides 64-bit load/store atomics (ARM64 only).
 | ||||
| 
 | ||||
|     kArmFeaturesCount                    //!< Count of ARM/ARM64 CPU features.
 | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [X86Features]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! X86/X64 CPU features.
 | ||||
|   ASMJIT_ENUM(X86Features) { | ||||
|     kX86FeatureNX = 0,                   //!< CPU has Not-Execute-Bit.
 | ||||
|     kX86FeatureMT,                       //!< CPU has multi-threading.
 | ||||
|     kX86FeatureRDTSC,                    //!< CPU has RDTSC.
 | ||||
|     kX86FeatureRDTSCP,                   //!< CPU has RDTSCP.
 | ||||
|     kX86FeatureCMOV,                     //!< CPU has CMOV.
 | ||||
|     kX86FeatureCMPXCHG8B,                //!< CPU has CMPXCHG8B.
 | ||||
|     kX86FeatureCMPXCHG16B,               //!< CPU has CMPXCHG16B (x64).
 | ||||
|     kX86FeatureCLFLUSH,                  //!< CPU has CLFUSH.
 | ||||
|     kX86FeatureCLFLUSH_OPT,              //!< CPU has CLFUSH (optimized).
 | ||||
|     kX86FeatureCLWB,                     //!< CPU has CLWB.
 | ||||
|     kX86FeaturePCOMMIT,                  //!< CPU has PCOMMIT.
 | ||||
|     kX86FeaturePREFETCH,                 //!< CPU has PREFETCH.
 | ||||
|     kX86FeaturePREFETCHWT1,              //!< CPU has PREFETCHWT1.
 | ||||
|     kX86FeatureLAHF_SAHF,                //!< CPU has LAHF/SAHF.
 | ||||
|     kX86FeatureFXSR,                     //!< CPU has FXSAVE/FXRSTOR.
 | ||||
|     kX86FeatureFXSR_OPT,                 //!< CPU has FXSAVE/FXRSTOR (optimized).
 | ||||
|     kX86FeatureMMX,                      //!< CPU has MMX.
 | ||||
|     kX86FeatureMMX2,                     //!< CPU has extended MMX.
 | ||||
|     kX86Feature3DNOW,                    //!< CPU has 3dNow!
 | ||||
|     kX86Feature3DNOW2,                   //!< CPU has enhanced 3dNow!
 | ||||
|     kX86FeatureSSE,                      //!< CPU has SSE.
 | ||||
|     kX86FeatureSSE2,                     //!< CPU has SSE2.
 | ||||
|     kX86FeatureSSE3,                     //!< CPU has SSE3.
 | ||||
|     kX86FeatureSSSE3,                    //!< CPU has SSSE3.
 | ||||
|     kX86FeatureSSE4A,                    //!< CPU has SSE4.A.
 | ||||
|     kX86FeatureSSE4_1,                   //!< CPU has SSE4.1.
 | ||||
|     kX86FeatureSSE4_2,                   //!< CPU has SSE4.2.
 | ||||
|     kX86FeatureMSSE,                     //!< CPU has Misaligned SSE (MSSE).
 | ||||
|     kX86FeatureMONITOR,                  //!< CPU has MONITOR and MWAIT.
 | ||||
|     kX86FeatureMOVBE,                    //!< CPU has MOVBE.
 | ||||
|     kX86FeaturePOPCNT,                   //!< CPU has POPCNT.
 | ||||
|     kX86FeatureLZCNT,                    //!< CPU has LZCNT.
 | ||||
|     kX86FeatureAESNI,                    //!< CPU has AESNI.
 | ||||
|     kX86FeaturePCLMULQDQ,                //!< CPU has PCLMULQDQ.
 | ||||
|     kX86FeatureRDRAND,                   //!< CPU has RDRAND.
 | ||||
|     kX86FeatureRDSEED,                   //!< CPU has RDSEED.
 | ||||
|     kX86FeatureSMAP,                     //!< CPU has SMAP (supervisor-mode access prevention).
 | ||||
|     kX86FeatureSMEP,                     //!< CPU has SMEP (supervisor-mode execution prevention).
 | ||||
|     kX86FeatureSHA,                      //!< CPU has SHA-1 and SHA-256.
 | ||||
|     kX86FeatureXSAVE,                    //!< CPU has XSAVE support - XSAVE/XRSTOR, XSETBV/XGETBV, and XCR0.
 | ||||
|     kX86FeatureXSAVE_OS,                 //!< OS has enabled XSAVE, you can call XGETBV to get value of XCR0.
 | ||||
|     kX86FeatureAVX,                      //!< CPU has AVX.
 | ||||
|     kX86FeatureAVX2,                     //!< CPU has AVX2.
 | ||||
|     kX86FeatureF16C,                     //!< CPU has F16C.
 | ||||
|     kX86FeatureFMA3,                     //!< CPU has FMA3.
 | ||||
|     kX86FeatureFMA4,                     //!< CPU has FMA4.
 | ||||
|     kX86FeatureXOP,                      //!< CPU has XOP.
 | ||||
|     kX86FeatureBMI,                      //!< CPU has BMI (bit manipulation instructions #1).
 | ||||
|     kX86FeatureBMI2,                     //!< CPU has BMI2 (bit manipulation instructions #2).
 | ||||
|     kX86FeatureADX,                      //!< CPU has ADX (multi-precision add-carry instruction extensions).
 | ||||
|     kX86FeatureTBM,                      //!< CPU has TBM (trailing bit manipulation).
 | ||||
|     kX86FeatureMPX,                      //!< CPU has MPX (memory protection extensions).
 | ||||
|     kX86FeatureHLE,                      //!< CPU has HLE.
 | ||||
|     kX86FeatureRTM,                      //!< CPU has RTM.
 | ||||
|     kX86FeatureERMS,                     //!< CPU has ERMS (enhanced REP MOVSB/STOSB).
 | ||||
|     kX86FeatureFSGSBASE,                 //!< CPU has FSGSBASE.
 | ||||
|     kX86FeatureAVX512F,                  //!< CPU has AVX-512F (foundation).
 | ||||
|     kX86FeatureAVX512CD,                 //!< CPU has AVX-512CD (conflict detection).
 | ||||
|     kX86FeatureAVX512PF,                 //!< CPU has AVX-512PF (prefetch instructions).
 | ||||
|     kX86FeatureAVX512ER,                 //!< CPU has AVX-512ER (exponential and reciprocal instructions).
 | ||||
|     kX86FeatureAVX512DQ,                 //!< CPU has AVX-512DQ (DWORD/QWORD).
 | ||||
|     kX86FeatureAVX512BW,                 //!< CPU has AVX-512BW (BYTE/WORD).
 | ||||
|     kX86FeatureAVX512VL,                 //!< CPU has AVX VL (vector length extensions).
 | ||||
|     kX86FeatureAVX512IFMA,               //!< CPU has AVX IFMA (integer fused multiply add using 52-bit precision).
 | ||||
|     kX86FeatureAVX512VBMI,               //!< CPU has AVX VBMI (vector byte manipulation instructions).
 | ||||
| 
 | ||||
|     kX86FeaturesCount                    //!< Count of X86/X64 CPU features.
 | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Other]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   enum { | ||||
|     kFeaturesPerUInt32 = static_cast<int>(sizeof(uint32_t)) * 8 | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [ArmInfo]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   struct ArmData { | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [X86Info]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   struct X86Data { | ||||
|     uint32_t _processorType;             //!< Processor type.
 | ||||
|     uint32_t _brandIndex;                //!< Brand index.
 | ||||
|     uint32_t _flushCacheLineSize;        //!< Flush cache line size (in bytes).
 | ||||
|     uint32_t _maxLogicalProcessors;      //!< Maximum number of addressable IDs for logical processors.
 | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE CpuInfo() noexcept { reset(); } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Reset]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(CpuInfo)); } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Detect]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_API void detect() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get CPU architecture, see \Arch.
 | ||||
|   ASMJIT_INLINE uint32_t getArch() const noexcept { return _arch; } | ||||
|   //! Set CPU architecture, see \Arch.
 | ||||
|   ASMJIT_INLINE void setArch(uint32_t arch) noexcept { _arch = static_cast<uint8_t>(arch); } | ||||
| 
 | ||||
|   //! Get CPU vendor string.
 | ||||
|   ASMJIT_INLINE const char* getVendorString() const noexcept { return _vendorString; } | ||||
|   //! Get CPU brand string.
 | ||||
|   ASMJIT_INLINE const char* getBrandString() const noexcept { return _brandString; } | ||||
| 
 | ||||
|   //! Get CPU vendor ID.
 | ||||
|   ASMJIT_INLINE uint32_t getVendorId() const noexcept { return _vendorId; } | ||||
|   //! Get CPU family ID.
 | ||||
|   ASMJIT_INLINE uint32_t getFamily() const noexcept { return _family; } | ||||
|   //! Get CPU model ID.
 | ||||
|   ASMJIT_INLINE uint32_t getModel() const noexcept { return _model; } | ||||
|   //! Get CPU stepping.
 | ||||
|   ASMJIT_INLINE uint32_t getStepping() const noexcept { return _stepping; } | ||||
| 
 | ||||
|   //! Get number of hardware threads available.
 | ||||
|   ASMJIT_INLINE uint32_t getHwThreadsCount() const noexcept { | ||||
|     return _hwThreadsCount; | ||||
|   } | ||||
| 
 | ||||
|   //! Get whether CPU has a `feature`.
 | ||||
|   ASMJIT_INLINE bool hasFeature(uint32_t feature) const noexcept { | ||||
|     ASMJIT_ASSERT(feature < sizeof(_features) * 8); | ||||
| 
 | ||||
|     uint32_t pos = feature / kFeaturesPerUInt32; | ||||
|     uint32_t bit = feature % kFeaturesPerUInt32; | ||||
| 
 | ||||
|     return static_cast<bool>((_features[pos] >> bit) & 0x1); | ||||
|   } | ||||
| 
 | ||||
|   //! Add a CPU `feature`.
 | ||||
|   ASMJIT_INLINE CpuInfo& addFeature(uint32_t feature) noexcept { | ||||
|     ASMJIT_ASSERT(feature < sizeof(_features) * 8); | ||||
| 
 | ||||
|     uint32_t pos = feature / kFeaturesPerUInt32; | ||||
|     uint32_t bit = feature % kFeaturesPerUInt32; | ||||
| 
 | ||||
|     _features[pos] |= static_cast<uint32_t>(1) << bit; | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors - ARM]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors - X86]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get processor type.
 | ||||
|   ASMJIT_INLINE uint32_t getX86ProcessorType() const noexcept { | ||||
|     return _x86Data._processorType; | ||||
|   } | ||||
| 
 | ||||
|   //! Get brand index.
 | ||||
|   ASMJIT_INLINE uint32_t getX86BrandIndex() const noexcept { | ||||
|     return _x86Data._brandIndex; | ||||
|   } | ||||
| 
 | ||||
|   //! Get flush cache line size.
 | ||||
|   ASMJIT_INLINE uint32_t getX86FlushCacheLineSize() const noexcept { | ||||
|     return _x86Data._flushCacheLineSize; | ||||
|   } | ||||
| 
 | ||||
|   //! Get maximum logical processors count.
 | ||||
|   ASMJIT_INLINE uint32_t getX86MaxLogicalProcessors() const noexcept { | ||||
|     return _x86Data._maxLogicalProcessors; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Statics]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get the host CPU information.
 | ||||
|   static ASMJIT_API const CpuInfo& getHost() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! CPU vendor string.
 | ||||
|   char _vendorString[16]; | ||||
|   //! CPU brand string.
 | ||||
|   char _brandString[64]; | ||||
| 
 | ||||
|   //! CPU architecture, see \ref Arch.
 | ||||
|   uint8_t _arch; | ||||
|   //! \internal
 | ||||
|   uint8_t _reserved[3]; | ||||
|   //! CPU vendor id, see \ref CpuVendor.
 | ||||
|   uint32_t _vendorId; | ||||
|   //! CPU family ID.
 | ||||
|   uint32_t _family; | ||||
|   //! CPU model ID.
 | ||||
|   uint32_t _model; | ||||
|   //! CPU stepping.
 | ||||
|   uint32_t _stepping; | ||||
| 
 | ||||
|   //! Number of hardware threads.
 | ||||
|   uint32_t _hwThreadsCount; | ||||
| 
 | ||||
|   //! CPU features (bit-array).
 | ||||
|   uint32_t _features[8]; | ||||
| 
 | ||||
|   // Architecture specific data.
 | ||||
|   union { | ||||
|     ArmData _armData; | ||||
|     X86Data _x86Data; | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_BASE_CPUINFO_H
 | ||||
							
								
								
									
										94
									
								
								DynamicHooks/thirdparty/AsmJit/base/globals.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								DynamicHooks/thirdparty/AsmJit/base/globals.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,94 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/globals.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::DebugUtils]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #if !defined(ASMJIT_DISABLE_TEXT) | ||||
| static const char errorMessages[] = { | ||||
|   "Ok\0" | ||||
|   "No heap memory\0" | ||||
|   "No virtual memory\0" | ||||
|   "Invalid argument\0" | ||||
|   "Invalid state\0" | ||||
|   "Invalid architecture\0" | ||||
|   "Not initialized\0" | ||||
|   "No code generated\0" | ||||
|   "Code too large\0" | ||||
|   "Label already bound\0" | ||||
|   "Unknown instruction\0" | ||||
|   "Illegal instruction\0" | ||||
|   "Illegal addressing\0" | ||||
|   "Illegal displacement\0" | ||||
|   "Overlapped arguments\0" | ||||
|   "Unknown error\0" | ||||
| }; | ||||
| 
 | ||||
| static const char* findPackedString(const char* p, uint32_t id, uint32_t maxId) noexcept { | ||||
|   uint32_t i = 0; | ||||
| 
 | ||||
|   if (id > maxId) | ||||
|     id = maxId; | ||||
| 
 | ||||
|   while (i < id) { | ||||
|     while (p[0]) | ||||
|       p++; | ||||
| 
 | ||||
|     p++; | ||||
|     i++; | ||||
|   } | ||||
| 
 | ||||
|   return p; | ||||
| } | ||||
| #endif // ASMJIT_DISABLE_TEXT
 | ||||
| 
 | ||||
| const char* DebugUtils::errorAsString(Error err) noexcept { | ||||
| #if !defined(ASMJIT_DISABLE_TEXT) | ||||
|   return findPackedString(errorMessages, err, kErrorCount); | ||||
| #else | ||||
|   static const char noMessage[] = ""; | ||||
|   return noMessage; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void DebugUtils::debugOutput(const char* str) noexcept { | ||||
| #if ASMJIT_OS_WINDOWS | ||||
|   ::OutputDebugStringA(str); | ||||
| #else | ||||
|   ::fputs(str, stderr); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void DebugUtils::assertionFailed(const char* file, int line, const char* msg) noexcept { | ||||
|   char str[1024]; | ||||
| 
 | ||||
|   snprintf(str, 1024, | ||||
|     "[asmjit] Assertion failed at %s (line %d):\n" | ||||
|     "[asmjit] %s\n", file, line, msg); | ||||
| 
 | ||||
|   // Support buggy `snprintf` implementations.
 | ||||
|   str[1023] = '\0'; | ||||
| 
 | ||||
|   debugOutput(str); | ||||
|   ::abort(); | ||||
| } | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
							
								
								
									
										666
									
								
								DynamicHooks/thirdparty/AsmJit/base/globals.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										666
									
								
								DynamicHooks/thirdparty/AsmJit/base/globals.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,666 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_BASE_GLOBALS_H | ||||
| #define _ASMJIT_BASE_GLOBALS_H | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../build.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| //! \addtogroup asmjit_base
 | ||||
| //! \{
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::TypeDefs]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! AsmJit error core (unsigned integer).
 | ||||
| typedef uint32_t Error; | ||||
| 
 | ||||
| //! 64-bit unsigned pointer, compatible with JIT and non-JIT generators.
 | ||||
| //!
 | ||||
| //! This is the preferred pointer type to use with AsmJit library. It has a
 | ||||
| //! capability to hold any pointer for any architecture making it an ideal
 | ||||
| //! candidate for a cross-platform code generator.
 | ||||
| typedef uint64_t Ptr; | ||||
| 
 | ||||
| //! like \ref Ptr, but signed.
 | ||||
| typedef int64_t SignedPtr; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::GlobalDefs]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Invalid index
 | ||||
| //!
 | ||||
| //! Invalid index is the last possible index that is never used in practice. In
 | ||||
| //! AsmJit it is used exclusively with strings to indicate the the length of the
 | ||||
| //! string is not known and has to be determined.
 | ||||
| static const size_t kInvalidIndex = ~static_cast<size_t>(0); | ||||
| 
 | ||||
| //! Invalid base address.
 | ||||
| static const Ptr kNoBaseAddress = static_cast<Ptr>(static_cast<SignedPtr>(-1)); | ||||
| 
 | ||||
| //! Global constants.
 | ||||
| ASMJIT_ENUM(GlobalDefs) { | ||||
|   //! Invalid value or operand id.
 | ||||
|   kInvalidValue = 0xFFFFFFFF, | ||||
| 
 | ||||
|   //! Invalid register index.
 | ||||
|   kInvalidReg = 0xFF, | ||||
|   //! Invalid variable type.
 | ||||
|   kInvalidVar = 0xFF, | ||||
| 
 | ||||
|   //! Host memory allocator overhead.
 | ||||
|   //!
 | ||||
|   //! The overhead is decremented from all zone allocators so the operating
 | ||||
|   //! system doesn't have to allocate one extra virtual page to keep tract of
 | ||||
|   //! the requested memory block.
 | ||||
|   //!
 | ||||
|   //! The number is actually a guess.
 | ||||
|   kMemAllocOverhead = sizeof(intptr_t) * 4, | ||||
| 
 | ||||
|   //! Memory grow threshold.
 | ||||
|   //!
 | ||||
|   //! After the grow threshold is reached the capacity won't be doubled
 | ||||
|   //! anymore.
 | ||||
|   kMemAllocGrowMax = 8192 * 1024 | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::ArchId]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! CPU architecture identifier.
 | ||||
| ASMJIT_ENUM(ArchId) { | ||||
|   //! No/Unknown architecture.
 | ||||
|   kArchNone = 0, | ||||
| 
 | ||||
|   //! X86 architecture (32-bit).
 | ||||
|   kArchX86 = 1, | ||||
|   //! X64 architecture (64-bit), also called AMD64.
 | ||||
|   kArchX64 = 2, | ||||
|   //! X32 architecture (64-bit with 32-bit pointers) (NOT USED ATM).
 | ||||
|   kArchX32 = 3, | ||||
| 
 | ||||
|   //! Arm architecture (32-bit).
 | ||||
|   kArchArm32 = 4, | ||||
|   //! Arm64 architecture (64-bit).
 | ||||
|   kArchArm64 = 5, | ||||
| 
 | ||||
| #if ASMJIT_ARCH_X86 | ||||
|   kArchHost = kArchX86 | ||||
| #elif ASMJIT_ARCH_X64 | ||||
|   kArchHost = kArchX64 | ||||
| #elif ASMJIT_ARCH_ARM32 | ||||
|   kArchHost = kArchArm32 | ||||
| #elif ASMJIT_ARCH_ARM64 | ||||
|   kArchHost = kArchArm64 | ||||
| #else | ||||
| # error "[asmjit] Unsupported host architecture." | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::CallConv]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Function calling convention.
 | ||||
| //!
 | ||||
| //! Calling convention is a scheme that defines how function arguments are
 | ||||
| //! passed and how the return value handled. In assembler programming it's
 | ||||
| //! always needed to comply with function calling conventions, because even
 | ||||
| //! small inconsistency can cause undefined behavior or application's crash.
 | ||||
| //!
 | ||||
| //! Platform Independent Conventions
 | ||||
| //! --------------------------------
 | ||||
| //!
 | ||||
| //!   - `kCallConvHost` - Should match the current C++ compiler native calling
 | ||||
| //!     convention.
 | ||||
| //!
 | ||||
| //! X86/X64 Specific Conventions
 | ||||
| //! ----------------------------
 | ||||
| //!
 | ||||
| //! List of calling conventions for 32-bit x86 mode:
 | ||||
| //!   - `kCallConvX86CDecl` - Calling convention for C runtime.
 | ||||
| //!   - `kCallConvX86StdCall` - Calling convention for WinAPI functions.
 | ||||
| //!   - `kCallConvX86MsThisCall` - Calling convention for C++ members under
 | ||||
| //!      Windows (produced by MSVC and all MSVC compatible compilers).
 | ||||
| //!   - `kCallConvX86MsFastCall` - Fastest calling convention that can be used
 | ||||
| //!      by MSVC compiler.
 | ||||
| //!   - `kCallConvX86BorlandFastCall` - Borland fastcall convention.
 | ||||
| //!   - `kCallConvX86GccFastCall` - GCC fastcall convention (2 register arguments).
 | ||||
| //!   - `kCallConvX86GccRegParm1` - GCC regparm(1) convention.
 | ||||
| //!   - `kCallConvX86GccRegParm2` - GCC regparm(2) convention.
 | ||||
| //!   - `kCallConvX86GccRegParm3` - GCC regparm(3) convention.
 | ||||
| //!
 | ||||
| //! List of calling conventions for 64-bit x86 mode (x64):
 | ||||
| //!   - `kCallConvX64Win` - Windows 64-bit calling convention (WIN64 ABI).
 | ||||
| //!   - `kCallConvX64Unix` - Unix 64-bit calling convention (AMD64 ABI).
 | ||||
| //!
 | ||||
| //! ARM Specific Conventions
 | ||||
| //! ------------------------
 | ||||
| //!
 | ||||
| //! List of ARM calling conventions:
 | ||||
| //!   - `kCallConvArm32SoftFP` - Legacy calling convention, floating point
 | ||||
| //!     arguments are passed via GP registers.
 | ||||
| //!   - `kCallConvArm32HardFP` - Modern calling convention, uses VFP registers
 | ||||
| //!     to pass floating point arguments.
 | ||||
| ASMJIT_ENUM(CallConv) { | ||||
|   //! Calling convention is invalid (can't be used).
 | ||||
|   kCallConvNone = 0, | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [X86]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! X86 `__cdecl` calling convention (used by C runtime and libraries).
 | ||||
|   //!
 | ||||
|   //! Compatible across MSVC and GCC.
 | ||||
|   //!
 | ||||
|   //! Arguments direction:
 | ||||
|   //! - Right to left.
 | ||||
|   //!
 | ||||
|   //! Stack is cleaned by:
 | ||||
|   //! - Caller.
 | ||||
|   //!
 | ||||
|   //! Return value:
 | ||||
|   //! - Integer types - `eax:edx` registers.
 | ||||
|   //! - Floating point - `fp0` register.
 | ||||
|   kCallConvX86CDecl = 1, | ||||
| 
 | ||||
|   //! X86 `__stdcall` calling convention (used mostly by WinAPI).
 | ||||
|   //!
 | ||||
|   //! Compatible across MSVC and GCC.
 | ||||
|   //!
 | ||||
|   //! Arguments direction:
 | ||||
|   //! - Right to left.
 | ||||
|   //!
 | ||||
|   //! Stack is cleaned by:
 | ||||
|   //! - Callee.
 | ||||
|   //!
 | ||||
|   //! Return value:
 | ||||
|   //! - Integer types - `eax:edx` registers.
 | ||||
|   //! - Floating point - `fp0` register.
 | ||||
|   kCallConvX86StdCall = 2, | ||||
| 
 | ||||
|   //! X86 `__thiscall` calling convention (MSVC/Intel specific).
 | ||||
|   //!
 | ||||
|   //! This is MSVC (and Intel) specific calling convention used when targeting
 | ||||
|   //! Windows platform for C++ class methods. Implicit `this` pointer (defined
 | ||||
|   //! as the first argument) is stored in `ecx` register instead of storing it
 | ||||
|   //! on the stack.
 | ||||
|   //!
 | ||||
|   //! This calling convention is implicitly used by MSVC for class functions.
 | ||||
|   //!
 | ||||
|   //! C++ class functions that have variable number of arguments use `__cdecl`
 | ||||
|   //! calling convention instead.
 | ||||
|   //!
 | ||||
|   //! Arguments direction:
 | ||||
|   //! - Right to left (except for the first argument passed in `ecx`).
 | ||||
|   //!
 | ||||
|   //! Stack is cleaned by:
 | ||||
|   //! - Callee.
 | ||||
|   //!
 | ||||
|   //! Return value:
 | ||||
|   //! - Integer types - `eax:edx` registers.
 | ||||
|   //! - Floating point - `fp0` register.
 | ||||
|   kCallConvX86MsThisCall = 3, | ||||
| 
 | ||||
|   //! X86 `__fastcall` convention (MSVC/Intel specific).
 | ||||
|   //!
 | ||||
|   //! The first two arguments (evaluated from the left to the right) are passed
 | ||||
|   //! in `ecx` and `edx` registers, all others on the stack from the right to
 | ||||
|   //! the left.
 | ||||
|   //!
 | ||||
|   //! Arguments direction:
 | ||||
|   //! - Right to left (except for the first two integers passed in `ecx` and `edx`).
 | ||||
|   //!
 | ||||
|   //! Stack is cleaned by:
 | ||||
|   //! - Callee.
 | ||||
|   //!
 | ||||
|   //! Return value:
 | ||||
|   //! - Integer types - `eax:edx` registers.
 | ||||
|   //! - Floating point - `fp0` register.
 | ||||
|   //!
 | ||||
|   //! NOTE: This calling convention differs from GCC's one.
 | ||||
|   kCallConvX86MsFastCall = 4, | ||||
| 
 | ||||
|   //! X86 `__fastcall` convention (Borland specific).
 | ||||
|   //!
 | ||||
|   //! The first two arguments (evaluated from the left to the right) are passed
 | ||||
|   //! in `ecx` and `edx` registers, all others on the stack from the left to
 | ||||
|   //! the right.
 | ||||
|   //!
 | ||||
|   //! Arguments direction:
 | ||||
|   //! - Left to right (except for the first two integers passed in `ecx` and `edx`).
 | ||||
|   //!
 | ||||
|   //! Stack is cleaned by:
 | ||||
|   //! - Callee.
 | ||||
|   //!
 | ||||
|   //! Return value:
 | ||||
|   //! - Integer types - `eax:edx` registers.
 | ||||
|   //! - Floating point - `fp0` register.
 | ||||
|   //!
 | ||||
|   //! NOTE: Arguments on the stack are in passed in left to right order, which
 | ||||
|   //! is really Borland specific, all other `__fastcall` calling conventions
 | ||||
|   //! use right to left order.
 | ||||
|   kCallConvX86BorlandFastCall = 5, | ||||
| 
 | ||||
|   //! X86 `__fastcall` convention (GCC specific).
 | ||||
|   //!
 | ||||
|   //! The first two arguments (evaluated from the left to the right) are passed
 | ||||
|   //! in `ecx` and `edx` registers, all others on the stack from the right to
 | ||||
|   //! the left.
 | ||||
|   //!
 | ||||
|   //! Arguments direction:
 | ||||
|   //! - Right to left (except for the first two integers passed in `ecx` and `edx`).
 | ||||
|   //!
 | ||||
|   //! Stack is cleaned by:
 | ||||
|   //! - Callee.
 | ||||
|   //!
 | ||||
|   //! Return value:
 | ||||
|   //! - Integer types - `eax:edx` registers.
 | ||||
|   //! - Floating point - `fp0` register.
 | ||||
|   //!
 | ||||
|   //! NOTE: This calling convention should be compatible with `kCallConvX86MsFastCall`.
 | ||||
|   kCallConvX86GccFastCall = 6, | ||||
| 
 | ||||
|   //! X86 `regparm(1)` convention (GCC specific).
 | ||||
|   //!
 | ||||
|   //! The first argument (evaluated from the left to the right) is passed in
 | ||||
|   //! `eax` register, all others on the stack from the right to the left.
 | ||||
|   //!
 | ||||
|   //! Arguments direction:
 | ||||
|   //! - Right to left (except for the first integer passed in `eax`).
 | ||||
|   //!
 | ||||
|   //! Stack is cleaned by:
 | ||||
|   //! - Caller.
 | ||||
|   //!
 | ||||
|   //! Return value:
 | ||||
|   //! - Integer types - `eax:edx` registers.
 | ||||
|   //! - Floating point - `fp0` register.
 | ||||
|   kCallConvX86GccRegParm1 = 7, | ||||
| 
 | ||||
|   //! X86 `regparm(2)` convention (GCC specific).
 | ||||
|   //!
 | ||||
|   //! The first two arguments (evaluated from the left to the right) are passed
 | ||||
|   //! in `ecx` and `edx` registers, all others on the stack from the right to
 | ||||
|   //! the left.
 | ||||
|   //!
 | ||||
|   //! Arguments direction:
 | ||||
|   //! - Right to left (except for the first two integers passed in `ecx` and `edx`).
 | ||||
|   //!
 | ||||
|   //! Stack is cleaned by:
 | ||||
|   //! - Caller.
 | ||||
|   //!
 | ||||
|   //! Return value:
 | ||||
|   //! - Integer types - `eax:edx` registers.
 | ||||
|   //! - Floating point - `fp0` register.
 | ||||
|   kCallConvX86GccRegParm2 = 8, | ||||
| 
 | ||||
|   //! X86 `regparm(3)` convention (GCC specific).
 | ||||
|   //!
 | ||||
|   //! Three first parameters (evaluated from left-to-right) are in
 | ||||
|   //! EAX:EDX:ECX registers, all others on the stack in right-to-left direction.
 | ||||
|   //!
 | ||||
|   //! Arguments direction:
 | ||||
|   //! - Right to left (except for the first three integers passed in `ecx`,
 | ||||
|   //!   `edx`, and `ecx`).
 | ||||
|   //!
 | ||||
|   //! Stack is cleaned by:
 | ||||
|   //! - Caller.
 | ||||
|   //!
 | ||||
|   //! Return value:
 | ||||
|   //! - Integer types - `eax:edx` registers.
 | ||||
|   //! - Floating point - `fp0` register.
 | ||||
|   kCallConvX86GccRegParm3 = 9, | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [X64]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! X64 calling convention used by Windows platform (WIN64-ABI).
 | ||||
|   //!
 | ||||
|   //! The first 4 arguments are passed in the following registers:
 | ||||
|   //! - 1. 32/64-bit integer in `rcx` and floating point argument in `xmm0`
 | ||||
|   //! - 2. 32/64-bit integer in `rdx` and floating point argument in `xmm1`
 | ||||
|   //! - 3. 32/64-bit integer in `r8` and floating point argument in `xmm2`
 | ||||
|   //! - 4. 32/64-bit integer in `r9` and floating point argument in `xmm3`
 | ||||
|   //!
 | ||||
|   //! If one or more argument from the first four doesn't match the list above
 | ||||
|   //! it is simply skipped. WIN64-ABI is very specific about this.
 | ||||
|   //!
 | ||||
|   //! All other arguments are pushed on the stack from the right to the left.
 | ||||
|   //! Stack has to be aligned by 16 bytes, always. There is also a 32-byte
 | ||||
|   //! shadow space on the stack that can be used to save up to four 64-bit
 | ||||
|   //! registers.
 | ||||
|   //!
 | ||||
|   //! Arguments direction:
 | ||||
|   //! - Right to left (except for all parameters passed in registers).
 | ||||
|   //!
 | ||||
|   //! Stack cleaned by:
 | ||||
|   //! - Caller.
 | ||||
|   //!
 | ||||
|   //! Return value:
 | ||||
|   //! - Integer types - `rax`.
 | ||||
|   //! - Floating point - `xmm0`.
 | ||||
|   //!
 | ||||
|   //! Stack is always aligned to 16 bytes.
 | ||||
|   //!
 | ||||
|   //! More information about this calling convention can be found on MSDN
 | ||||
|   //!   <http://msdn.microsoft.com/en-us/library/9b372w95.aspx>.
 | ||||
|   kCallConvX64Win = 10, | ||||
| 
 | ||||
|   //! X64 calling convention used by Unix platforms (AMD64-ABI).
 | ||||
|   //!
 | ||||
|   //! First six 32 or 64-bit integer arguments are passed in `rdi`, `rsi`,
 | ||||
|   //! `rdx`, `rcx`, `r8`, and `r9` registers. First eight floating point or xmm
 | ||||
|   //! arguments are passed in `xmm0`, `xmm1`, `xmm2`, `xmm3`, `xmm4`, `xmm5`,
 | ||||
|   //! `xmm6`, and `xmm7` registers.
 | ||||
|   //!
 | ||||
|   //! There is also a red zene below the stack pointer that can be used by the
 | ||||
|   //! function. The red zone is typically from [rsp-128] to [rsp-8], however,
 | ||||
|   //! red zone can also be disabled.
 | ||||
|   //!
 | ||||
|   //! Arguments direction:
 | ||||
|   //! - Right to left (except for all arguments passed in registers).
 | ||||
|   //!
 | ||||
|   //! Stack cleaned by:
 | ||||
|   //! - Caller.
 | ||||
|   //!
 | ||||
|   //! Return value:
 | ||||
|   //! - Integer types - `rax`.
 | ||||
|   //! - Floating point - `xmm0`.
 | ||||
|   //!
 | ||||
|   //! Stack is always aligned to 16 bytes.
 | ||||
|   kCallConvX64Unix = 11, | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [ARM]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   kCallConvArm32SoftFP = 16, | ||||
|   kCallConvArm32HardFP = 17, | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Internal]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   _kCallConvX86Start = 1, | ||||
|   //! \internal
 | ||||
|   _kCallConvX86End = 9, | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   _kCallConvX64Start = 10, | ||||
|   //! \internal
 | ||||
|   _kCallConvX64End = 11, | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   _kCallConvArmStart = 16, | ||||
|   //! \internal
 | ||||
|   _kCallConvArmEnd = 17, | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Host]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
| #if defined(ASMJIT_DOCGEN) | ||||
|   //! Default calling convention based on the current compiler's settings.
 | ||||
|   //!
 | ||||
|   //! NOTE: This should be always the same as `kCallConvHostCDecl`, but some
 | ||||
|   //! compilers allow to override the default calling convention. Overriding
 | ||||
|   //! is not detected at the moment.
 | ||||
|   kCallConvHost         = DETECTED_AT_COMPILE_TIME, | ||||
|   //! Default C calling convention based on the current compiler's settings.
 | ||||
|   kCallConvHostCDecl    = DETECTED_AT_COMPILE_TIME, | ||||
|   //! Compatibility for `__stdcall` calling convention.
 | ||||
|   //!
 | ||||
|   //! NOTE: This enumeration is always set to a value which is compatible with
 | ||||
|   //! the current compiler's `__stdcall` calling convention. In 64-bit mode
 | ||||
|   //! there is no such convention and the value is mapped to `kCallConvX64Win`
 | ||||
|   //! or `kCallConvX64Unix`, depending on the host architecture.
 | ||||
|   kCallConvHostStdCall  = DETECTED_AT_COMPILE_TIME, | ||||
|   //! Compatibility for `__fastcall` calling convention.
 | ||||
|   //!
 | ||||
|   //! NOTE: This enumeration is always set to a value which is compatible with
 | ||||
|   //! the current compiler's `__fastcall` calling convention. In 64-bit mode
 | ||||
|   //! there is no such convention and the value is mapped to `kCallConvX64Win`
 | ||||
|   //! or `kCallConvX64Unix`, depending on the host architecture.
 | ||||
|   kCallConvHostFastCall = DETECTED_AT_COMPILE_TIME | ||||
| #elif ASMJIT_ARCH_X86 | ||||
|   // X86 Host Support.
 | ||||
|   kCallConvHost         = kCallConvX86CDecl, | ||||
|   kCallConvHostCDecl    = kCallConvX86CDecl, | ||||
|   kCallConvHostStdCall  = kCallConvX86StdCall, | ||||
|   kCallConvHostFastCall = | ||||
|     ASMJIT_CC_MSC       ? kCallConvX86MsFastCall      : | ||||
|     ASMJIT_CC_GCC       ? kCallConvX86GccFastCall     : | ||||
|     ASMJIT_CC_CLANG     ? kCallConvX86GccFastCall     : | ||||
|     ASMJIT_CC_CODEGEAR  ? kCallConvX86BorlandFastCall : kCallConvNone | ||||
| #elif ASMJIT_ARCH_X64 | ||||
|   // X64 Host Support.
 | ||||
|   kCallConvHost         = ASMJIT_OS_WINDOWS ? kCallConvX64Win : kCallConvX64Unix, | ||||
|   // These don't exist in 64-bit mode.
 | ||||
|   kCallConvHostCDecl    = kCallConvHost, | ||||
|   kCallConvHostStdCall  = kCallConvHost, | ||||
|   kCallConvHostFastCall = kCallConvHost | ||||
| #elif ASMJIT_ARCH_ARM32 | ||||
| # if defined(__SOFTFP__) | ||||
|   kCallConvHost         = kCallConvArm32SoftFP, | ||||
| # else | ||||
|   kCallConvHost         = kCallConvArm32HardFP, | ||||
| # endif | ||||
|   // These don't exist on ARM.
 | ||||
|   kCallConvHostCDecl    = kCallConvHost, | ||||
|   kCallConvHostStdCall  = kCallConvHost, | ||||
|   kCallConvHostFastCall = kCallConvHost | ||||
| #else | ||||
| # error "[asmjit] Couldn't determine the target's calling convention." | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::ErrorCode]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! AsmJit error codes.
 | ||||
| ASMJIT_ENUM(ErrorCode) { | ||||
|   //! No error (success).
 | ||||
|   //!
 | ||||
|   //! This is default state and state you want.
 | ||||
|   kErrorOk = 0, | ||||
| 
 | ||||
|   //! Heap memory allocation failed.
 | ||||
|   kErrorNoHeapMemory, | ||||
| 
 | ||||
|   //! Virtual memory allocation failed.
 | ||||
|   kErrorNoVirtualMemory, | ||||
| 
 | ||||
|   //! Invalid argument.
 | ||||
|   kErrorInvalidArgument, | ||||
| 
 | ||||
|   //! Invalid state.
 | ||||
|   kErrorInvalidState, | ||||
| 
 | ||||
|   //! Invalid architecture.
 | ||||
|   kErrorInvalidArch, | ||||
| 
 | ||||
|   //! The object is not initialized.
 | ||||
|   kErrorNotInitialized, | ||||
| 
 | ||||
|   //! No code generated.
 | ||||
|   //!
 | ||||
|   //! Returned by runtime if the code-generator contains no code.
 | ||||
|   kErrorNoCodeGenerated, | ||||
| 
 | ||||
|   //! Code generated is too large to fit in memory reserved.
 | ||||
|   //!
 | ||||
|   //! Returned by `StaticRuntime` in case that the code generated is too large
 | ||||
|   //! to fit in the memory already reserved for it.
 | ||||
|   kErrorCodeTooLarge, | ||||
| 
 | ||||
|   //! Label is already bound.
 | ||||
|   kErrorLabelAlreadyBound, | ||||
| 
 | ||||
|   //! Unknown instruction (an instruction ID is out of bounds or instruction
 | ||||
|   //! name is invalid).
 | ||||
|   kErrorUnknownInst, | ||||
| 
 | ||||
|   //! Illegal instruction.
 | ||||
|   //!
 | ||||
|   //! This status code can also be returned in X64 mode if AH, BH, CH or DH
 | ||||
|   //! registers have been used together with a REX prefix. The instruction
 | ||||
|   //! is not encodable in such case.
 | ||||
|   //!
 | ||||
|   //! Example of raising `kErrorIllegalInst` error.
 | ||||
|   //!
 | ||||
|   //! ~~~
 | ||||
|   //! // Invalid address size.
 | ||||
|   //! a.mov(dword_ptr(eax), al);
 | ||||
|   //!
 | ||||
|   //! // Undecodable instruction - AH used with R10, however R10 can only be
 | ||||
|   //! // encoded by using REX prefix, which conflicts with AH.
 | ||||
|   //! a.mov(byte_ptr(r10), ah);
 | ||||
|   //! ~~~
 | ||||
|   //!
 | ||||
|   //! NOTE: In debug mode assertion is raised instead of returning an error.
 | ||||
|   kErrorIllegalInst, | ||||
| 
 | ||||
|   //! Illegal (unencodable) addressing used.
 | ||||
|   kErrorIllegalAddresing, | ||||
| 
 | ||||
|   //! Illegal (unencodable) displacement used.
 | ||||
|   //!
 | ||||
|   //! X86/X64 Specific
 | ||||
|   //! ----------------
 | ||||
|   //!
 | ||||
|   //! Short form of jump instruction has been used, but the displacement is out
 | ||||
|   //! of bounds.
 | ||||
|   kErrorIllegalDisplacement, | ||||
| 
 | ||||
|   //! A variable has been assigned more than once to a function argument (Compiler).
 | ||||
|   kErrorOverlappedArgs, | ||||
| 
 | ||||
|   //! Count of AsmJit error codes.
 | ||||
|   kErrorCount | ||||
| }; | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Init / NoInit]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #if !defined(ASMJIT_DOCGEN) | ||||
| struct _Init {}; | ||||
| static const _Init Init = {}; | ||||
| 
 | ||||
| struct _NoInit {}; | ||||
| static const _NoInit NoInit = {}; | ||||
| #endif // !ASMJIT_DOCGEN
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::DebugUtils]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| namespace DebugUtils { | ||||
| 
 | ||||
| //! Get a printable version of `asmjit::Error` value.
 | ||||
| ASMJIT_API const char* errorAsString(Error err) noexcept; | ||||
| 
 | ||||
| //! \addtogroup asmjit_base
 | ||||
| //! \{
 | ||||
| 
 | ||||
| //! Called in debug build to output a debugging message caused by assertion
 | ||||
| //! failure or tracing.
 | ||||
| ASMJIT_API void debugOutput(const char* str) noexcept; | ||||
| 
 | ||||
| //! Called in debug build on assertion failure.
 | ||||
| //!
 | ||||
| //! \param file Source file name where it happened.
 | ||||
| //! \param line Line in the source file.
 | ||||
| //! \param msg Message to display.
 | ||||
| //!
 | ||||
| //! If you have problems with assertions put a breakpoint at assertionFailed()
 | ||||
| //! function (asmjit/base/globals.cpp) and check the call stack to locate the
 | ||||
| //! failing code.
 | ||||
| ASMJIT_API void ASMJIT_NORETURN assertionFailed(const char* file, int line, const char* msg) noexcept; | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| } // DebugUtils namespace
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [ASMJIT_ASSERT]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #if defined(ASMJIT_DEBUG) | ||||
| # define ASMJIT_ASSERT(exp) \ | ||||
|   do { \ | ||||
|     if (!(exp)) { \ | ||||
|       ::asmjit::DebugUtils::assertionFailed( \ | ||||
|         __FILE__ + ::asmjit::DebugUtils::kSourceRelativePathOffset, \ | ||||
|         __LINE__, \ | ||||
|         #exp); \ | ||||
|     } \ | ||||
|   } while (0) | ||||
| # define ASMJIT_NOT_REACHED() \ | ||||
|   ::asmjit::DebugUtils::assertionFailed( \ | ||||
|     __FILE__ + ::asmjit::DebugUtils::kSourceRelativePathOffset, \ | ||||
|     __LINE__, \ | ||||
|     "MUST NOT BE REACHED") | ||||
| #else | ||||
| # define ASMJIT_ASSERT(exp) ASMJIT_NOP | ||||
| # define ASMJIT_NOT_REACHED() ASMJIT_ASSUME(0) | ||||
| #endif // DEBUG
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [ASMJIT_PROPAGATE_ERROR]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! Used by AsmJit to return the `_Exp_` result if it's an error.
 | ||||
| #define ASMJIT_PROPAGATE_ERROR(_Exp_) \ | ||||
|   do { \ | ||||
|     ::asmjit::Error _errval = (_Exp_); \ | ||||
|     if (_errval != ::asmjit::kErrorOk) \ | ||||
|       return _errval; \ | ||||
|   } while (0) | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit_cast<>]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! \addtogroup asmjit_base
 | ||||
| //! \{
 | ||||
| 
 | ||||
| //! Cast used to cast pointer to function. It's like reinterpret_cast<>,
 | ||||
| //! but uses internally C style cast to work with MinGW.
 | ||||
| //!
 | ||||
| //! If you are using single compiler and `reinterpret_cast<>` works for you,
 | ||||
| //! there is no reason to use `asmjit_cast<>`. If you are writing
 | ||||
| //! cross-platform software with various compiler support, consider using
 | ||||
| //! `asmjit_cast<>` instead of `reinterpret_cast<>`.
 | ||||
| template<typename T, typename Z> | ||||
| static ASMJIT_INLINE T asmjit_cast(Z* p) noexcept { return (T)p; } | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_BASE_GLOBALS_H
 | ||||
							
								
								
									
										20
									
								
								DynamicHooks/thirdparty/AsmJit/base/hlstream.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								DynamicHooks/thirdparty/AsmJit/base/hlstream.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/hlstream.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
							
								
								
									
										1174
									
								
								DynamicHooks/thirdparty/AsmJit/base/hlstream.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1174
									
								
								DynamicHooks/thirdparty/AsmJit/base/hlstream.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										194
									
								
								DynamicHooks/thirdparty/AsmJit/base/logger.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								DynamicHooks/thirdparty/AsmJit/base/logger.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,194 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #include "../build.h" | ||||
| #if !defined(ASMJIT_DISABLE_LOGGER) | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/containers.h" | ||||
| #include "../base/logger.h" | ||||
| #include "../base/utils.h" | ||||
| #include <stdarg.h> | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::LogUtil]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| bool LogUtil::formatLine(StringBuilder& sb, const uint8_t* binData, size_t binLen, size_t dispLen, size_t imLen, const char* comment) noexcept { | ||||
|   size_t currentLen = sb.getLength(); | ||||
|   size_t commentLen = comment ? Utils::strLen(comment, kMaxCommentLength) : 0; | ||||
| 
 | ||||
|   ASMJIT_ASSERT(binLen >= dispLen); | ||||
| 
 | ||||
|   if ((binLen != 0 && binLen != kInvalidIndex) || commentLen) { | ||||
|     size_t align = kMaxInstLength; | ||||
|     char sep = ';'; | ||||
| 
 | ||||
|     for (size_t i = (binLen == kInvalidIndex); i < 2; i++) { | ||||
|       size_t begin = sb.getLength(); | ||||
| 
 | ||||
|       // Append align.
 | ||||
|       if (currentLen < align) { | ||||
|         if (!sb.appendChars(' ', align - currentLen)) | ||||
|           return false; | ||||
|       } | ||||
| 
 | ||||
|       // Append separator.
 | ||||
|       if (sep) { | ||||
|         if (!(sb.appendChar(sep) & sb.appendChar(' '))) | ||||
|           return false; | ||||
|       } | ||||
| 
 | ||||
|       // Append binary data or comment.
 | ||||
|       if (i == 0) { | ||||
|         if (!sb.appendHex(binData, binLen - dispLen - imLen)) | ||||
|           return false; | ||||
|         if (!sb.appendChars('.', dispLen * 2)) | ||||
|           return false; | ||||
|         if (!sb.appendHex(binData + binLen - imLen, imLen)) | ||||
|           return false; | ||||
|         if (commentLen == 0) | ||||
|           break; | ||||
|       } | ||||
|       else { | ||||
|         if (!sb.appendString(comment, commentLen)) | ||||
|           return false; | ||||
|       } | ||||
| 
 | ||||
|       currentLen += sb.getLength() - begin; | ||||
|       align += kMaxBinaryLength; | ||||
|       sep = '|'; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return sb.appendChar('\n'); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Logger - Construction / Destruction]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Logger::Logger() noexcept { | ||||
|   _options = 0; | ||||
|   ::memset(_indentation, 0, ASMJIT_ARRAY_SIZE(_indentation)); | ||||
| } | ||||
| 
 | ||||
| Logger::~Logger() noexcept {} | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Logger - Logging]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void Logger::logFormat(uint32_t style, const char* fmt, ...) noexcept { | ||||
|   char buf[1024]; | ||||
|   size_t len; | ||||
| 
 | ||||
|   va_list ap; | ||||
|   va_start(ap, fmt); | ||||
|   len = vsnprintf(buf, sizeof(buf), fmt, ap); | ||||
|   va_end(ap); | ||||
| 
 | ||||
|   if (len >= sizeof(buf)) | ||||
|     len = sizeof(buf) - 1; | ||||
| 
 | ||||
|   logString(style, buf, len); | ||||
| } | ||||
| 
 | ||||
| void Logger::logBinary(uint32_t style, const void* data, size_t size) noexcept { | ||||
|   static const char prefix[] = ".data "; | ||||
|   static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; | ||||
| 
 | ||||
|   const uint8_t* s = static_cast<const uint8_t*>(data); | ||||
|   size_t i = size; | ||||
| 
 | ||||
|   char buffer[128]; | ||||
|   ::memcpy(buffer, prefix, ASMJIT_ARRAY_SIZE(prefix) - 1); | ||||
| 
 | ||||
|   while (i) { | ||||
|     uint32_t n = static_cast<uint32_t>(Utils::iMin<size_t>(i, 16)); | ||||
|     char* p = buffer + ASMJIT_ARRAY_SIZE(prefix) - 1; | ||||
| 
 | ||||
|     i -= n; | ||||
|     do { | ||||
|       uint32_t c = s[0]; | ||||
| 
 | ||||
|       p[0] = hex[c >> 4]; | ||||
|       p[1] = hex[c & 15]; | ||||
| 
 | ||||
|       p += 2; | ||||
|       s += 1; | ||||
|     } while (--n); | ||||
| 
 | ||||
|     *p++ = '\n'; | ||||
|     logString(style, buffer, (size_t)(p - buffer)); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Logger - Indentation]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void Logger::setIndentation(const char* indentation) noexcept { | ||||
|   ::memset(_indentation, 0, ASMJIT_ARRAY_SIZE(_indentation)); | ||||
|   if (!indentation) | ||||
|     return; | ||||
| 
 | ||||
|   size_t length = Utils::strLen(indentation, ASMJIT_ARRAY_SIZE(_indentation) - 1); | ||||
|   ::memcpy(_indentation, indentation, length); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::FileLogger - Construction / Destruction]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| FileLogger::FileLogger(FILE* stream) noexcept : _stream(nullptr) { setStream(stream); } | ||||
| FileLogger::~FileLogger() noexcept {} | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::FileLogger - Logging]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void FileLogger::logString(uint32_t style, const char* buf, size_t len) noexcept { | ||||
|   if (!_stream) | ||||
|     return; | ||||
| 
 | ||||
|   if (len == kInvalidIndex) | ||||
|     len = strlen(buf); | ||||
| 
 | ||||
|   fwrite(buf, 1, len, _stream); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::StringLogger - Construction / Destruction]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| StringLogger::StringLogger() noexcept {} | ||||
| StringLogger::~StringLogger() noexcept {} | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::StringLogger - Logging]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void StringLogger::logString(uint32_t style, const char* buf, size_t len) noexcept { | ||||
|   _stringBuilder.appendString(buf, len); | ||||
| } | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // !ASMJIT_DISABLE_LOGGER
 | ||||
							
								
								
									
										268
									
								
								DynamicHooks/thirdparty/AsmJit/base/logger.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								DynamicHooks/thirdparty/AsmJit/base/logger.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,268 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_BASE_LOGGER_H | ||||
| #define _ASMJIT_BASE_LOGGER_H | ||||
| 
 | ||||
| #include "../build.h" | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/containers.h" | ||||
| #include <stdarg.h> | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| //! \addtogroup asmjit_base
 | ||||
| //! \{
 | ||||
| 
 | ||||
| #if !defined(ASMJIT_DISABLE_LOGGER) | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::LogUtil]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // Only used by asmjit internals, not available to consumers.
 | ||||
| #if defined(ASMJIT_EXPORTS) | ||||
| struct LogUtil { | ||||
|   enum { | ||||
|     // Has to be big to be able to hold all metadata compiler can assign to a
 | ||||
|     // single instruction.
 | ||||
|     kMaxCommentLength = 512, | ||||
|     kMaxInstLength = 40, | ||||
|     kMaxBinaryLength = 26 | ||||
|   }; | ||||
| 
 | ||||
|   static bool formatLine( | ||||
|     StringBuilder& sb, | ||||
|     const uint8_t* binData, size_t binLen, size_t dispLen, size_t imLen, const char* comment) noexcept; | ||||
| }; | ||||
| #endif // ASMJIT_EXPORTS
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Logger]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Abstract logging class.
 | ||||
| //!
 | ||||
| //! This class can be inherited and reimplemented to fit into your logging
 | ||||
| //! subsystem. When reimplementing use `Logger::log()` method to log into
 | ||||
| //! a custom stream.
 | ||||
| //!
 | ||||
| //! This class also contain `_enabled` member that can be used to enable
 | ||||
| //! or disable logging.
 | ||||
| class ASMJIT_VIRTAPI Logger { | ||||
|  public: | ||||
|   ASMJIT_NO_COPY(Logger) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Options]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Logger options.
 | ||||
|   ASMJIT_ENUM(Options) { | ||||
|     kOptionBinaryForm      = 0x00000001, //! Output instructions also in binary form.
 | ||||
|     kOptionHexImmediate    = 0x00000002, //! Output immediates as hexadecimal numbers.
 | ||||
|     kOptionHexDisplacement = 0x00000004  //! Output displacements as hexadecimal numbers.
 | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Style]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Logger style.
 | ||||
|   ASMJIT_ENUM(Style) { | ||||
|     kStyleDefault = 0, | ||||
|     kStyleDirective = 1, | ||||
|     kStyleLabel = 2, | ||||
|     kStyleData = 3, | ||||
|     kStyleComment = 4, | ||||
| 
 | ||||
|     kStyleCount = 5 | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Create a `Logger` instance.
 | ||||
|   ASMJIT_API Logger() noexcept; | ||||
|   //! Destroy the `Logger` instance.
 | ||||
|   ASMJIT_API virtual ~Logger() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Logging]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Log output.
 | ||||
|   virtual void logString(uint32_t style, const char* buf, size_t len = kInvalidIndex) noexcept = 0; | ||||
| 
 | ||||
|   //! Log formatter message (like sprintf) sending output to `logString()` method.
 | ||||
|   ASMJIT_API void logFormat(uint32_t style, const char* fmt, ...) noexcept; | ||||
|   //! Log binary data.
 | ||||
|   ASMJIT_API void logBinary(uint32_t style, const void* data, size_t size) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Options]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get all logger options as a single integer.
 | ||||
|   ASMJIT_INLINE uint32_t getOptions() const noexcept { return _options; } | ||||
| 
 | ||||
|   //! Get the given logger option.
 | ||||
|   ASMJIT_INLINE bool hasOption(uint32_t option) const noexcept { | ||||
|     return (_options & option) != 0; | ||||
|   } | ||||
|   ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _options |= options; } | ||||
|   ASMJIT_INLINE void clearOptions(uint32_t options) noexcept { _options &= ~options; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Indentation]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get indentation.
 | ||||
|   ASMJIT_INLINE const char* getIndentation() const noexcept { | ||||
|     return _indentation; | ||||
|   } | ||||
| 
 | ||||
|   //! Set indentation.
 | ||||
|   ASMJIT_API void setIndentation(const char* indentation) noexcept; | ||||
| 
 | ||||
|   //! Reset indentation.
 | ||||
|   ASMJIT_INLINE void resetIndentation() noexcept { | ||||
|     setIndentation(nullptr); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Options, see \ref LoggerOption.
 | ||||
|   uint32_t _options; | ||||
| 
 | ||||
|   //! Indentation.
 | ||||
|   char _indentation[12]; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::FileLogger]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Logger that can log to standard C `FILE*` stream.
 | ||||
| class ASMJIT_VIRTAPI FileLogger : public Logger { | ||||
|  public: | ||||
|   ASMJIT_NO_COPY(FileLogger) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Create a new `FileLogger` that logs to a `FILE` stream.
 | ||||
|   ASMJIT_API FileLogger(FILE* stream = nullptr) noexcept; | ||||
| 
 | ||||
|   //! Destroy the `FileLogger`.
 | ||||
|   ASMJIT_API virtual ~FileLogger() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get `FILE*` stream.
 | ||||
|   //!
 | ||||
|   //! NOTE: Return value can be `nullptr`.
 | ||||
|   ASMJIT_INLINE FILE* getStream() const noexcept { | ||||
|     return _stream; | ||||
|   } | ||||
| 
 | ||||
|   //! Set `FILE*` stream, can be set to `nullptr` to disable logging, although
 | ||||
|   //! the `ExternalTool` will still call `logString` even if there is no stream.
 | ||||
|   ASMJIT_INLINE void setStream(FILE* stream) noexcept { | ||||
|     _stream = stream; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Logging]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_API virtual void logString(uint32_t style, const char* buf, size_t len = kInvalidIndex) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! C file stream.
 | ||||
|   FILE* _stream; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::StringLogger]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! String logger.
 | ||||
| class ASMJIT_VIRTAPI StringLogger : public Logger { | ||||
|  public: | ||||
|   ASMJIT_NO_COPY(StringLogger) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Create new `StringLogger`.
 | ||||
|   ASMJIT_API StringLogger() noexcept; | ||||
| 
 | ||||
|   //! Destroy the `StringLogger`.
 | ||||
|   ASMJIT_API virtual ~StringLogger() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get `char*` pointer which represents the resulting string.
 | ||||
|   //!
 | ||||
|   //! The pointer is owned by `StringLogger`, it can't be modified or freed.
 | ||||
|   ASMJIT_INLINE const char* getString() const noexcept { | ||||
|     return _stringBuilder.getData(); | ||||
|   } | ||||
| 
 | ||||
|   //! Get the length of the string returned by `getString()`.
 | ||||
|   ASMJIT_INLINE size_t getLength() const noexcept { | ||||
|     return _stringBuilder.getLength(); | ||||
|   } | ||||
| 
 | ||||
|   //! Clear the resulting string.
 | ||||
|   ASMJIT_INLINE void clearString() noexcept { | ||||
|     _stringBuilder.clear(); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Logging]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_API virtual void logString(uint32_t style, const char* buf, size_t len = kInvalidIndex) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Output.
 | ||||
|   StringBuilder _stringBuilder; | ||||
| }; | ||||
| #else | ||||
| struct Logger; | ||||
| #endif // !ASMJIT_DISABLE_LOGGER
 | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_BASE_LOGGER_H
 | ||||
							
								
								
									
										52
									
								
								DynamicHooks/thirdparty/AsmJit/base/operand.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								DynamicHooks/thirdparty/AsmJit/base/operand.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/globals.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Operand]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // Prevent static initialization.
 | ||||
| class Operand { | ||||
|  public: | ||||
|   struct BaseOp { | ||||
|     uint8_t op; | ||||
|     uint8_t size; | ||||
|     uint8_t reserved_2_1; | ||||
|     uint8_t reserved_3_1; | ||||
| 
 | ||||
|     uint32_t id; | ||||
| 
 | ||||
|     uint32_t reserved_8_4; | ||||
|     uint32_t reserved_12_4; | ||||
|   }; | ||||
| 
 | ||||
|   // Kept in union to prevent LTO warnings.
 | ||||
|   union { | ||||
|     BaseOp _base; | ||||
| 
 | ||||
|     // Required to properly align this _fake_ `Operand`, not used.
 | ||||
|     uint64_t _data[2]; | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| ASMJIT_VARAPI const Operand noOperand; | ||||
| const Operand noOperand = {{ 0, 0, 0, 0, kInvalidValue, 0, 0 }}; | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
							
								
								
									
										1192
									
								
								DynamicHooks/thirdparty/AsmJit/base/operand.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1192
									
								
								DynamicHooks/thirdparty/AsmJit/base/operand.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										132
									
								
								DynamicHooks/thirdparty/AsmJit/base/podvector.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								DynamicHooks/thirdparty/AsmJit/base/podvector.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,132 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/podvector.h" | ||||
| #include "../base/utils.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::PodVectorBase - NullData]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| const PodVectorBase::Data PodVectorBase::_nullData = { 0, 0 }; | ||||
| 
 | ||||
| static ASMJIT_INLINE bool isDataStatic(PodVectorBase* self, PodVectorBase::Data* d) noexcept { | ||||
|   return (void*)(self + 1) == (void*)d; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::PodVectorBase - Reset]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Clear vector data and free internal buffer.
 | ||||
| void PodVectorBase::reset(bool releaseMemory) noexcept { | ||||
|   Data* d = _d; | ||||
|   if (d == &_nullData) | ||||
|     return; | ||||
| 
 | ||||
|   if (releaseMemory && !isDataStatic(this, d)) { | ||||
|     ASMJIT_FREE(d); | ||||
|     _d = const_cast<Data*>(&_nullData); | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   d->length = 0; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::PodVectorBase - Helpers]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error PodVectorBase::_grow(size_t n, size_t sizeOfT) noexcept { | ||||
|   Data* d = _d; | ||||
| 
 | ||||
|   size_t threshold = kMemAllocGrowMax / sizeOfT; | ||||
|   size_t capacity = d->capacity; | ||||
|   size_t after = d->length; | ||||
| 
 | ||||
|   if (IntTraits<size_t>::maxValue() - n < after) | ||||
|     return kErrorNoHeapMemory; | ||||
| 
 | ||||
|   after += n; | ||||
| 
 | ||||
|   if (capacity >= after) | ||||
|     return kErrorOk; | ||||
| 
 | ||||
|   // PodVector is used as a linear array for some data structures used by
 | ||||
|   // AsmJit code generation. The purpose of this agressive growing schema
 | ||||
|   // is to minimize memory reallocations, because AsmJit code generation
 | ||||
|   // classes live short life and will be freed or reused soon.
 | ||||
|   if (capacity < 32) | ||||
|     capacity = 32; | ||||
|   else if (capacity < 128) | ||||
|     capacity = 128; | ||||
|   else if (capacity < 512) | ||||
|     capacity = 512; | ||||
| 
 | ||||
|   while (capacity < after) { | ||||
|     if (capacity < threshold) | ||||
|       capacity *= 2; | ||||
|     else | ||||
|       capacity += threshold; | ||||
|   } | ||||
| 
 | ||||
|   return _reserve(capacity, sizeOfT); | ||||
| } | ||||
| 
 | ||||
| Error PodVectorBase::_reserve(size_t n, size_t sizeOfT) noexcept { | ||||
|   Data* d = _d; | ||||
| 
 | ||||
|   if (d->capacity >= n) | ||||
|     return kErrorOk; | ||||
| 
 | ||||
|   size_t nBytes = sizeof(Data) + n * sizeOfT; | ||||
|   if (ASMJIT_UNLIKELY(nBytes < n)) | ||||
|     return kErrorNoHeapMemory; | ||||
| 
 | ||||
|   if (d == &_nullData) { | ||||
|     d = static_cast<Data*>(ASMJIT_ALLOC(nBytes)); | ||||
|     if (ASMJIT_UNLIKELY(d == nullptr)) | ||||
|       return kErrorNoHeapMemory; | ||||
|     d->length = 0; | ||||
|   } | ||||
|   else { | ||||
|     if (isDataStatic(this, d)) { | ||||
|       Data* oldD = d; | ||||
| 
 | ||||
|       d = static_cast<Data*>(ASMJIT_ALLOC(nBytes)); | ||||
|       if (ASMJIT_UNLIKELY(d == nullptr)) | ||||
|         return kErrorNoHeapMemory; | ||||
| 
 | ||||
|       size_t len = oldD->length; | ||||
|       d->length = len; | ||||
|       ::memcpy(d->getData(), oldD->getData(), len * sizeOfT); | ||||
|     } | ||||
|     else { | ||||
|       d = static_cast<Data*>(ASMJIT_REALLOC(d, nBytes)); | ||||
|       if (ASMJIT_UNLIKELY(d == nullptr)) | ||||
|         return kErrorNoHeapMemory; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   d->capacity = n; | ||||
|   _d = d; | ||||
| 
 | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
							
								
								
									
										281
									
								
								DynamicHooks/thirdparty/AsmJit/base/podvector.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								DynamicHooks/thirdparty/AsmJit/base/podvector.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,281 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_BASE_PODVECTOR_H | ||||
| #define _ASMJIT_BASE_PODVECTOR_H | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/globals.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| //! \addtogroup asmjit_base
 | ||||
| //! \{
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::PodVectorBase]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! \internal
 | ||||
| class PodVectorBase { | ||||
|  public: | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Data]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   struct Data { | ||||
|     //! Get data.
 | ||||
|     ASMJIT_INLINE void* getData() const noexcept { | ||||
|       return static_cast<void*>(const_cast<Data*>(this + 1)); | ||||
|     } | ||||
| 
 | ||||
|     //! Capacity of the vector.
 | ||||
|     size_t capacity; | ||||
|     //! Length of the vector.
 | ||||
|     size_t length; | ||||
|   }; | ||||
| 
 | ||||
|   static ASMJIT_API const Data _nullData; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Create a new instance of `PodVectorBase`.
 | ||||
|   ASMJIT_INLINE PodVectorBase() noexcept : _d(const_cast<Data*>(&_nullData)) {} | ||||
|   //! Destroy the `PodVectorBase` and its data.
 | ||||
|   ASMJIT_INLINE ~PodVectorBase() noexcept { reset(true); } | ||||
| 
 | ||||
| protected: | ||||
|   explicit ASMJIT_INLINE PodVectorBase(Data* d) noexcept : _d(d) {} | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Reset]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
| public: | ||||
|   //! Reset the vector data and set its `length` to zero.
 | ||||
|   //!
 | ||||
|   //! If `releaseMemory` is true the vector buffer will be released to the
 | ||||
|   //! system.
 | ||||
|   ASMJIT_API void reset(bool releaseMemory = false) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Grow / Reserve]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
| protected: | ||||
|   ASMJIT_API Error _grow(size_t n, size_t sizeOfT) noexcept; | ||||
|   ASMJIT_API Error _reserve(size_t n, size_t sizeOfT) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
| public: | ||||
|   Data* _d; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::PodVector<T>]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Template used to store and manage array of POD data.
 | ||||
| //!
 | ||||
| //! This template has these adventages over other vector<> templates:
 | ||||
| //! - Non-copyable (designed to be non-copyable, we want it)
 | ||||
| //! - No copy-on-write (some implementations of stl can use it)
 | ||||
| //! - Optimized for working only with POD types
 | ||||
| //! - Uses ASMJIT_... memory management macros
 | ||||
| template <typename T> | ||||
| class PodVector : public PodVectorBase { | ||||
|  public: | ||||
|   ASMJIT_NO_COPY(PodVector<T>) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Create a new instance of `PodVector<T>`.
 | ||||
|   ASMJIT_INLINE PodVector() noexcept {} | ||||
|   //! Destroy the `PodVector<T>` and its data.
 | ||||
|   ASMJIT_INLINE ~PodVector() noexcept {} | ||||
| 
 | ||||
| protected: | ||||
|   explicit ASMJIT_INLINE PodVector(Data* d) noexcept : PodVectorBase(d) {} | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Data]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
| public: | ||||
|   //! Get whether the vector is empty.
 | ||||
|   ASMJIT_INLINE bool isEmpty() const noexcept { return _d->length == 0; } | ||||
|   //! Get length.
 | ||||
|   ASMJIT_INLINE size_t getLength() const noexcept { return _d->length; } | ||||
|   //! Get capacity.
 | ||||
|   ASMJIT_INLINE size_t getCapacity() const noexcept { return _d->capacity; } | ||||
|   //! Get data.
 | ||||
|   ASMJIT_INLINE T* getData() noexcept { return static_cast<T*>(_d->getData()); } | ||||
|   //! \overload
 | ||||
|   ASMJIT_INLINE const T* getData() const noexcept { return static_cast<const T*>(_d->getData()); } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Grow / Reserve]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Called to grow the buffer to fit at least `n` elements more.
 | ||||
|   ASMJIT_INLINE Error _grow(size_t n) noexcept { return PodVectorBase::_grow(n, sizeof(T)); } | ||||
|   //! Realloc internal array to fit at least `n` items.
 | ||||
|   ASMJIT_INLINE Error _reserve(size_t n) noexcept { return PodVectorBase::_reserve(n, sizeof(T)); } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Ops]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Prepend `item` to vector.
 | ||||
|   Error prepend(const T& item) noexcept { | ||||
|     Data* d = _d; | ||||
| 
 | ||||
|     if (d->length == d->capacity) { | ||||
|       ASMJIT_PROPAGATE_ERROR(_grow(1)); | ||||
|       _d = d; | ||||
|     } | ||||
| 
 | ||||
|     ::memmove(static_cast<T*>(d->getData()) + 1, d->getData(), d->length * sizeof(T)); | ||||
|     ::memcpy(d->getData(), &item, sizeof(T)); | ||||
| 
 | ||||
|     d->length++; | ||||
|     return kErrorOk; | ||||
|   } | ||||
| 
 | ||||
|   //! Insert an `item` at the `index`.
 | ||||
|   Error insert(size_t index, const T& item) noexcept { | ||||
|     Data* d = _d; | ||||
|     ASMJIT_ASSERT(index <= d->length); | ||||
| 
 | ||||
|     if (d->length == d->capacity) { | ||||
|       ASMJIT_PROPAGATE_ERROR(_grow(1)); | ||||
|       d = _d; | ||||
|     } | ||||
| 
 | ||||
|     T* dst = static_cast<T*>(d->getData()) + index; | ||||
|     ::memmove(dst + 1, dst, d->length - index); | ||||
|     ::memcpy(dst, &item, sizeof(T)); | ||||
| 
 | ||||
|     d->length++; | ||||
|     return kErrorOk; | ||||
|   } | ||||
| 
 | ||||
|   //! Append `item` to vector.
 | ||||
|   Error append(const T& item) noexcept { | ||||
|     Data* d = _d; | ||||
| 
 | ||||
|     if (d->length == d->capacity) { | ||||
|       ASMJIT_PROPAGATE_ERROR(_grow(1)); | ||||
|       d = _d; | ||||
|     } | ||||
| 
 | ||||
|     ::memcpy(static_cast<T*>(d->getData()) + d->length, &item, sizeof(T)); | ||||
| 
 | ||||
|     d->length++; | ||||
|     return kErrorOk; | ||||
|   } | ||||
| 
 | ||||
|   //! Get index of `val` or `kInvalidIndex` if not found.
 | ||||
|   size_t indexOf(const T& val) const noexcept { | ||||
|     Data* d = _d; | ||||
| 
 | ||||
|     const T* data = static_cast<const T*>(d->getData()); | ||||
|     size_t len = d->length; | ||||
| 
 | ||||
|     for (size_t i = 0; i < len; i++) | ||||
|       if (data[i] == val) | ||||
|         return i; | ||||
| 
 | ||||
|     return kInvalidIndex; | ||||
|   } | ||||
| 
 | ||||
|   //! Remove item at index `i`.
 | ||||
|   void removeAt(size_t i) noexcept { | ||||
|     Data* d = _d; | ||||
|     ASMJIT_ASSERT(i < d->length); | ||||
| 
 | ||||
|     T* data = static_cast<T*>(d->getData()) + i; | ||||
|     d->length--; | ||||
|     ::memmove(data, data + 1, d->length - i); | ||||
|   } | ||||
| 
 | ||||
|   //! Swap this pod-vector with `other`.
 | ||||
|   void swap(PodVector<T>& other) noexcept { | ||||
|     T* otherData = other._d; | ||||
|     other._d = _d; | ||||
|     _d = otherData; | ||||
|   } | ||||
| 
 | ||||
|   //! Get item at index `i`.
 | ||||
|   ASMJIT_INLINE T& operator[](size_t i) noexcept { | ||||
|     ASMJIT_ASSERT(i < getLength()); | ||||
|     return getData()[i]; | ||||
|   } | ||||
| 
 | ||||
|   //! Get item at index `i`.
 | ||||
|   ASMJIT_INLINE const T& operator[](size_t i) const noexcept { | ||||
|     ASMJIT_ASSERT(i < getLength()); | ||||
|     return getData()[i]; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::PodVectorTmp<T>]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| template<typename T, size_t N> | ||||
| class PodVectorTmp : public PodVector<T> { | ||||
|  public: | ||||
|   ASMJIT_NO_COPY(PodVectorTmp<T, N>) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [StaticData]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   struct StaticData : public PodVectorBase::Data { | ||||
|     char data[sizeof(T) * N]; | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Create a new instance of `PodVectorTmp<T>`.
 | ||||
|   ASMJIT_INLINE PodVectorTmp() noexcept : PodVector<T>(&_staticData) { | ||||
|     _staticData.capacity = N; | ||||
|     _staticData.length = 0; | ||||
|   } | ||||
|   //! Destroy the `PodVectorTmp<T>` and its data.
 | ||||
|   ASMJIT_INLINE ~PodVectorTmp() noexcept {} | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   StaticData _staticData; | ||||
| }; | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_BASE_PODVECTOR_H
 | ||||
							
								
								
									
										214
									
								
								DynamicHooks/thirdparty/AsmJit/base/runtime.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								DynamicHooks/thirdparty/AsmJit/base/runtime.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,214 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/assembler.h" | ||||
| #include "../base/runtime.h" | ||||
| 
 | ||||
| // TODO: Rename this, or make call conv independent of CompilerFunc.
 | ||||
| #include "../base/compilerfunc.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Runtime - Utilities]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| static ASMJIT_INLINE uint32_t hostStackAlignment() noexcept { | ||||
|   // By default a pointer-size stack alignment is assumed.
 | ||||
|   uint32_t alignment = sizeof(intptr_t); | ||||
| 
 | ||||
|   // ARM & ARM64
 | ||||
|   // -----------
 | ||||
|   //
 | ||||
|   //   - 32-bit ARM requires stack to be aligned to 8 bytes.
 | ||||
|   //   - 64-bit ARM requires stack to be aligned to 16 bytes.
 | ||||
| #if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64 | ||||
|   alignment = ASMJIT_ARCH_ARM32 ? 8 : 16; | ||||
| #endif | ||||
| 
 | ||||
|   // X86 & X64
 | ||||
|   // ---------
 | ||||
|   //
 | ||||
|   //   - 32-bit X86 requires stack to be aligned to 4 bytes. Modern Linux, APPLE
 | ||||
|   //     and UNIX guarantees 16-byte stack alignment even in 32-bit, but I'm
 | ||||
|   //     not sure about all other UNIX operating systems, because 16-byte alignment
 | ||||
|   //     is addition to an older specification.
 | ||||
|   //   - 64-bit X86 requires stack to be aligned to 16 bytes.
 | ||||
| #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 | ||||
|   int modernOS = ASMJIT_OS_LINUX  || // Linux & ANDROID.
 | ||||
|                  ASMJIT_OS_MAC    || // OSX and iOS.
 | ||||
|                  ASMJIT_OS_BSD;      // BSD variants.
 | ||||
|   alignment = ASMJIT_ARCH_X64 || modernOS ? 16 : 4; | ||||
| #endif | ||||
| 
 | ||||
|   return alignment; | ||||
| } | ||||
| 
 | ||||
| static ASMJIT_INLINE void hostFlushInstructionCache(void* p, size_t size) noexcept { | ||||
|   // Only useful on non-x86 architectures.
 | ||||
| #if !ASMJIT_ARCH_X86 && !ASMJIT_ARCH_X64 | ||||
| # if ASMJIT_OS_WINDOWS | ||||
|   // Windows has a built-in support in kernel32.dll.
 | ||||
|   ::FlushInstructionCache(_memMgr.getProcessHandle(), p, size); | ||||
| # endif // ASMJIT_OS_WINDOWS
 | ||||
| #else | ||||
|   ASMJIT_UNUSED(p); | ||||
|   ASMJIT_UNUSED(size); | ||||
| #endif // !ASMJIT_ARCH_X86 && !ASMJIT_ARCH_X64
 | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Runtime - Construction / Destruction]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Runtime::Runtime() noexcept | ||||
|   : _runtimeType(kTypeNone), | ||||
|     _allocType(kVMemAllocFreeable), | ||||
|     _cpuInfo(), | ||||
|     _stackAlignment(0), | ||||
|     _cdeclConv(kCallConvNone), | ||||
|     _stdCallConv(kCallConvNone), | ||||
|     _baseAddress(kNoBaseAddress), | ||||
|     _sizeLimit(0) { | ||||
| 
 | ||||
|   ::memset(_reserved, 0, sizeof(_reserved)); | ||||
| } | ||||
| Runtime::~Runtime() noexcept {} | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::HostRuntime - Construction / Destruction]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| HostRuntime::HostRuntime() noexcept { | ||||
|   _runtimeType = kTypeJit; | ||||
|   _cpuInfo = CpuInfo::getHost(); | ||||
| 
 | ||||
|   _stackAlignment = hostStackAlignment(); | ||||
|   _cdeclConv = kCallConvHostCDecl; | ||||
|   _stdCallConv = kCallConvHostStdCall; | ||||
| } | ||||
| HostRuntime::~HostRuntime() noexcept {} | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::HostRuntime - Interface]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void HostRuntime::flush(void* p, size_t size) noexcept { | ||||
|   hostFlushInstructionCache(p, size); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::StaticRuntime - Construction / Destruction]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| StaticRuntime::StaticRuntime(void* baseAddress, size_t sizeLimit) noexcept { | ||||
|   _sizeLimit = sizeLimit; | ||||
|   _baseAddress = static_cast<Ptr>((uintptr_t)baseAddress); | ||||
| } | ||||
| StaticRuntime::~StaticRuntime() noexcept {} | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::StaticRuntime - Interface]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error StaticRuntime::add(void** dst, Assembler* assembler) noexcept { | ||||
|   size_t codeSize = assembler->getCodeSize(); | ||||
|   size_t sizeLimit = _sizeLimit; | ||||
| 
 | ||||
|   if (codeSize == 0) { | ||||
|     *dst = nullptr; | ||||
|     return kErrorNoCodeGenerated; | ||||
|   } | ||||
| 
 | ||||
|   if (sizeLimit != 0 && sizeLimit < codeSize) { | ||||
|     *dst = nullptr; | ||||
|     return kErrorCodeTooLarge; | ||||
|   } | ||||
| 
 | ||||
|   Ptr baseAddress = _baseAddress; | ||||
|   uint8_t* p = static_cast<uint8_t*>((void*)static_cast<uintptr_t>(baseAddress)); | ||||
| 
 | ||||
|   // Since the base address is known the `relocSize` returned should be equal
 | ||||
|   // to `codeSize`. It's better to fail if they don't match instead of passsing
 | ||||
|   // silently.
 | ||||
|   size_t relocSize = assembler->relocCode(p, baseAddress); | ||||
|   if (relocSize == 0 || codeSize != relocSize) { | ||||
|     *dst = nullptr; | ||||
|     return kErrorInvalidState; | ||||
|   } | ||||
| 
 | ||||
|   _baseAddress += codeSize; | ||||
|   if (sizeLimit) | ||||
|     sizeLimit -= codeSize; | ||||
| 
 | ||||
|   flush(p, codeSize); | ||||
|   *dst = p; | ||||
| 
 | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| Error StaticRuntime::release(void* p) noexcept { | ||||
|   // There is nothing to release as `StaticRuntime` doesn't manage any memory.
 | ||||
|   ASMJIT_UNUSED(p); | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::JitRuntime - Construction / Destruction]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| JitRuntime::JitRuntime() noexcept {} | ||||
| JitRuntime::~JitRuntime() noexcept {} | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::JitRuntime - Interface]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error JitRuntime::add(void** dst, Assembler* assembler) noexcept { | ||||
|   size_t codeSize = assembler->getCodeSize(); | ||||
|   if (codeSize == 0) { | ||||
|     *dst = nullptr; | ||||
|     return kErrorNoCodeGenerated; | ||||
|   } | ||||
| 
 | ||||
|   void* p = _memMgr.alloc(codeSize, getAllocType()); | ||||
|   if (p == nullptr) { | ||||
|     *dst = nullptr; | ||||
|     return kErrorNoVirtualMemory; | ||||
|   } | ||||
| 
 | ||||
|   // Relocate the code and release the unused memory back to `VMemMgr`.
 | ||||
|   size_t relocSize = assembler->relocCode(p); | ||||
|   if (relocSize == 0) { | ||||
|     *dst = nullptr; | ||||
|     _memMgr.release(p); | ||||
|     return kErrorInvalidState; | ||||
|   } | ||||
| 
 | ||||
|   if (relocSize < codeSize) | ||||
|     _memMgr.shrink(p, relocSize); | ||||
| 
 | ||||
|   flush(p, relocSize); | ||||
|   *dst = p; | ||||
| 
 | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| Error JitRuntime::release(void* p) noexcept { | ||||
|   return _memMgr.release(p); | ||||
| } | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
							
								
								
									
										266
									
								
								DynamicHooks/thirdparty/AsmJit/base/runtime.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								DynamicHooks/thirdparty/AsmJit/base/runtime.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,266 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_BASE_RUNTIME_H | ||||
| #define _ASMJIT_BASE_RUNTIME_H | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/cpuinfo.h" | ||||
| #include "../base/vmem.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [Forward Declarations]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| class Assembler; | ||||
| class CpuInfo; | ||||
| 
 | ||||
| //! \addtogroup asmjit_base
 | ||||
| //! \{
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Runtime]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Base runtime.
 | ||||
| class ASMJIT_VIRTAPI Runtime { | ||||
|  public: | ||||
|   ASMJIT_NO_COPY(Runtime) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [asmjit::RuntimeType]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_ENUM(Type) { | ||||
|     kTypeNone = 0, | ||||
|     kTypeJit = 1, | ||||
|     kTypeRemote = 2 | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Create a `Runtime` instance.
 | ||||
|   ASMJIT_API Runtime() noexcept; | ||||
|   //! Destroy the `Runtime` instance.
 | ||||
|   ASMJIT_API virtual ~Runtime() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get the runtime type, see \ref Type.
 | ||||
|   ASMJIT_INLINE uint32_t getRuntimeType() const noexcept { return _runtimeType; } | ||||
| 
 | ||||
|   //! Get stack alignment of the target.
 | ||||
|   ASMJIT_INLINE uint32_t getStackAlignment() const noexcept { return _stackAlignment; } | ||||
| 
 | ||||
|   //! Get the CDECL calling convention conforming to the runtime's ABI.
 | ||||
|   //!
 | ||||
|   //! NOTE: This is a default calling convention used by the runtime's target.
 | ||||
|   ASMJIT_INLINE uint32_t getCdeclConv() const noexcept { return _cdeclConv; } | ||||
|   //! Get the STDCALL calling convention conforming to the runtime's ABI.
 | ||||
|   //!
 | ||||
|   //! NOTE: STDCALL calling convention is only used by 32-bit x86 target. On
 | ||||
|   //! all other targets it's mapped to CDECL and calling `getStdcallConv()` will
 | ||||
|   //! return the same as `getCdeclConv()`.
 | ||||
|   ASMJIT_INLINE uint32_t getStdCallConv() const noexcept { return _stdCallConv; } | ||||
| 
 | ||||
|   //! Get CPU information.
 | ||||
|   ASMJIT_INLINE const CpuInfo& getCpuInfo() const noexcept { return _cpuInfo; } | ||||
|   //! Set CPU information.
 | ||||
|   ASMJIT_INLINE void setCpuInfo(const CpuInfo& ci) noexcept { _cpuInfo = ci; } | ||||
| 
 | ||||
|   //! Get whether the runtime has a base address.
 | ||||
|   ASMJIT_INLINE bool hasBaseAddress() const noexcept { return _baseAddress != kNoBaseAddress; } | ||||
|   //! Get the base address.
 | ||||
|   ASMJIT_INLINE Ptr getBaseAddress() const noexcept { return _baseAddress; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Interface]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Allocate a memory needed for a code generated by `assembler` and
 | ||||
|   //! relocate it to the target location.
 | ||||
|   //!
 | ||||
|   //! The beginning of the memory allocated for the function is returned in
 | ||||
|   //! `dst`. Returns Status code as \ref ErrorCode, on failure `dst` is set to
 | ||||
|   //! `nullptr`.
 | ||||
|   virtual Error add(void** dst, Assembler* assembler) noexcept = 0; | ||||
| 
 | ||||
|   //! Release memory allocated by `add`.
 | ||||
|   virtual Error release(void* p) noexcept = 0; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Type of the runtime.
 | ||||
|   uint8_t _runtimeType; | ||||
|   //! Type of the allocation.
 | ||||
|   uint8_t _allocType; | ||||
| 
 | ||||
|   //! Runtime's stack alignment.
 | ||||
|   uint8_t _stackAlignment; | ||||
|   //! CDECL calling convention conforming to runtime ABI.
 | ||||
|   uint8_t _cdeclConv; | ||||
|   //! STDCALL calling convention conforming to runtime ABI.
 | ||||
|   uint8_t _stdCallConv; | ||||
|   //! \internal
 | ||||
|   uint8_t _reserved[3]; | ||||
| 
 | ||||
|   //! Runtime CPU information.
 | ||||
|   CpuInfo _cpuInfo; | ||||
| 
 | ||||
|   //! Base address (-1 means no base address).
 | ||||
|   Ptr _baseAddress; | ||||
|   //! Maximum size of the code that can be added to the runtime (0=unlimited).
 | ||||
|   size_t _sizeLimit; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::HostRuntime]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Base runtime for JIT code generation.
 | ||||
| class ASMJIT_VIRTAPI HostRuntime : public Runtime { | ||||
|  public: | ||||
|   ASMJIT_NO_COPY(HostRuntime) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Create a `HostRuntime` instance.
 | ||||
|   ASMJIT_API HostRuntime() noexcept; | ||||
|   //! Destroy the `HostRuntime` instance.
 | ||||
|   ASMJIT_API virtual ~HostRuntime() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Interface]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Flush an instruction cache.
 | ||||
|   //!
 | ||||
|   //! This member function is called after the code has been copied to the
 | ||||
|   //! destination buffer. It is only useful for JIT code generation as it
 | ||||
|   //! causes a flush of the processor cache.
 | ||||
|   //!
 | ||||
|   //! Flushing is basically a NOP under X86/X64, but is needed by architectures
 | ||||
|   //! that do not have a transparent instruction cache.
 | ||||
|   //!
 | ||||
|   //! This function can also be overridden to improve compatibility with tools
 | ||||
|   //! such as Valgrind, however, it's not an official part of AsmJit.
 | ||||
|   ASMJIT_API virtual void flush(void* p, size_t size) noexcept; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::StaticRuntime]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! JIT static runtime.
 | ||||
| //!
 | ||||
| //! JIT static runtime can be used to generate code to a memory location that
 | ||||
| //! is known.
 | ||||
| class ASMJIT_VIRTAPI StaticRuntime : public HostRuntime { | ||||
|  public: | ||||
|   ASMJIT_NO_COPY(StaticRuntime) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Create a `StaticRuntime` instance.
 | ||||
|   //!
 | ||||
|   //! The `address` specifies a fixed target address, which will be used as a
 | ||||
|   //! base address for relocation, and `sizeLimit` specifies the maximum size
 | ||||
|   //! of a code that can be copied to it. If there is no limit `sizeLimit`
 | ||||
|   //! should be zero.
 | ||||
|   ASMJIT_API StaticRuntime(void* baseAddress, size_t sizeLimit = 0) noexcept; | ||||
|   //! Destroy the `StaticRuntime` instance.
 | ||||
|   ASMJIT_API virtual ~StaticRuntime() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get the base address.
 | ||||
|   ASMJIT_INLINE Ptr getBaseAddress() const noexcept { return _baseAddress; } | ||||
| 
 | ||||
|   //! Get the maximum size of the code that can be relocated/stored in the target.
 | ||||
|   //!
 | ||||
|   //! Returns zero if unlimited.
 | ||||
|   ASMJIT_INLINE size_t getSizeLimit() const noexcept { return _sizeLimit; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Interface]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_API virtual Error add(void** dst, Assembler* assembler) noexcept; | ||||
|   ASMJIT_API virtual Error release(void* p) noexcept; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::JitRuntime]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! JIT runtime.
 | ||||
| class ASMJIT_VIRTAPI JitRuntime : public HostRuntime { | ||||
|  public: | ||||
|   ASMJIT_NO_COPY(JitRuntime) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Create a `JitRuntime` instance.
 | ||||
|   ASMJIT_API JitRuntime() noexcept; | ||||
|   //! Destroy the `JitRuntime` instance.
 | ||||
|   ASMJIT_API virtual ~JitRuntime() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get the type of allocation.
 | ||||
|   ASMJIT_INLINE uint32_t getAllocType() const noexcept { return _allocType; } | ||||
|   //! Set the type of allocation.
 | ||||
|   ASMJIT_INLINE void setAllocType(uint32_t allocType) noexcept { _allocType = allocType; } | ||||
| 
 | ||||
|   //! Get the virtual memory manager.
 | ||||
|   ASMJIT_INLINE VMemMgr* getMemMgr() const noexcept { return const_cast<VMemMgr*>(&_memMgr); } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Interface]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_API virtual Error add(void** dst, Assembler* assembler) noexcept; | ||||
|   ASMJIT_API virtual Error release(void* p) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Virtual memory manager.
 | ||||
|   VMemMgr _memMgr; | ||||
| }; | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_BASE_RUNTIME_H
 | ||||
							
								
								
									
										289
									
								
								DynamicHooks/thirdparty/AsmJit/base/utils.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								DynamicHooks/thirdparty/AsmJit/base/utils.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,289 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/utils.h" | ||||
| 
 | ||||
| #if ASMJIT_OS_POSIX | ||||
| # include <time.h> | ||||
| # include <unistd.h> | ||||
| #endif // ASMJIT_OS_POSIX
 | ||||
| 
 | ||||
| #if ASMJIT_OS_MAC | ||||
| # include <mach/mach_time.h> | ||||
| #endif // ASMJIT_OS_MAC
 | ||||
| 
 | ||||
| #if ASMJIT_OS_WINDOWS | ||||
| # if defined(_MSC_VER) && _MSC_VER >= 1400 | ||||
| #  include <intrin.h> | ||||
| # else | ||||
| #  define _InterlockedCompareExchange InterlockedCompareExchange | ||||
| # endif // _MSC_VER
 | ||||
| #endif // ASMJIT_OS_WINDOWS
 | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::CpuTicks - Windows]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #if ASMJIT_OS_WINDOWS | ||||
| static volatile uint32_t Utils_hiResTicks; | ||||
| static volatile double Utils_hiResFreq; | ||||
| 
 | ||||
| uint32_t Utils::getTickCount() noexcept { | ||||
|   do { | ||||
|     uint32_t hiResOk = Utils_hiResTicks; | ||||
| 
 | ||||
|     if (hiResOk == 1) { | ||||
|       LARGE_INTEGER now; | ||||
|       if (!::QueryPerformanceCounter(&now)) | ||||
|         break; | ||||
|       return (int64_t)(double(now.QuadPart) / Utils_hiResFreq); | ||||
|     } | ||||
| 
 | ||||
|     if (hiResOk == 0) { | ||||
|       LARGE_INTEGER qpf; | ||||
|       if (!::QueryPerformanceFrequency(&qpf)) { | ||||
|         _InterlockedCompareExchange((LONG*)&Utils_hiResTicks, 0xFFFFFFFF, 0); | ||||
|         break; | ||||
|       } | ||||
| 
 | ||||
|       LARGE_INTEGER now; | ||||
|       if (!::QueryPerformanceCounter(&now)) { | ||||
|         _InterlockedCompareExchange((LONG*)&Utils_hiResTicks, 0xFFFFFFFF, 0); | ||||
|         break; | ||||
|       } | ||||
| 
 | ||||
|       double freqDouble = double(qpf.QuadPart) / 1000.0; | ||||
|       Utils_hiResFreq = freqDouble; | ||||
|       _InterlockedCompareExchange((LONG*)&Utils_hiResTicks, 1, 0); | ||||
| 
 | ||||
|       return static_cast<uint32_t>( | ||||
|         static_cast<int64_t>(double(now.QuadPart) / freqDouble) & 0xFFFFFFFF); | ||||
|     } | ||||
|   } while (0); | ||||
| 
 | ||||
|   // Bail to a less precise GetTickCount().
 | ||||
|   return ::GetTickCount(); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::CpuTicks - Mac]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #elif ASMJIT_OS_MAC | ||||
| static mach_timebase_info_data_t CpuTicks_machTime; | ||||
| 
 | ||||
| uint32_t Utils::getTickCount() noexcept { | ||||
|   // Initialize the first time CpuTicks::now() is called (See Apple's QA1398).
 | ||||
|   if (CpuTicks_machTime.denom == 0) { | ||||
|     if (mach_timebase_info(&CpuTicks_machTime) != KERN_SUCCESS) | ||||
|       return 0; | ||||
|   } | ||||
| 
 | ||||
|   // mach_absolute_time() returns nanoseconds, we need just milliseconds.
 | ||||
|   uint64_t t = mach_absolute_time() / 1000000; | ||||
| 
 | ||||
|   t = t * CpuTicks_machTime.numer / CpuTicks_machTime.denom; | ||||
|   return static_cast<uint32_t>(t & 0xFFFFFFFFU); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::CpuTicks - Posix]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #else | ||||
| uint32_t Utils::getTickCount() noexcept { | ||||
| #if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0 | ||||
|   struct timespec ts; | ||||
| 
 | ||||
|   if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) | ||||
|     return 0; | ||||
| 
 | ||||
|   uint64_t t = (uint64_t(ts.tv_sec ) * 1000) + (uint64_t(ts.tv_nsec) / 1000000); | ||||
|   return static_cast<uint32_t>(t & 0xFFFFFFFFU); | ||||
| #else  // _POSIX_MONOTONIC_CLOCK
 | ||||
| #error "[asmjit] Utils::getTickCount() is not implemented for your target OS." | ||||
|   return 0; | ||||
| #endif  // _POSIX_MONOTONIC_CLOCK
 | ||||
| } | ||||
| #endif // ASMJIT_OS
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Utils - Unit]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #if defined(ASMJIT_TEST) | ||||
| UNIT(base_utils) { | ||||
|   uint32_t i; | ||||
| 
 | ||||
|   INFO("IntTraits<>."); | ||||
|   EXPECT(IntTraits<signed char>::kIsSigned,"IntTraits<signed char> should report signed."); | ||||
|   EXPECT(IntTraits<short>::kIsSigned, "IntTraits<signed short> should report signed."); | ||||
|   EXPECT(IntTraits<int>::kIsSigned, "IntTraits<int> should report signed."); | ||||
|   EXPECT(IntTraits<long>::kIsSigned, "IntTraits<long> should report signed."); | ||||
| 
 | ||||
|   EXPECT(IntTraits<unsigned char>::kIsUnsigned, "IntTraits<unsigned char> should report unsigned."); | ||||
|   EXPECT(IntTraits<unsigned short>::kIsUnsigned, "IntTraits<unsigned short> should report unsigned."); | ||||
|   EXPECT(IntTraits<unsigned int>::kIsUnsigned, "IntTraits<unsigned int> should report unsigned."); | ||||
|   EXPECT(IntTraits<unsigned long>::kIsUnsigned, "IntTraits<unsigned long> should report unsigned."); | ||||
| 
 | ||||
|   EXPECT(IntTraits<intptr_t>::kIsSigned, "IntTraits<intptr_t> should report signed."); | ||||
|   EXPECT(IntTraits<uintptr_t>::kIsUnsigned, "IntTraits<uintptr_t> should report unsigned."); | ||||
| 
 | ||||
|   EXPECT(IntTraits<intptr_t>::kIsIntPtr, "IntTraits<intptr_t> should report intptr_t type."); | ||||
|   EXPECT(IntTraits<uintptr_t>::kIsIntPtr, "IntTraits<uintptr_t> should report intptr_t type."); | ||||
| 
 | ||||
|   INFO("Utils::iMin()/iMax()."); | ||||
|   EXPECT(Utils::iMin<int>( 0, -1) == -1, "Utils::iMin<int> should return a minimum value."); | ||||
|   EXPECT(Utils::iMin<int>(-1, -2) == -2, "Utils::iMin<int> should return a minimum value."); | ||||
|   EXPECT(Utils::iMin<int>( 1,  2) ==  1, "Utils::iMin<int> should return a minimum value."); | ||||
| 
 | ||||
|   EXPECT(Utils::iMax<int>( 0, -1) ==  0, "Utils::iMax<int> should return a maximum value."); | ||||
|   EXPECT(Utils::iMax<int>(-1, -2) == -1, "Utils::iMax<int> should return a maximum value."); | ||||
|   EXPECT(Utils::iMax<int>( 1,  2) ==  2, "Utils::iMax<int> should return a maximum value."); | ||||
| 
 | ||||
|   INFO("Utils::inInterval()."); | ||||
|   EXPECT(Utils::inInterval<int>(11 , 10, 20) == true , "Utils::inInterval<int> should return true if inside."); | ||||
|   EXPECT(Utils::inInterval<int>(101, 10, 20) == false, "Utils::inInterval<int> should return false if outside."); | ||||
| 
 | ||||
|   INFO("Utils::isInt8()."); | ||||
|   EXPECT(Utils::isInt8(-128) == true , "Utils::isInt8<> should return true if inside."); | ||||
|   EXPECT(Utils::isInt8( 127) == true , "Utils::isInt8<> should return true if inside."); | ||||
|   EXPECT(Utils::isInt8(-129) == false, "Utils::isInt8<> should return false if outside."); | ||||
|   EXPECT(Utils::isInt8( 128) == false, "Utils::isInt8<> should return false if outside."); | ||||
| 
 | ||||
|   INFO("Utils::isInt16()."); | ||||
|   EXPECT(Utils::isInt16(-32768) == true , "Utils::isInt16<> should return true if inside."); | ||||
|   EXPECT(Utils::isInt16( 32767) == true , "Utils::isInt16<> should return true if inside."); | ||||
|   EXPECT(Utils::isInt16(-32769) == false, "Utils::isInt16<> should return false if outside."); | ||||
|   EXPECT(Utils::isInt16( 32768) == false, "Utils::isInt16<> should return false if outside."); | ||||
| 
 | ||||
|   INFO("Utils::isInt32()."); | ||||
|   EXPECT(Utils::isInt32( 2147483647    ) == true, "Utils::isInt32<int> should return true if inside."); | ||||
|   EXPECT(Utils::isInt32(-2147483647 - 1) == true, "Utils::isInt32<int> should return true if inside."); | ||||
|   EXPECT(Utils::isInt32(ASMJIT_UINT64_C(2147483648)) == false, "Utils::isInt32<int> should return false if outside."); | ||||
|   EXPECT(Utils::isInt32(ASMJIT_UINT64_C(0xFFFFFFFF)) == false, "Utils::isInt32<int> should return false if outside."); | ||||
|   EXPECT(Utils::isInt32(ASMJIT_UINT64_C(0xFFFFFFFF) + 1) == false, "Utils::isInt32<int> should return false if outside."); | ||||
| 
 | ||||
|   INFO("Utils::isUInt8()."); | ||||
|   EXPECT(Utils::isUInt8(0)   == true , "Utils::isUInt8<> should return true if inside."); | ||||
|   EXPECT(Utils::isUInt8(255) == true , "Utils::isUInt8<> should return true if inside."); | ||||
|   EXPECT(Utils::isUInt8(256) == false, "Utils::isUInt8<> should return false if outside."); | ||||
|   EXPECT(Utils::isUInt8(-1)  == false, "Utils::isUInt8<> should return false if negative."); | ||||
| 
 | ||||
|   INFO("Utils::isUInt12()."); | ||||
|   EXPECT(Utils::isUInt12(0)    == true , "Utils::isUInt12<> should return true if inside."); | ||||
|   EXPECT(Utils::isUInt12(4095) == true , "Utils::isUInt12<> should return true if inside."); | ||||
|   EXPECT(Utils::isUInt12(4096) == false, "Utils::isUInt12<> should return false if outside."); | ||||
|   EXPECT(Utils::isUInt12(-1)   == false, "Utils::isUInt12<> should return false if negative."); | ||||
| 
 | ||||
|   INFO("Utils::isUInt16()."); | ||||
|   EXPECT(Utils::isUInt16(0)     == true , "Utils::isUInt16<> should return true if inside."); | ||||
|   EXPECT(Utils::isUInt16(65535) == true , "Utils::isUInt16<> should return true if inside."); | ||||
|   EXPECT(Utils::isUInt16(65536) == false, "Utils::isUInt16<> should return false if outside."); | ||||
|   EXPECT(Utils::isUInt16(-1)    == false, "Utils::isUInt16<> should return false if negative."); | ||||
| 
 | ||||
|   INFO("Utils::isUInt32()."); | ||||
|   EXPECT(Utils::isUInt32(ASMJIT_UINT64_C(0xFFFFFFFF)) == true, "Utils::isUInt32<uint64_t> should return true if inside."); | ||||
|   EXPECT(Utils::isUInt32(ASMJIT_UINT64_C(0xFFFFFFFF) + 1) == false, "Utils::isUInt32<uint64_t> should return false if outside."); | ||||
|   EXPECT(Utils::isUInt32(-1) == false, "Utils::isUInt32<int> should return false if negative."); | ||||
| 
 | ||||
|   INFO("Utils::isPower2()."); | ||||
|   for (i = 0; i < 64; i++) { | ||||
|     EXPECT(Utils::isPowerOf2(static_cast<uint64_t>(1) << i) == true, | ||||
|       "Utils::isPower2() didn't report power of 2."); | ||||
|     EXPECT(Utils::isPowerOf2((static_cast<uint64_t>(1) << i) ^ 0x001101) == false, | ||||
|       "Utils::isPower2() didn't report not power of 2."); | ||||
|   } | ||||
| 
 | ||||
|   INFO("Utils::mask()."); | ||||
|   for (i = 0; i < 32; i++) { | ||||
|     EXPECT(Utils::mask(i) == (1 << i), | ||||
|       "Utils::mask(%u) should return %X.", i, (1 << i)); | ||||
|   } | ||||
| 
 | ||||
|   INFO("Utils::bits()."); | ||||
|   for (i = 0; i < 32; i++) { | ||||
|     uint32_t expectedBits = 0; | ||||
| 
 | ||||
|     for (uint32_t b = 0; b < i; b++) | ||||
|       expectedBits |= static_cast<uint32_t>(1) << b; | ||||
| 
 | ||||
|     EXPECT(Utils::bits(i) == expectedBits, | ||||
|       "Utils::bits(%u) should return %X.", i, expectedBits); | ||||
|   } | ||||
| 
 | ||||
|   INFO("Utils::hasBit()."); | ||||
|   for (i = 0; i < 32; i++) { | ||||
|     EXPECT(Utils::hasBit((1 << i), i) == true, | ||||
|       "Utils::hasBit(%X, %u) should return true.", (1 << i), i); | ||||
|   } | ||||
| 
 | ||||
|   INFO("Utils::bitCount()."); | ||||
|   for (i = 0; i < 32; i++) { | ||||
|     EXPECT(Utils::bitCount((1 << i)) == 1, | ||||
|       "Utils::bitCount(%X) should return true.", (1 << i)); | ||||
|   } | ||||
|   EXPECT(Utils::bitCount(0x000000F0) ==  4, ""); | ||||
|   EXPECT(Utils::bitCount(0x10101010) ==  4, ""); | ||||
|   EXPECT(Utils::bitCount(0xFF000000) ==  8, ""); | ||||
|   EXPECT(Utils::bitCount(0xFFFFFFF7) == 31, ""); | ||||
|   EXPECT(Utils::bitCount(0x7FFFFFFF) == 31, ""); | ||||
| 
 | ||||
|   INFO("Utils::findFirstBit()."); | ||||
|   for (i = 0; i < 32; i++) { | ||||
|     EXPECT(Utils::findFirstBit((1 << i)) == i, | ||||
|       "Utils::findFirstBit(%X) should return %u.", (1 << i), i); | ||||
|   } | ||||
| 
 | ||||
|   INFO("Utils::keepNOnesFromRight()."); | ||||
|   EXPECT(Utils::keepNOnesFromRight(0xF, 1) == 0x1, ""); | ||||
|   EXPECT(Utils::keepNOnesFromRight(0xF, 2) == 0x3, ""); | ||||
|   EXPECT(Utils::keepNOnesFromRight(0xF, 3) == 0x7, ""); | ||||
|   EXPECT(Utils::keepNOnesFromRight(0x5, 2) == 0x5, ""); | ||||
|   EXPECT(Utils::keepNOnesFromRight(0xD, 2) == 0x5, ""); | ||||
| 
 | ||||
|   INFO("Utils::isAligned()."); | ||||
|   EXPECT(Utils::isAligned<size_t>(0xFFFF,  4) == false, ""); | ||||
|   EXPECT(Utils::isAligned<size_t>(0xFFF4,  4) == true , ""); | ||||
|   EXPECT(Utils::isAligned<size_t>(0xFFF8,  8) == true , ""); | ||||
|   EXPECT(Utils::isAligned<size_t>(0xFFF0, 16) == true , ""); | ||||
| 
 | ||||
|   INFO("Utils::alignTo()."); | ||||
|   EXPECT(Utils::alignTo<size_t>(0xFFFF,  4) == 0x10000, ""); | ||||
|   EXPECT(Utils::alignTo<size_t>(0xFFF4,  4) == 0x0FFF4, ""); | ||||
|   EXPECT(Utils::alignTo<size_t>(0xFFF8,  8) == 0x0FFF8, ""); | ||||
|   EXPECT(Utils::alignTo<size_t>(0xFFF0, 16) == 0x0FFF0, ""); | ||||
|   EXPECT(Utils::alignTo<size_t>(0xFFF0, 32) == 0x10000, ""); | ||||
| 
 | ||||
|   INFO("Utils::alignToPowerOf2()."); | ||||
|   EXPECT(Utils::alignToPowerOf2<size_t>(0xFFFF) == 0x10000, ""); | ||||
|   EXPECT(Utils::alignToPowerOf2<size_t>(0xF123) == 0x10000, ""); | ||||
|   EXPECT(Utils::alignToPowerOf2<size_t>(0x0F00) == 0x01000, ""); | ||||
|   EXPECT(Utils::alignToPowerOf2<size_t>(0x0100) == 0x00100, ""); | ||||
|   EXPECT(Utils::alignToPowerOf2<size_t>(0x1001) == 0x02000, ""); | ||||
| 
 | ||||
|   INFO("Utils::alignDiff()."); | ||||
|   EXPECT(Utils::alignDiff<size_t>(0xFFFF,  4) ==  1, ""); | ||||
|   EXPECT(Utils::alignDiff<size_t>(0xFFF4,  4) ==  0, ""); | ||||
|   EXPECT(Utils::alignDiff<size_t>(0xFFF8,  8) ==  0, ""); | ||||
|   EXPECT(Utils::alignDiff<size_t>(0xFFF0, 16) ==  0, ""); | ||||
|   EXPECT(Utils::alignDiff<size_t>(0xFFF0, 32) == 16, ""); | ||||
| } | ||||
| #endif // ASMJIT_TEST
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
							
								
								
									
										1348
									
								
								DynamicHooks/thirdparty/AsmJit/base/utils.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1348
									
								
								DynamicHooks/thirdparty/AsmJit/base/utils.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1075
									
								
								DynamicHooks/thirdparty/AsmJit/base/vectypes.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1075
									
								
								DynamicHooks/thirdparty/AsmJit/base/vectypes.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1282
									
								
								DynamicHooks/thirdparty/AsmJit/base/vmem.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1282
									
								
								DynamicHooks/thirdparty/AsmJit/base/vmem.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										233
									
								
								DynamicHooks/thirdparty/AsmJit/base/vmem.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								DynamicHooks/thirdparty/AsmJit/base/vmem.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,233 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_BASE_VMEM_H | ||||
| #define _ASMJIT_BASE_VMEM_H | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/utils.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| //! \addtogroup asmjit_base
 | ||||
| //! \{
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::VMemAllocType]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Type of virtual memory allocation, see `VMemMgr::alloc()`.
 | ||||
| ASMJIT_ENUM(VMemAllocType) { | ||||
|   //! Normal memory allocation, has to be freed by `VMemMgr::release()`.
 | ||||
|   kVMemAllocFreeable = 0, | ||||
|   //! Allocate permanent memory, can't be freed.
 | ||||
|   kVMemAllocPermanent = 1 | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::VMemFlags]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Type of virtual memory allocation, see `VMemMgr::alloc()`.
 | ||||
| ASMJIT_ENUM(VMemFlags) { | ||||
|   //! Memory is writable.
 | ||||
|   kVMemFlagWritable = 0x00000001, | ||||
|   //! Memory is executable.
 | ||||
|   kVMemFlagExecutable = 0x00000002 | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::VMemUtil]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Virtual memory utilities.
 | ||||
| //!
 | ||||
| //! Defines functions that provide facility to allocate and free memory that is
 | ||||
| //! executable in a platform independent manner. If both the processor and host
 | ||||
| //! operating system support data-execution-prevention then the only way how to
 | ||||
| //! run machine code is to allocate it to a memory that has marked as executable.
 | ||||
| //! VMemUtil is just unified interface to platform dependent APIs.
 | ||||
| //!
 | ||||
| //! `VirtualAlloc()` function is used on Windows operating system and `mmap()`
 | ||||
| //! on POSIX. `VirtualAlloc()` and `mmap()` documentation provide a detailed
 | ||||
| //! overview on how to use a platform specific APIs.
 | ||||
| struct VMemUtil { | ||||
|   //! Get a size/alignment of a single virtual memory page.
 | ||||
|   static ASMJIT_API size_t getPageSize() noexcept; | ||||
| 
 | ||||
|   //! Get a recommended granularity for a single `alloc` call.
 | ||||
|   static ASMJIT_API size_t getPageGranularity() noexcept; | ||||
| 
 | ||||
|   //! Allocate virtual memory.
 | ||||
|   //!
 | ||||
|   //! Pages are readable/writeable, but they are not guaranteed to be
 | ||||
|   //! executable unless 'canExecute' is true. Returns the address of
 | ||||
|   //! allocated memory, or `nullptr` on failure.
 | ||||
|   static ASMJIT_API void* alloc(size_t length, size_t* allocated, uint32_t flags) noexcept; | ||||
|   //! Free memory allocated by `alloc()`.
 | ||||
|   static ASMJIT_API Error release(void* addr, size_t length) noexcept; | ||||
| 
 | ||||
| #if ASMJIT_OS_WINDOWS | ||||
|   //! Allocate virtual memory of `hProcess` (Windows only).
 | ||||
|   static ASMJIT_API void* allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, uint32_t flags) noexcept; | ||||
| 
 | ||||
|   //! Release virtual memory of `hProcess` (Windows only).
 | ||||
|   static ASMJIT_API Error releaseProcessMemory(HANDLE hProcess, void* addr, size_t length) noexcept; | ||||
| #endif // ASMJIT_OS_WINDOWS
 | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::VMemMgr]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Reference implementation of memory manager that uses `VMemUtil` to allocate
 | ||||
| //! chunks of virtual memory and bit arrays to manage it.
 | ||||
| class VMemMgr { | ||||
|  public: | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
| #if !ASMJIT_OS_WINDOWS | ||||
|   //! Create a `VMemMgr` instance.
 | ||||
|   ASMJIT_API VMemMgr() noexcept; | ||||
| #else | ||||
|   //! Create a `VMemMgr` instance.
 | ||||
|   //!
 | ||||
|   //! NOTE: When running on Windows it's possible to specify a `hProcess` to
 | ||||
|   //! be used for memory allocation. Using `hProcess` allows to allocate memory
 | ||||
|   //! of a remote process.
 | ||||
|   ASMJIT_API VMemMgr(HANDLE hProcess = static_cast<HANDLE>(0)) noexcept; | ||||
| #endif // ASMJIT_OS_WINDOWS
 | ||||
| 
 | ||||
|   //! Destroy the `VMemMgr` instance and free all blocks.
 | ||||
|   ASMJIT_API ~VMemMgr() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Reset]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Free all allocated memory.
 | ||||
|   ASMJIT_API void reset() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
| #if ASMJIT_OS_WINDOWS | ||||
|   //! Get the handle of the process memory manager is bound to.
 | ||||
|   ASMJIT_INLINE HANDLE getProcessHandle() const noexcept { | ||||
|     return _hProcess; | ||||
|   } | ||||
| #endif // ASMJIT_OS_WINDOWS
 | ||||
| 
 | ||||
|   //! Get how many bytes are currently allocated.
 | ||||
|   ASMJIT_INLINE size_t getAllocatedBytes() const noexcept { | ||||
|     return _allocatedBytes; | ||||
|   } | ||||
| 
 | ||||
|   //! Get how many bytes are currently used.
 | ||||
|   ASMJIT_INLINE size_t getUsedBytes() const noexcept { | ||||
|     return _usedBytes; | ||||
|   } | ||||
| 
 | ||||
|   //! Get whether to keep allocated memory after the `VMemMgr` is destroyed.
 | ||||
|   //!
 | ||||
|   //! \sa \ref setKeepVirtualMemory.
 | ||||
|   ASMJIT_INLINE bool getKeepVirtualMemory() const noexcept { | ||||
|     return _keepVirtualMemory; | ||||
|   } | ||||
| 
 | ||||
|   //! Set whether to keep allocated memory after memory manager is
 | ||||
|   //! destroyed.
 | ||||
|   //!
 | ||||
|   //! This method is usable when patching code of remote process. You need to
 | ||||
|   //! allocate process memory, store generated assembler into it and patch the
 | ||||
|   //! method you want to redirect (into your code). This method affects only
 | ||||
|   //! VMemMgr destructor. After destruction all internal
 | ||||
|   //! structures are freed, only the process virtual memory remains.
 | ||||
|   //!
 | ||||
|   //! NOTE: Memory allocated with kVMemAllocPermanent is always kept.
 | ||||
|   //!
 | ||||
|   //! \sa \ref getKeepVirtualMemory.
 | ||||
|   ASMJIT_INLINE void setKeepVirtualMemory(bool keepVirtualMemory) noexcept { | ||||
|     _keepVirtualMemory = keepVirtualMemory; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Alloc / Release]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Allocate a `size` bytes of virtual memory.
 | ||||
|   //!
 | ||||
|   //! Note that if you are implementing your own virtual memory manager then you
 | ||||
|   //! can quitly ignore type of allocation. This is mainly for AsmJit to memory
 | ||||
|   //! manager that allocated memory will be never freed.
 | ||||
|   ASMJIT_API void* alloc(size_t size, uint32_t type = kVMemAllocFreeable) noexcept; | ||||
| 
 | ||||
|   //! Free previously allocated memory at a given `address`.
 | ||||
|   ASMJIT_API Error release(void* p) noexcept; | ||||
| 
 | ||||
|   //! Free extra memory allocated with `p`.
 | ||||
|   ASMJIT_API Error shrink(void* p, size_t used) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
| #if ASMJIT_OS_WINDOWS | ||||
|   //! Process passed to `VirtualAllocEx` and `VirtualFree`.
 | ||||
|   HANDLE _hProcess; | ||||
| #endif // ASMJIT_OS_WINDOWS
 | ||||
| 
 | ||||
|   //! Lock to enable thread-safe functionality.
 | ||||
|   Lock _lock; | ||||
| 
 | ||||
|   //! Default block size.
 | ||||
|   size_t _blockSize; | ||||
|   //! Default block density.
 | ||||
|   size_t _blockDensity; | ||||
| 
 | ||||
|   // Whether to keep virtual memory after destroy.
 | ||||
|   bool _keepVirtualMemory; | ||||
| 
 | ||||
|   //! How many bytes are currently allocated.
 | ||||
|   size_t _allocatedBytes; | ||||
|   //! How many bytes are currently used.
 | ||||
|   size_t _usedBytes; | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   //! \{
 | ||||
| 
 | ||||
|   struct RbNode; | ||||
|   struct MemNode; | ||||
|   struct PermanentNode; | ||||
| 
 | ||||
|   // Memory nodes root.
 | ||||
|   MemNode* _root; | ||||
|   // Memory nodes list.
 | ||||
|   MemNode* _first; | ||||
|   MemNode* _last; | ||||
|   MemNode* _optimal; | ||||
|   // Permanent memory.
 | ||||
|   PermanentNode* _permanent; | ||||
| 
 | ||||
|   //! \}
 | ||||
| }; | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_BASE_VMEM_H
 | ||||
							
								
								
									
										193
									
								
								DynamicHooks/thirdparty/AsmJit/base/zone.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								DynamicHooks/thirdparty/AsmJit/base/zone.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,193 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/utils.h" | ||||
| #include "../base/zone.h" | ||||
| #include <stdarg.h> | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| //! Zero size block used by `Zone` that doesn't have any memory allocated.
 | ||||
| static const Zone::Block Zone_zeroBlock = { | ||||
|   nullptr, nullptr, nullptr, nullptr, { 0 } | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Zone - Construction / Destruction]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Zone::Zone(size_t blockSize) noexcept { | ||||
|   _block = const_cast<Zone::Block*>(&Zone_zeroBlock); | ||||
|   _blockSize = blockSize; | ||||
| } | ||||
| 
 | ||||
| Zone::~Zone() noexcept { | ||||
|   reset(true); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Zone - Reset]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void Zone::reset(bool releaseMemory) noexcept { | ||||
|   Block* cur = _block; | ||||
| 
 | ||||
|   // Can't be altered.
 | ||||
|   if (cur == &Zone_zeroBlock) | ||||
|     return; | ||||
| 
 | ||||
|   if (releaseMemory) { | ||||
|     // Since cur can be in the middle of the double-linked list, we have to
 | ||||
|     // traverse to both directions `prev` and `next` separately.
 | ||||
|     Block* next = cur->next; | ||||
|     do { | ||||
|       Block* prev = cur->prev; | ||||
|       ASMJIT_FREE(cur); | ||||
|       cur = prev; | ||||
|     } while (cur != nullptr); | ||||
| 
 | ||||
|     cur = next; | ||||
|     while (cur != nullptr) { | ||||
|       next = cur->next; | ||||
|       ASMJIT_FREE(cur); | ||||
|       cur = next; | ||||
|     } | ||||
| 
 | ||||
|     _block = const_cast<Zone::Block*>(&Zone_zeroBlock); | ||||
|   } | ||||
|   else { | ||||
|     while (cur->prev != nullptr) | ||||
|       cur = cur->prev; | ||||
| 
 | ||||
|     cur->pos = cur->data; | ||||
|     _block = cur; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Zone - Alloc]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void* Zone::_alloc(size_t size) noexcept { | ||||
|   Block* curBlock = _block; | ||||
|   size_t blockSize = Utils::iMax<size_t>(_blockSize, size); | ||||
| 
 | ||||
|   // The `_alloc()` method can only be called if there is not enough space
 | ||||
|   // in the current block, see `alloc()` implementation for more details.
 | ||||
|   ASMJIT_ASSERT(curBlock == &Zone_zeroBlock || curBlock->getRemainingSize() < size); | ||||
| 
 | ||||
|   // If the `Zone` has been reset the current block doesn't have to be the
 | ||||
|   // last one. Check if there is a block that can be used instead of allocating
 | ||||
|   // a new one. If there is a `next` block it's completely unused, we don't have
 | ||||
|   // to check for remaining bytes.
 | ||||
|   Block* next = curBlock->next; | ||||
|   if (next != nullptr && next->getBlockSize() >= size) { | ||||
|     next->pos = next->data + size; | ||||
|     _block = next; | ||||
|     return static_cast<void*>(next->data); | ||||
|   } | ||||
| 
 | ||||
|   // Prevent arithmetic overflow.
 | ||||
|   if (blockSize > ~static_cast<size_t>(0) - sizeof(Block)) | ||||
|     return nullptr; | ||||
| 
 | ||||
|   Block* newBlock = static_cast<Block*>(ASMJIT_ALLOC(sizeof(Block) - sizeof(void*) + blockSize)); | ||||
|   if (newBlock == nullptr) | ||||
|     return nullptr; | ||||
| 
 | ||||
|   newBlock->pos = newBlock->data + size; | ||||
|   newBlock->end = newBlock->data + blockSize; | ||||
|   newBlock->prev = nullptr; | ||||
|   newBlock->next = nullptr; | ||||
| 
 | ||||
|   if (curBlock != &Zone_zeroBlock) { | ||||
|     newBlock->prev = curBlock; | ||||
|     curBlock->next = newBlock; | ||||
| 
 | ||||
|     // Does only happen if there is a next block, but the requested memory
 | ||||
|     // can't fit into it. In this case a new buffer is allocated and inserted
 | ||||
|     // between the current block and the next one.
 | ||||
|     if (next != nullptr) { | ||||
|       newBlock->next = next; | ||||
|       next->prev = newBlock; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   _block = newBlock; | ||||
|   return static_cast<void*>(newBlock->data); | ||||
| } | ||||
| 
 | ||||
| void* Zone::allocZeroed(size_t size) noexcept { | ||||
|   void* p = alloc(size); | ||||
|   if (p != nullptr) | ||||
|     ::memset(p, 0, size); | ||||
|   return p; | ||||
| } | ||||
| 
 | ||||
| void* Zone::dup(const void* data, size_t size) noexcept { | ||||
|   if (data == nullptr) | ||||
|     return nullptr; | ||||
| 
 | ||||
|   if (size == 0) | ||||
|     return nullptr; | ||||
| 
 | ||||
|   void* m = alloc(size); | ||||
|   if (m == nullptr) | ||||
|     return nullptr; | ||||
| 
 | ||||
|   ::memcpy(m, data, size); | ||||
|   return m; | ||||
| } | ||||
| 
 | ||||
| char* Zone::sdup(const char* str) noexcept { | ||||
|   if (str == nullptr) | ||||
|     return nullptr; | ||||
| 
 | ||||
|   size_t len = ::strlen(str); | ||||
|   if (len == 0) | ||||
|     return nullptr; | ||||
| 
 | ||||
|   // Include NULL terminator and limit string length.
 | ||||
|   if (++len > 256) | ||||
|     len = 256; | ||||
| 
 | ||||
|   char* m = static_cast<char*>(alloc(len)); | ||||
|   if (m == nullptr) | ||||
|     return nullptr; | ||||
| 
 | ||||
|   ::memcpy(m, str, len); | ||||
|   m[len - 1] = '\0'; | ||||
|   return m; | ||||
| } | ||||
| 
 | ||||
| char* Zone::sformat(const char* fmt, ...) noexcept { | ||||
|   if (fmt == nullptr) | ||||
|     return nullptr; | ||||
| 
 | ||||
|   char buf[512]; | ||||
|   size_t len; | ||||
| 
 | ||||
|   va_list ap; | ||||
|   va_start(ap, fmt); | ||||
| 
 | ||||
|   len = vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf) - 1, fmt, ap); | ||||
|   buf[len++] = 0; | ||||
| 
 | ||||
|   va_end(ap); | ||||
|   return static_cast<char*>(dup(buf, len)); | ||||
| } | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
							
								
								
									
										220
									
								
								DynamicHooks/thirdparty/AsmJit/base/zone.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								DynamicHooks/thirdparty/AsmJit/base/zone.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,220 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_BASE_ZONE_H | ||||
| #define _ASMJIT_BASE_ZONE_H | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/globals.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| //! \addtogroup asmjit_base
 | ||||
| //! \{
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Zone]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Zone memory allocator.
 | ||||
| //!
 | ||||
| //! Zone is an incremental memory allocator that allocates memory by simply
 | ||||
| //! incrementing a pointer. It allocates blocks of memory by using standard
 | ||||
| //! C library `malloc/free`, but divides these blocks into smaller segments
 | ||||
| //! requirested by calling `Zone::alloc()` and friends.
 | ||||
| //!
 | ||||
| //! Zone memory allocators are designed to allocate data of short lifetime. The
 | ||||
| //! data used by `Assembler` and `Compiler` has a very short lifetime, thus, is
 | ||||
| //! allocated by `Zone`. The advantage is that `Zone` can free all of the data
 | ||||
| //! allocated at once by calling `reset()` or by `Zone` destructor.
 | ||||
| class Zone { | ||||
|  public: | ||||
|   //! \internal
 | ||||
|   //!
 | ||||
|   //! A single block of memory.
 | ||||
|   struct Block { | ||||
|     // ------------------------------------------------------------------------
 | ||||
|     // [Accessors]
 | ||||
|     // ------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     //! Get the size of the block.
 | ||||
|     ASMJIT_INLINE size_t getBlockSize() const noexcept { | ||||
|       return (size_t)(end - data); | ||||
|     } | ||||
| 
 | ||||
|     //! Get count of remaining bytes in the block.
 | ||||
|     ASMJIT_INLINE size_t getRemainingSize() const noexcept { | ||||
|       return (size_t)(end - pos); | ||||
|     } | ||||
| 
 | ||||
|     // ------------------------------------------------------------------------
 | ||||
|     // [Members]
 | ||||
|     // ------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     //! Current data pointer (pointer to the first available byte).
 | ||||
|     uint8_t* pos; | ||||
|     //! End data pointer (pointer to the first invalid byte).
 | ||||
|     uint8_t* end; | ||||
| 
 | ||||
|     //! Link to the previous block.
 | ||||
|     Block* prev; | ||||
|     //! Link to the next block.
 | ||||
|     Block* next; | ||||
| 
 | ||||
|     //! Data.
 | ||||
|     uint8_t data[sizeof(void*)]; | ||||
|   }; | ||||
| 
 | ||||
|   enum { | ||||
|     //! Zone allocator overhead.
 | ||||
|     kZoneOverhead = | ||||
|       kMemAllocOverhead | ||||
|         + static_cast<int>(sizeof(Block) - sizeof(void*)) | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Create a new instance of `Zone` allocator.
 | ||||
|   //!
 | ||||
|   //! The `blockSize` parameter describes the default size of the block. If the
 | ||||
|   //! `size` parameter passed to `alloc()` is greater than the default size
 | ||||
|   //! `Zone` will allocate and use a larger block, but it will not change the
 | ||||
|   //! default `blockSize`.
 | ||||
|   //!
 | ||||
|   //! It's not required, but it's good practice to set `blockSize` to a
 | ||||
|   //! reasonable value that depends on the usage of `Zone`. Greater block sizes
 | ||||
|   //! are generally safer and performs better than unreasonably low values.
 | ||||
|   ASMJIT_API Zone(size_t blockSize) noexcept; | ||||
| 
 | ||||
|   //! Destroy the `Zone` instance.
 | ||||
|   //!
 | ||||
|   //! This will destroy the `Zone` instance and release all blocks of memory
 | ||||
|   //! allocated by it. It performs implicit `reset(true)`.
 | ||||
|   ASMJIT_API ~Zone() noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Reset]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Reset the `Zone` invalidating all blocks allocated.
 | ||||
|   //!
 | ||||
|   //! If `releaseMemory` is true all buffers will be released to the system.
 | ||||
|   ASMJIT_API void reset(bool releaseMemory = false) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get the default block size.
 | ||||
|   ASMJIT_INLINE size_t getBlockSize() const noexcept { | ||||
|     return _blockSize; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Alloc]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Allocate `size` bytes of memory.
 | ||||
|   //!
 | ||||
|   //! Pointer returned is valid until the `Zone` instance is destroyed or reset
 | ||||
|   //! by calling `reset()`. If you plan to make an instance of C++ from the
 | ||||
|   //! given pointer use placement `new` and `delete` operators:
 | ||||
|   //!
 | ||||
|   //! ~~~
 | ||||
|   //! using namespace asmjit;
 | ||||
|   //!
 | ||||
|   //! class Object { ... };
 | ||||
|   //!
 | ||||
|   //! // Create Zone with default block size of approximately 65536 bytes.
 | ||||
|   //! Zone zone(65536 - Zone::kZoneOverhead);
 | ||||
|   //!
 | ||||
|   //! // Create your objects using zone object allocating, for example:
 | ||||
|   //! Object* obj = static_cast<Object*>( zone.alloc(sizeof(Object)) );
 | ||||
|   //
 | ||||
|   //! if (obj == nullptr) {
 | ||||
|   //!   // Handle out of memory error.
 | ||||
|   //! }
 | ||||
|   //!
 | ||||
|   //! // Placement `new` and `delete` operators can be used to instantiate it.
 | ||||
|   //! new(obj) Object();
 | ||||
|   //!
 | ||||
|   //! // ... lifetime of your objects ...
 | ||||
|   //!
 | ||||
|   //! // To destroy the instance (if required).
 | ||||
|   //! obj->~Object();
 | ||||
|   //!
 | ||||
|   //! // Reset or destroy `Zone`.
 | ||||
|   //! zone.reset();
 | ||||
|   //! ~~~
 | ||||
|   ASMJIT_INLINE void* alloc(size_t size) noexcept { | ||||
|     Block* cur = _block; | ||||
| 
 | ||||
|     uint8_t* ptr = cur->pos; | ||||
|     size_t remainingBytes = (size_t)(cur->end - ptr); | ||||
| 
 | ||||
|     if (remainingBytes < size) | ||||
|       return _alloc(size); | ||||
| 
 | ||||
|     cur->pos += size; | ||||
|     ASMJIT_ASSERT(cur->pos <= cur->end); | ||||
| 
 | ||||
|     return (void*)ptr; | ||||
|   } | ||||
| 
 | ||||
|   //! Allocate `size` bytes of zeroed memory.
 | ||||
|   //!
 | ||||
|   //! See \ref alloc() for more details.
 | ||||
|   ASMJIT_API void* allocZeroed(size_t size) noexcept; | ||||
| 
 | ||||
|   //! Like `alloc()`, but the return pointer is casted to `T*`.
 | ||||
|   template<typename T> | ||||
|   ASMJIT_INLINE T* allocT(size_t size = sizeof(T)) noexcept { | ||||
|     return static_cast<T*>(alloc(size)); | ||||
|   } | ||||
| 
 | ||||
|   //! Like `allocZeroed()`, but the return pointer is casted to `T*`.
 | ||||
|   template<typename T> | ||||
|   ASMJIT_INLINE T* allocZeroedT(size_t size = sizeof(T)) noexcept { | ||||
|     return static_cast<T*>(allocZeroed(size)); | ||||
|   } | ||||
| 
 | ||||
|   //! \internal
 | ||||
|   ASMJIT_API void* _alloc(size_t size) noexcept; | ||||
| 
 | ||||
|   //! Helper to duplicate data.
 | ||||
|   ASMJIT_API void* dup(const void* data, size_t size) noexcept; | ||||
| 
 | ||||
|   //! Helper to duplicate string.
 | ||||
|   ASMJIT_API char* sdup(const char* str) noexcept; | ||||
| 
 | ||||
|   //! Helper to duplicate formatted string, maximum length is 256 bytes.
 | ||||
|   ASMJIT_API char* sformat(const char* str, ...) noexcept; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! The current block.
 | ||||
|   Block* _block; | ||||
|   //! Default block size.
 | ||||
|   size_t _blockSize; | ||||
| }; | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_BASE_ZONE_H
 | ||||
							
								
								
									
										928
									
								
								DynamicHooks/thirdparty/AsmJit/build.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										928
									
								
								DynamicHooks/thirdparty/AsmJit/build.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,928 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_BUILD_H | ||||
| #define _ASMJIT_BUILD_H | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Build - Configuration]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // AsmJit is by default compiled only for a host processor for the purpose of
 | ||||
| // JIT code generation. Both Assembler and Compiler code generators are compiled
 | ||||
| // by default. Preprocessor macros can be used to change the default behavior.
 | ||||
| 
 | ||||
| // External Config File
 | ||||
| // --------------------
 | ||||
| //
 | ||||
| // Define in case your configuration is generated in an external file to be
 | ||||
| // included.
 | ||||
| 
 | ||||
| #if defined(ASMJIT_CONFIG_FILE) | ||||
| # include ASMJIT_CONFIG_FILE | ||||
| #endif // ASMJIT_CONFIG_FILE
 | ||||
| 
 | ||||
| // AsmJit Static Builds and Embedding
 | ||||
| // ----------------------------------
 | ||||
| //
 | ||||
| // These definitions can be used to enable static library build. Embed is used
 | ||||
| // when AsmJit's source code is embedded directly in another project, implies
 | ||||
| // static build as well.
 | ||||
| //
 | ||||
| // #define ASMJIT_EMBED              // Asmjit is embedded (implies ASMJIT_STATIC).
 | ||||
| // #define ASMJIT_STATIC             // Define to enable static-library build.
 | ||||
| 
 | ||||
| // AsmJit Build Modes
 | ||||
| // ------------------
 | ||||
| //
 | ||||
| // These definitions control the build mode and tracing support. The build mode
 | ||||
| // should be auto-detected at compile time, but it's possible to override it in
 | ||||
| // case that the auto-detection fails.
 | ||||
| //
 | ||||
| // Tracing is a feature that is never compiled by default and it's only used to
 | ||||
| // debug AsmJit itself.
 | ||||
| //
 | ||||
| // #define ASMJIT_DEBUG              // Define to enable debug-mode.
 | ||||
| // #define ASMJIT_RELEASE            // Define to enable release-mode.
 | ||||
| // #define ASMJIT_TRACE              // Define to enable tracing.
 | ||||
| 
 | ||||
| // AsmJit Build Backends
 | ||||
| // ---------------------
 | ||||
| //
 | ||||
| // These definitions control which backends to compile. If none of these is
 | ||||
| // defined AsmJit will use host architecture by default (for JIT code generation).
 | ||||
| //
 | ||||
| // #define ASMJIT_BUILD_X86          // Define to enable x86 instruction set (32-bit).
 | ||||
| // #define ASMJIT_BUILD_X64          // Define to enable x64 instruction set (64-bit).
 | ||||
| // #define ASMJIT_BUILD_HOST         // Define to enable host instruction set.
 | ||||
| 
 | ||||
| // AsmJit Build Features
 | ||||
| // ---------------------
 | ||||
| //
 | ||||
| // Flags can be defined to disable standard features. These are handy especially
 | ||||
| // when building asmjit statically and some features are not needed or unwanted
 | ||||
| // (like Compiler).
 | ||||
| //
 | ||||
| // AsmJit features are enabled by default.
 | ||||
| // #define ASMJIT_DISABLE_COMPILER   // Disable Compiler (completely).
 | ||||
| // #define ASMJIT_DISABLE_LOGGER     // Disable Logger (completely).
 | ||||
| // #define ASMJIT_DISABLE_TEXT       // Disable everything that contains text
 | ||||
| //                                   // representation (instructions, errors, ...).
 | ||||
| 
 | ||||
| // Prevent compile-time errors caused by misconfiguration.
 | ||||
| #if defined(ASMJIT_DISABLE_TEXT) && !defined(ASMJIT_DISABLE_LOGGER) | ||||
| # error "[asmjit] ASMJIT_DISABLE_TEXT requires ASMJIT_DISABLE_LOGGER to be defined." | ||||
| #endif // ASMJIT_DISABLE_TEXT && !ASMJIT_DISABLE_LOGGER
 | ||||
| 
 | ||||
| // Detect ASMJIT_DEBUG and ASMJIT_RELEASE if not forced from outside.
 | ||||
| #if !defined(ASMJIT_DEBUG) && !defined(ASMJIT_RELEASE) && !defined(NDEBUG) | ||||
| # define ASMJIT_DEBUG | ||||
| #else | ||||
| # define ASMJIT_RELEASE | ||||
| #endif | ||||
| 
 | ||||
| // ASMJIT_EMBED implies ASMJIT_STATIC.
 | ||||
| #if defined(ASMJIT_EMBED) && !defined(ASMJIT_STATIC) | ||||
| # define ASMJIT_STATIC | ||||
| #endif | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Build - VERSION]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // [@VERSION{@]
 | ||||
| #define ASMJIT_VERSION_MAJOR 1 | ||||
| #define ASMJIT_VERSION_MINOR 0 | ||||
| #define ASMJIT_VERSION_PATCH 0 | ||||
| #define ASMJIT_VERSION_STRING "1.0.0" | ||||
| // [@VERSION}@]
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Build - WIN32]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // [@WIN32_CRT_NO_DEPRECATE{@]
 | ||||
| #if defined(_MSC_VER) && defined(ASMJIT_EXPORTS) | ||||
| # if !defined(_CRT_SECURE_NO_DEPRECATE) | ||||
| #  define _CRT_SECURE_NO_DEPRECATE | ||||
| # endif | ||||
| # if !defined(_CRT_SECURE_NO_WARNINGS) | ||||
| #  define _CRT_SECURE_NO_WARNINGS | ||||
| # endif | ||||
| #endif | ||||
| // [@WIN32_CRT_NO_DEPRECATE}@]
 | ||||
| 
 | ||||
| // [@WIN32_LEAN_AND_MEAN{@]
 | ||||
| #if (defined(_WIN32) || defined(_WINDOWS)) && !defined(_WINDOWS_) | ||||
| # if !defined(WIN32_LEAN_AND_MEAN) | ||||
| #  define WIN32_LEAN_AND_MEAN | ||||
| #  define ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN | ||||
| # endif | ||||
| # if !defined(NOMINMAX) | ||||
| #  define NOMINMAX | ||||
| #  define ASMJIT_UNDEF_NOMINMAX | ||||
| # endif | ||||
| # include <windows.h> | ||||
| # if defined(ASMJIT_UNDEF_NOMINMAX) | ||||
| #  undef NOMINMAX | ||||
| #  undef ASMJIT_UNDEF_NOMINMAX | ||||
| # endif | ||||
| # if defined(ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN) | ||||
| #  undef WIN32_LEAN_AND_MEAN | ||||
| #  undef ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN | ||||
| # endif | ||||
| #endif | ||||
| // [@WIN32_LEAN_AND_MEAN}@]
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Build - OS]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // [@OS{@]
 | ||||
| #if defined(_WIN32) || defined(_WINDOWS) | ||||
| #define ASMJIT_OS_WINDOWS       (1) | ||||
| #else | ||||
| #define ASMJIT_OS_WINDOWS       (0) | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__APPLE__) | ||||
| # include <TargetConditionals.h> | ||||
| # define ASMJIT_OS_MAC          (TARGET_OS_MAC) | ||||
| # define ASMJIT_OS_IOS          (TARGET_OS_IPHONE) | ||||
| #else | ||||
| # define ASMJIT_OS_MAC          (0) | ||||
| # define ASMJIT_OS_IOS          (0) | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__ANDROID__) | ||||
| # define ASMJIT_OS_ANDROID      (1) | ||||
| #else | ||||
| # define ASMJIT_OS_ANDROID      (0) | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__linux__) || defined(__ANDROID__) | ||||
| # define ASMJIT_OS_LINUX        (1) | ||||
| #else | ||||
| # define ASMJIT_OS_LINUX        (0) | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__DragonFly__) | ||||
| # define ASMJIT_OS_DRAGONFLYBSD (1) | ||||
| #else | ||||
| # define ASMJIT_OS_DRAGONFLYBSD (0) | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__FreeBSD__) | ||||
| # define ASMJIT_OS_FREEBSD      (1) | ||||
| #else | ||||
| # define ASMJIT_OS_FREEBSD      (0) | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__NetBSD__) | ||||
| # define ASMJIT_OS_NETBSD       (1) | ||||
| #else | ||||
| # define ASMJIT_OS_NETBSD       (0) | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__OpenBSD__) | ||||
| # define ASMJIT_OS_OPENBSD      (1) | ||||
| #else | ||||
| # define ASMJIT_OS_OPENBSD      (0) | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__QNXNTO__) | ||||
| # define ASMJIT_OS_QNX          (1) | ||||
| #else | ||||
| # define ASMJIT_OS_QNX          (0) | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__sun) | ||||
| # define ASMJIT_OS_SOLARIS      (1) | ||||
| #else | ||||
| # define ASMJIT_OS_SOLARIS      (0) | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__CYGWIN__) | ||||
| # define ASMJIT_OS_CYGWIN       (1) | ||||
| #else | ||||
| # define ASMJIT_OS_CYGWIN       (0) | ||||
| #endif | ||||
| 
 | ||||
| #define ASMJIT_OS_BSD ( \ | ||||
|         ASMJIT_OS_FREEBSD       || \ | ||||
|         ASMJIT_OS_DRAGONFLYBSD  || \ | ||||
|         ASMJIT_OS_NETBSD        || \ | ||||
|         ASMJIT_OS_OPENBSD       || \ | ||||
|         ASMJIT_OS_MAC) | ||||
| #define ASMJIT_OS_POSIX         (!ASMJIT_OS_WINDOWS) | ||||
| // [@OS}@]
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Build - ARCH]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // [@ARCH{@]
 | ||||
| // \def ASMJIT_ARCH_ARM32
 | ||||
| // True if the target architecture is a 32-bit ARM.
 | ||||
| //
 | ||||
| // \def ASMJIT_ARCH_ARM64
 | ||||
| // True if the target architecture is a 64-bit ARM.
 | ||||
| //
 | ||||
| // \def ASMJIT_ARCH_X86
 | ||||
| // True if the target architecture is a 32-bit X86/IA32
 | ||||
| //
 | ||||
| // \def ASMJIT_ARCH_X64
 | ||||
| // True if the target architecture is a 64-bit X64/AMD64
 | ||||
| //
 | ||||
| // \def ASMJIT_ARCH_LE
 | ||||
| // True if the target architecture is little endian.
 | ||||
| //
 | ||||
| // \def ASMJIT_ARCH_BE
 | ||||
| // True if the target architecture is big endian.
 | ||||
| //
 | ||||
| // \def ASMJIT_ARCH_64BIT
 | ||||
| // True if the target architecture is 64-bit.
 | ||||
| 
 | ||||
| #if (defined(_M_X64  ) || defined(__x86_64) || defined(__x86_64__) || \ | ||||
|      defined(_M_AMD64) || defined(__amd64 ) || defined(__amd64__ )) | ||||
| # define ASMJIT_ARCH_X64 1 | ||||
| #else | ||||
| # define ASMJIT_ARCH_X64 0 | ||||
| #endif | ||||
| 
 | ||||
| #if (defined(_M_IX86 ) || defined(__X86__ ) || defined(__i386  ) || \ | ||||
|      defined(__IA32__) || defined(__I86__ ) || defined(__i386__) || \ | ||||
|      defined(__i486__) || defined(__i586__) || defined(__i686__)) | ||||
| # define ASMJIT_ARCH_X86 (!ASMJIT_ARCH_X64) | ||||
| #else | ||||
| # define ASMJIT_ARCH_X86 0 | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__aarch64__) | ||||
| # define ASMJIT_ARCH_ARM64 1 | ||||
| #else | ||||
| # define ASMJIT_ARCH_ARM64 0 | ||||
| #endif | ||||
| 
 | ||||
| #if (defined(_M_ARM  ) || defined(__arm    ) || defined(__thumb__ ) || \ | ||||
|      defined(_M_ARMT ) || defined(__arm__  ) || defined(__thumb2__)) | ||||
| # define ASMJIT_ARCH_ARM32 (!ASMJIT_ARCH_ARM64) | ||||
| #else | ||||
| # define ASMJIT_ARCH_ARM32 0 | ||||
| #endif | ||||
| 
 | ||||
| #define ASMJIT_ARCH_LE    (  \ | ||||
|         ASMJIT_ARCH_X86   || \ | ||||
|         ASMJIT_ARCH_X64   || \ | ||||
|         ASMJIT_ARCH_ARM32 || \ | ||||
|         ASMJIT_ARCH_ARM64 ) | ||||
| #define ASMJIT_ARCH_BE (!(ASMJIT_ARCH_LE)) | ||||
| #define ASMJIT_ARCH_64BIT (ASMJIT_ARCH_X64 || ASMJIT_ARCH_ARM64) | ||||
| // [@ARCH}@]
 | ||||
| 
 | ||||
| // [@ARCH_UNALIGNED_RW{@]
 | ||||
| // \def ASMJIT_ARCH_UNALIGNED_16
 | ||||
| // True if the target architecture allows unaligned 16-bit reads and writes.
 | ||||
| //
 | ||||
| // \def ASMJIT_ARCH_UNALIGNED_32
 | ||||
| // True if the target architecture allows unaligned 32-bit reads and writes.
 | ||||
| //
 | ||||
| // \def ASMJIT_ARCH_UNALIGNED_64
 | ||||
| // True if the target architecture allows unaligned 64-bit reads and writes.
 | ||||
| 
 | ||||
| #define ASMJIT_ARCH_UNALIGNED_16 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) | ||||
| #define ASMJIT_ARCH_UNALIGNED_32 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) | ||||
| #define ASMJIT_ARCH_UNALIGNED_64 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) | ||||
| // [@ARCH_UNALIGNED_RW}@]
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Build - CC]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // [@CC{@]
 | ||||
| // \def ASMJIT_CC_CLANG
 | ||||
| // True if the detected C++ compiler is CLANG (contains normalized CLANG version).
 | ||||
| //
 | ||||
| // \def ASMJIT_CC_CODEGEAR
 | ||||
| // True if the detected C++ compiler is CODEGEAR or BORLAND (version not normalized).
 | ||||
| //
 | ||||
| // \def ASMJIT_CC_GCC
 | ||||
| // True if the detected C++ compiler is GCC (contains normalized GCC version).
 | ||||
| //
 | ||||
| // \def ASMJIT_CC_MSC
 | ||||
| // True if the detected C++ compiler is MSC (contains normalized MSC version).
 | ||||
| //
 | ||||
| // \def ASMJIT_CC_MINGW
 | ||||
| // Defined to 32 or 64 in case this is a MINGW, otherwise 0.
 | ||||
| 
 | ||||
| #define ASMJIT_CC_CLANG 0 | ||||
| #define ASMJIT_CC_CODEGEAR 0 | ||||
| #define ASMJIT_CC_GCC 0 | ||||
| #define ASMJIT_CC_MSC 0 | ||||
| 
 | ||||
| #if defined(__CODEGEARC__) | ||||
| # undef  ASMJIT_CC_CODEGEAR | ||||
| # define ASMJIT_CC_CODEGEAR (__CODEGEARC__) | ||||
| #elif defined(__BORLANDC__) | ||||
| # undef  ASMJIT_CC_CODEGEAR | ||||
| # define ASMJIT_CC_CODEGEAR (__BORLANDC__) | ||||
| #elif defined(__clang__) && defined(__clang_minor__) | ||||
| # undef  ASMJIT_CC_CLANG | ||||
| # define ASMJIT_CC_CLANG (__clang_major__ * 10000000 + __clang_minor__ * 100000 + __clang_patchlevel__) | ||||
| #elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) | ||||
| # undef  ASMJIT_CC_GCC | ||||
| # define ASMJIT_CC_GCC (__GNUC__ * 10000000 + __GNUC_MINOR__ * 100000 + __GNUC_PATCHLEVEL__) | ||||
| #elif defined(_MSC_VER) && defined(_MSC_FULL_VER) | ||||
| # undef  ASMJIT_CC_MSC | ||||
| # if _MSC_VER == _MSC_FULL_VER / 10000 | ||||
| #  define ASMJIT_CC_MSC (_MSC_VER * 100000 + (_MSC_FULL_VER % 10000)) | ||||
| # else | ||||
| #  define ASMJIT_CC_MSC (_MSC_VER * 100000 + (_MSC_FULL_VER % 100000)) | ||||
| # endif | ||||
| #else | ||||
| # error "[asmjit] Unable to detect the C/C++ compiler." | ||||
| #endif | ||||
| 
 | ||||
| #if ASMJIT_CC_GCC && defined(__GXX_EXPERIMENTAL_CXX0X__) | ||||
| # define ASMJIT_CC_GCC_CXX0X 1 | ||||
| #else | ||||
| # define ASMJIT_CC_GCC_CXX0X 0 | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__MINGW64__) | ||||
| # define ASMJIT_CC_MINGW 64 | ||||
| #elif defined(__MINGW32__) | ||||
| # define ASMJIT_CC_MINGW 32 | ||||
| #else | ||||
| # define ASMJIT_CC_MINGW 0 | ||||
| #endif | ||||
| 
 | ||||
| #define ASMJIT_CC_CODEGEAR_EQ(x, y, z) (ASMJIT_CC_CODEGEAR == (x << 8) + y) | ||||
| #define ASMJIT_CC_CODEGEAR_GE(x, y, z) (ASMJIT_CC_CODEGEAR >= (x << 8) + y) | ||||
| 
 | ||||
| #define ASMJIT_CC_CLANG_EQ(x, y, z) (ASMJIT_CC_CLANG == x * 10000000 + y * 100000 + z) | ||||
| #define ASMJIT_CC_CLANG_GE(x, y, z) (ASMJIT_CC_CLANG >= x * 10000000 + y * 100000 + z) | ||||
| 
 | ||||
| #define ASMJIT_CC_GCC_EQ(x, y, z) (ASMJIT_CC_GCC == x * 10000000 + y * 100000 + z) | ||||
| #define ASMJIT_CC_GCC_GE(x, y, z) (ASMJIT_CC_GCC >= x * 10000000 + y * 100000 + z) | ||||
| 
 | ||||
| #define ASMJIT_CC_MSC_EQ(x, y, z) (ASMJIT_CC_MSC == x * 10000000 + y * 100000 + z) | ||||
| #define ASMJIT_CC_MSC_GE(x, y, z) (ASMJIT_CC_MSC >= x * 10000000 + y * 100000 + z) | ||||
| // [@CC}@]
 | ||||
| 
 | ||||
| // [@CC_FEATURES{@]
 | ||||
| // \def ASMJIT_CC_HAS_NATIVE_CHAR
 | ||||
| // True if the C++ compiler treats char as a native type.
 | ||||
| //
 | ||||
| // \def ASMJIT_CC_HAS_NATIVE_WCHAR_T
 | ||||
| // True if the C++ compiler treats wchar_t as a native type.
 | ||||
| //
 | ||||
| // \def ASMJIT_CC_HAS_NATIVE_CHAR16_T
 | ||||
| // True if the C++ compiler treats char16_t as a native type.
 | ||||
| //
 | ||||
| // \def ASMJIT_CC_HAS_NATIVE_CHAR32_T
 | ||||
| // True if the C++ compiler treats char32_t as a native type.
 | ||||
| //
 | ||||
| // \def ASMJIT_CC_HAS_OVERRIDE
 | ||||
| // True if the C++ compiler supports override keyword.
 | ||||
| //
 | ||||
| // \def ASMJIT_CC_HAS_NOEXCEPT
 | ||||
| // True if the C++ compiler supports noexcept keyword.
 | ||||
| 
 | ||||
| #if ASMJIT_CC_CLANG | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE               (1) | ||||
| # define ASMJIT_CC_HAS_BUILTIN                 (1) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC                (0) | ||||
| 
 | ||||
| # define ASMJIT_CC_HAS_ALIGNAS                 (__has_extension(__cxx_alignas__)) | ||||
| # define ASMJIT_CC_HAS_ALIGNOF                 (__has_extension(__cxx_alignof__)) | ||||
| # define ASMJIT_CC_HAS_ASSUME                  (0) | ||||
| # define ASMJIT_CC_HAS_ASSUME_ALIGNED          (0) | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED       (__has_attribute(__aligned__)) | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (__has_attribute(__always_inline__)) | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE      (__has_attribute(__noinline__)) | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN      (__has_attribute(__noreturn__)) | ||||
| # define ASMJIT_CC_HAS_BUILTIN_ASSUME          (__has_builtin(__builtin_assume)) | ||||
| # define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED  (__has_builtin(__builtin_assume_aligned)) | ||||
| # define ASMJIT_CC_HAS_BUILTIN_EXPECT          (__has_builtin(__builtin_expect)) | ||||
| # define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE     (__has_builtin(__builtin_unreachable)) | ||||
| # define ASMJIT_CC_HAS_CONSTEXPR               (__has_extension(__cxx_constexpr__)) | ||||
| # define ASMJIT_CC_HAS_DECLTYPE                (__has_extension(__cxx_decltype__)) | ||||
| # define ASMJIT_CC_HAS_DEFAULT_FUNCTION        (__has_extension(__cxx_defaulted_functions__)) | ||||
| # define ASMJIT_CC_HAS_DELETE_FUNCTION         (__has_extension(__cxx_deleted_functions__)) | ||||
| # define ASMJIT_CC_HAS_FINAL                   (__has_extension(__cxx_override_control__)) | ||||
| # define ASMJIT_CC_HAS_INITIALIZER_LIST        (__has_extension(__cxx_generalized_initializers__)) | ||||
| # define ASMJIT_CC_HAS_LAMBDA                  (__has_extension(__cxx_lambdas__)) | ||||
| # define ASMJIT_CC_HAS_NATIVE_CHAR             (1) | ||||
| # define ASMJIT_CC_HAS_NATIVE_CHAR16_T         (__has_extension(__cxx_unicode_literals__)) | ||||
| # define ASMJIT_CC_HAS_NATIVE_CHAR32_T         (__has_extension(__cxx_unicode_literals__)) | ||||
| # define ASMJIT_CC_HAS_NATIVE_WCHAR_T          (1) | ||||
| # define ASMJIT_CC_HAS_NOEXCEPT                (__has_extension(__cxx_noexcept__)) | ||||
| # define ASMJIT_CC_HAS_NULLPTR                 (__has_extension(__cxx_nullptr__)) | ||||
| # define ASMJIT_CC_HAS_OVERRIDE                (__has_extension(__cxx_override_control__)) | ||||
| # define ASMJIT_CC_HAS_RVALUE                  (__has_extension(__cxx_rvalue_references__)) | ||||
| # define ASMJIT_CC_HAS_STATIC_ASSERT           (__has_extension(__cxx_static_assert__)) | ||||
| #endif | ||||
| 
 | ||||
| #if ASMJIT_CC_CODEGEAR | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE               (0) | ||||
| # define ASMJIT_CC_HAS_BUILTIN                 (0) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC                (1) | ||||
| 
 | ||||
| # define ASMJIT_CC_HAS_ALIGNAS                 (0) | ||||
| # define ASMJIT_CC_HAS_ALIGNOF                 (0) | ||||
| # define ASMJIT_CC_HAS_ASSUME                  (0) | ||||
| # define ASMJIT_CC_HAS_ASSUME_ALIGNED          (0) | ||||
| # define ASMJIT_CC_HAS_CONSTEXPR               (0) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC_ALIGN          (ASMJIT_CC_CODEGEAR >= 0x0610) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE    (0) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC_NOINLINE       (0) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC_NORETURN       (ASMJIT_CC_CODEGEAR >= 0x0610) | ||||
| # define ASMJIT_CC_HAS_DECLTYPE                (ASMJIT_CC_CODEGEAR >= 0x0610) | ||||
| # define ASMJIT_CC_HAS_DEFAULT_FUNCTION        (0) | ||||
| # define ASMJIT_CC_HAS_DELETE_FUNCTION         (0) | ||||
| # define ASMJIT_CC_HAS_FINAL                   (0) | ||||
| # define ASMJIT_CC_HAS_INITIALIZER_LIST        (0) | ||||
| # define ASMJIT_CC_HAS_LAMBDA                  (0) | ||||
| # define ASMJIT_CC_HAS_NATIVE_CHAR             (1) | ||||
| # define ASMJIT_CC_HAS_NATIVE_CHAR16_T         (0) | ||||
| # define ASMJIT_CC_HAS_NATIVE_CHAR32_T         (0) | ||||
| # define ASMJIT_CC_HAS_NATIVE_WCHAR_T          (1) | ||||
| # define ASMJIT_CC_HAS_NOEXCEPT                (0) | ||||
| # define ASMJIT_CC_HAS_NULLPTR                 (0) | ||||
| # define ASMJIT_CC_HAS_OVERRIDE                (0) | ||||
| # define ASMJIT_CC_HAS_RVALUE                  (ASMJIT_CC_CODEGEAR >= 0x0610) | ||||
| # define ASMJIT_CC_HAS_STATIC_ASSERT           (ASMJIT_CC_CODEGEAR >= 0x0610) | ||||
| #endif | ||||
| 
 | ||||
| #if ASMJIT_CC_GCC | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE               (1) | ||||
| # define ASMJIT_CC_HAS_BUILTIN                 (1) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC                (0) | ||||
| 
 | ||||
| # define ASMJIT_CC_HAS_ALIGNAS                 (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_ALIGNOF                 (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_ASSUME                  (0) | ||||
| # define ASMJIT_CC_HAS_ASSUME_ALIGNED          (0) | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED       (ASMJIT_CC_GCC_GE(2, 7, 0)) | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (ASMJIT_CC_GCC_GE(4, 4, 0) && !ASMJIT_CC_MINGW) | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE      (ASMJIT_CC_GCC_GE(3, 4, 0) && !ASMJIT_CC_MINGW) | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN      (ASMJIT_CC_GCC_GE(2, 5, 0)) | ||||
| # define ASMJIT_CC_HAS_BUILTIN_ASSUME          (0) | ||||
| # define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED  (ASMJIT_CC_GCC_GE(4, 7, 0)) | ||||
| # define ASMJIT_CC_HAS_BUILTIN_EXPECT          (1) | ||||
| # define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE     (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_CONSTEXPR               (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_DECLTYPE                (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_DEFAULT_FUNCTION        (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_DELETE_FUNCTION         (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_FINAL                   (ASMJIT_CC_GCC_GE(4, 7, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_INITIALIZER_LIST        (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_LAMBDA                  (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_NATIVE_CHAR             (1) | ||||
| # define ASMJIT_CC_HAS_NATIVE_CHAR16_T         (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_NATIVE_CHAR32_T         (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_NATIVE_WCHAR_T          (1) | ||||
| # define ASMJIT_CC_HAS_NOEXCEPT                (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_NULLPTR                 (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_OVERRIDE                (ASMJIT_CC_GCC_GE(4, 7, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_RVALUE                  (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| # define ASMJIT_CC_HAS_STATIC_ASSERT           (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_GCC_CXX0X) | ||||
| #endif | ||||
| 
 | ||||
| #if ASMJIT_CC_MSC | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE               (0) | ||||
| # define ASMJIT_CC_HAS_BUILTIN                 (0) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC                (1) | ||||
| 
 | ||||
| # define ASMJIT_CC_HAS_ALIGNAS                 (ASMJIT_CC_MSC_GE(19, 0, 0)) | ||||
| # define ASMJIT_CC_HAS_ALIGNOF                 (ASMJIT_CC_MSC_GE(19, 0, 0)) | ||||
| # define ASMJIT_CC_HAS_ASSUME                  (1) | ||||
| # define ASMJIT_CC_HAS_ASSUME_ALIGNED          (0) | ||||
| # define ASMJIT_CC_HAS_CONSTEXPR               (ASMJIT_CC_MSC_GE(19, 0, 0)) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC_ALIGN          (1) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE    (1) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC_NOINLINE       (1) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC_NORETURN       (1) | ||||
| # define ASMJIT_CC_HAS_DECLTYPE                (ASMJIT_CC_MSC_GE(16, 0, 0)) | ||||
| # define ASMJIT_CC_HAS_DEFAULT_FUNCTION        (ASMJIT_CC_MSC_GE(18, 0, 0)) | ||||
| # define ASMJIT_CC_HAS_DELETE_FUNCTION         (ASMJIT_CC_MSC_GE(18, 0, 0)) | ||||
| # define ASMJIT_CC_HAS_FINAL                   (ASMJIT_CC_MSC_GE(14, 0, 0)) | ||||
| # define ASMJIT_CC_HAS_INITIALIZER_LIST        (ASMJIT_CC_MSC_GE(18, 0, 0)) | ||||
| # define ASMJIT_CC_HAS_LAMBDA                  (ASMJIT_CC_MSC_GE(16, 0, 0)) | ||||
| # define ASMJIT_CC_HAS_NATIVE_CHAR             (1) | ||||
| # define ASMJIT_CC_HAS_NATIVE_CHAR16_T         (ASMJIT_CC_MSC_GE(19, 0, 0)) | ||||
| # define ASMJIT_CC_HAS_NATIVE_CHAR32_T         (ASMJIT_CC_MSC_GE(19, 0, 0)) | ||||
| # if defined(_NATIVE_WCHAR_T_DEFINED) | ||||
| #  define ASMJIT_CC_HAS_NATIVE_WCHAR_T         (1) | ||||
| # else | ||||
| #  define ASMJIT_CC_HAS_NATIVE_WCHAR_T         (0) | ||||
| # endif | ||||
| # define ASMJIT_CC_HAS_NOEXCEPT                (ASMJIT_CC_MSC_GE(19, 0, 0)) | ||||
| # define ASMJIT_CC_HAS_NULLPTR                 (ASMJIT_CC_MSC_GE(16, 0, 0)) | ||||
| # define ASMJIT_CC_HAS_OVERRIDE                (ASMJIT_CC_MSC_GE(14, 0, 0)) | ||||
| # define ASMJIT_CC_HAS_RVALUE                  (ASMJIT_CC_MSC_GE(16, 0, 0)) | ||||
| # define ASMJIT_CC_HAS_STATIC_ASSERT           (ASMJIT_CC_MSC_GE(16, 0, 0)) | ||||
| #endif | ||||
| 
 | ||||
| #if !ASMJIT_CC_HAS_ATTRIBUTE | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED       (0) | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (0) | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE      (0) | ||||
| # define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN      (0) | ||||
| #endif | ||||
| 
 | ||||
| #if !ASMJIT_CC_HAS_BUILTIN | ||||
| # define ASMJIT_CC_HAS_BUILTIN_ASSUME          (0) | ||||
| # define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED  (0) | ||||
| # define ASMJIT_CC_HAS_BUILTIN_EXPECT          (0) | ||||
| # define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE     (0) | ||||
| #endif | ||||
| 
 | ||||
| #if !ASMJIT_CC_HAS_DECLSPEC | ||||
| # define ASMJIT_CC_HAS_DECLSPEC_ALIGN          (0) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE    (0) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC_NOINLINE       (0) | ||||
| # define ASMJIT_CC_HAS_DECLSPEC_NORETURN       (0) | ||||
| #endif | ||||
| // [@CC_FEATURES}@]
 | ||||
| 
 | ||||
| // [@CC_API{@]
 | ||||
| // \def ASMJIT_API
 | ||||
| // The decorated function is asmjit API and should be exported.
 | ||||
| #if !defined(ASMJIT_API) | ||||
| # if defined(ASMJIT_STATIC) | ||||
| #  define ASMJIT_API | ||||
| # elif ASMJIT_OS_WINDOWS | ||||
| #  if (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && !ASMJIT_CC_MINGW | ||||
| #   if defined(ASMJIT_EXPORTS) | ||||
| #    define ASMJIT_API __attribute__((__dllexport__)) | ||||
| #   else | ||||
| #    define ASMJIT_API __attribute__((__dllimport__)) | ||||
| #   endif | ||||
| #  else | ||||
| #   if defined(ASMJIT_EXPORTS) | ||||
| #    define ASMJIT_API __declspec(dllexport) | ||||
| #   else | ||||
| #    define ASMJIT_API __declspec(dllimport) | ||||
| #   endif | ||||
| #  endif | ||||
| # else | ||||
| #  if ASMJIT_CC_CLANG || ASMJIT_CC_GCC_GE(4, 0, 0) | ||||
| #   define ASMJIT_API __attribute__((__visibility__("default"))) | ||||
| #  endif | ||||
| # endif | ||||
| #endif | ||||
| // [@CC_API}@]
 | ||||
| 
 | ||||
| // [@CC_VARAPI{@]
 | ||||
| // \def ASMJIT_VARAPI
 | ||||
| // The decorated variable is part of asmjit API and is exported.
 | ||||
| #if !defined(ASMJIT_VARAPI) | ||||
| # define ASMJIT_VARAPI extern ASMJIT_API | ||||
| #endif | ||||
| // [@CC_VARAPI}@]
 | ||||
| 
 | ||||
| // [@CC_VIRTAPI{@]
 | ||||
| // \def ASMJIT_VIRTAPI
 | ||||
| // The decorated class has a virtual table and is part of asmjit API.
 | ||||
| //
 | ||||
| // This is basically a workaround. When using MSVC and marking class as DLL
 | ||||
| // export everything gets exported, which is unwanted in most projects. MSVC
 | ||||
| // automatically exports typeinfo and vtable if at least one symbol of the
 | ||||
| // class is exported. However, GCC has some strange behavior that even if
 | ||||
| // one or more symbol is exported it doesn't export typeinfo unless the
 | ||||
| // class itself is decorated with "visibility(default)" (i.e. asmjit_API).
 | ||||
| #if (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && !ASMJIT_OS_WINDOWS | ||||
| # define ASMJIT_VIRTAPI ASMJIT_API | ||||
| #else | ||||
| # define ASMJIT_VIRTAPI | ||||
| #endif | ||||
| // [@CC_VIRTAPI}@]
 | ||||
| 
 | ||||
| // [@CC_INLINE{@]
 | ||||
| // \def ASMJIT_INLINE
 | ||||
| // Always inline the decorated function.
 | ||||
| #if ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE | ||||
| # define ASMJIT_INLINE inline __attribute__((__always_inline__)) | ||||
| #elif ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE | ||||
| # define ASMJIT_INLINE __forceinline | ||||
| #else | ||||
| # define ASMJIT_INLINE inline | ||||
| #endif | ||||
| // [@CC_INLINE}@]
 | ||||
| 
 | ||||
| // [@CC_NOINLINE{@]
 | ||||
| // \def ASMJIT_NOINLINE
 | ||||
| // Never inline the decorated function.
 | ||||
| #if ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE | ||||
| # define ASMJIT_NOINLINE __attribute__((__noinline__)) | ||||
| #elif ASMJIT_CC_HAS_DECLSPEC_NOINLINE | ||||
| # define ASMJIT_NOINLINE __declspec(noinline) | ||||
| #else | ||||
| # define ASMJIT_NOINLINE | ||||
| #endif | ||||
| // [@CC_NOINLINE}@]
 | ||||
| 
 | ||||
| // [@CC_NORETURN{@]
 | ||||
| // \def ASMJIT_NORETURN
 | ||||
| // The decorated function never returns (exit, assertion failure, etc...).
 | ||||
| #if ASMJIT_CC_HAS_ATTRIBUTE_NORETURN | ||||
| # define ASMJIT_NORETURN __attribute__((__noreturn__)) | ||||
| #elif ASMJIT_CC_HAS_DECLSPEC_NORETURN | ||||
| # define ASMJIT_NORETURN __declspec(noreturn) | ||||
| #else | ||||
| # define ASMJIT_NORETURN | ||||
| #endif | ||||
| // [@CC_NORETURN}@]
 | ||||
| 
 | ||||
| // [@CC_CDECL{@]
 | ||||
| // \def ASMJIT_CDECL
 | ||||
| // Standard C function calling convention decorator (__cdecl).
 | ||||
| #if ASMJIT_ARCH_X86 | ||||
| # if ASMJIT_CC_HAS_ATTRIBUTE | ||||
| #  define ASMJIT_CDECL __attribute__((__cdecl__)) | ||||
| # else | ||||
| #  define ASMJIT_CDECL __cdecl | ||||
| # endif | ||||
| #else | ||||
| # define ASMJIT_CDECL | ||||
| #endif | ||||
| // [@CC_CDECL}@]
 | ||||
| 
 | ||||
| // [@CC_STDCALL{@]
 | ||||
| // \def ASMJIT_STDCALL
 | ||||
| // StdCall function calling convention decorator (__stdcall).
 | ||||
| #if ASMJIT_ARCH_X86 | ||||
| # if ASMJIT_CC_HAS_ATTRIBUTE | ||||
| #  define ASMJIT_STDCALL __attribute__((__stdcall__)) | ||||
| # else | ||||
| #  define ASMJIT_STDCALL __stdcall | ||||
| # endif | ||||
| #else | ||||
| # define ASMJIT_STDCALL | ||||
| #endif | ||||
| // [@CC_STDCALL}@]
 | ||||
| 
 | ||||
| // [@CC_FASTCALL{@]
 | ||||
| // \def ASMJIT_FASTCALL
 | ||||
| // FastCall function calling convention decorator (__fastcall).
 | ||||
| #if ASMJIT_ARCH_X86 | ||||
| # if ASMJIT_CC_HAS_ATTRIBUTE | ||||
| #  define ASMJIT_FASTCALL __attribute__((__fastcall__)) | ||||
| # else | ||||
| #  define ASMJIT_FASTCALL __fastcall | ||||
| # endif | ||||
| #else | ||||
| # define ASMJIT_FASTCALL | ||||
| #endif | ||||
| // [@CC_FASTCALL}@]
 | ||||
| 
 | ||||
| // [@CC_REGPARM{@]
 | ||||
| // \def ASMJIT_REGPARM(n)
 | ||||
| // A custom calling convention which passes n arguments in registers.
 | ||||
| #if ASMJIT_ARCH_X86 && (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) | ||||
| # define ASMJIT_REGPARM(n) __attribute__((__regparm__(n))) | ||||
| #else | ||||
| # define ASMJIT_REGPARM(n) | ||||
| #endif | ||||
| // [@CC_REGPARM}@]
 | ||||
| 
 | ||||
| // [@CC_NOEXCEPT{@]
 | ||||
| // \def ASMJIT_NOEXCEPT
 | ||||
| // The decorated function never throws an exception (noexcept).
 | ||||
| #if ASMJIT_CC_HAS_NOEXCEPT | ||||
| # define ASMJIT_NOEXCEPT noexcept | ||||
| #else | ||||
| # define ASMJIT_NOEXCEPT | ||||
| #endif | ||||
| // [@CC_NOEXCEPT}@]
 | ||||
| 
 | ||||
| // [@CC_NOP{@]
 | ||||
| // \def ASMJIT_NOP
 | ||||
| // No operation.
 | ||||
| #if !defined(ASMJIT_NOP) | ||||
| # define ASMJIT_NOP ((void)0) | ||||
| #endif | ||||
| // [@CC_NOP}@]
 | ||||
| 
 | ||||
| // [@CC_ASSUME{@]
 | ||||
| // \def ASMJIT_ASSUME(exp)
 | ||||
| // Assume that the expression exp is always true.
 | ||||
| #if ASMJIT_CC_HAS_ASSUME | ||||
| # define ASMJIT_ASSUME(exp) __assume(exp) | ||||
| #elif ASMJIT_CC_HAS_BUILTIN_ASSUME | ||||
| # define ASMJIT_ASSUME(exp) __builtin_assume(exp) | ||||
| #elif ASMJIT_CC_HAS_BUILTIN_UNREACHABLE | ||||
| # define ASMJIT_ASSUME(exp) do { if (!(exp)) __builtin_unreachable(); } while (0) | ||||
| #else | ||||
| # define ASMJIT_ASSUME(exp) ((void)0) | ||||
| #endif | ||||
| // [@CC_ASSUME}@]
 | ||||
| 
 | ||||
| // [@CC_ASSUME_ALIGNED{@]
 | ||||
| // \def ASMJIT_ASSUME_ALIGNED(p, alignment)
 | ||||
| // Assume that the pointer 'p' is aligned to at least 'alignment' bytes.
 | ||||
| #if ASMJIT_CC_HAS_ASSUME_ALIGNED | ||||
| # define ASMJIT_ASSUME_ALIGNED(p, alignment) __assume_aligned(p, alignment) | ||||
| #elif ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED | ||||
| # define ASMJIT_ASSUME_ALIGNED(p, alignment) p = __builtin_assume_aligned(p, alignment) | ||||
| #else | ||||
| # define ASMJIT_ASSUME_ALIGNED(p, alignment) ((void)0) | ||||
| #endif | ||||
| // [@CC_ASSUME_ALIGNED}@]
 | ||||
| 
 | ||||
| // [@CC_EXPECT{@]
 | ||||
| // \def ASMJIT_LIKELY(exp)
 | ||||
| // Expression exp is likely to be true.
 | ||||
| //
 | ||||
| // \def ASMJIT_UNLIKELY(exp)
 | ||||
| // Expression exp is likely to be false.
 | ||||
| #if ASMJIT_HAS_BUILTIN_EXPECT | ||||
| # define ASMJIT_LIKELY(exp) __builtin_expect(!!(exp), 1) | ||||
| # define ASMJIT_UNLIKELY(exp) __builtin_expect(!!(exp), 0) | ||||
| #else | ||||
| # define ASMJIT_LIKELY(exp) exp | ||||
| # define ASMJIT_UNLIKELY(exp) exp | ||||
| #endif | ||||
| // [@CC_EXPECT}@]
 | ||||
| 
 | ||||
| // [@CC_FALLTHROUGH{@]
 | ||||
| // \def ASMJIT_FALLTHROUGH
 | ||||
| // The code falls through annotation (switch / case).
 | ||||
| #if ASMJIT_CC_CLANG && __cplusplus >= 201103L | ||||
| # define ASMJIT_FALLTHROUGH [[clang::fallthrough]] | ||||
| #else | ||||
| # define ASMJIT_FALLTHROUGH (void)0 | ||||
| #endif | ||||
| // [@CC_FALLTHROUGH}@]
 | ||||
| 
 | ||||
| // [@CC_UNUSED{@]
 | ||||
| // \def ASMJIT_UNUSED(x)
 | ||||
| // Mark a variable x as unused.
 | ||||
| #define ASMJIT_UNUSED(x) (void)(x) | ||||
| // [@CC_UNUSED}@]
 | ||||
| 
 | ||||
| // [@CC_OFFSET_OF{@]
 | ||||
| // \def ASMJIT_OFFSET_OF(x, y).
 | ||||
| // Get the offset of a member y of a struct x at compile-time.
 | ||||
| #define ASMJIT_OFFSET_OF(x, y) ((int)(intptr_t)((const char*)&((const x*)0x1)->y) - 1) | ||||
| // [@CC_OFFSET_OF}@]
 | ||||
| 
 | ||||
| // [@CC_ARRAY_SIZE{@]
 | ||||
| // \def ASMJIT_ARRAY_SIZE(x)
 | ||||
| // Get the array size of x at compile-time.
 | ||||
| #define ASMJIT_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) | ||||
| // [@CC_ARRAY_SIZE}@]
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Build - STDTYPES]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // [@STDTYPES{@]
 | ||||
| #if defined(__MINGW32__) || defined(__MINGW64__) | ||||
| # include <sys/types.h> | ||||
| #endif | ||||
| #if defined(_MSC_VER) && (_MSC_VER < 1600) | ||||
| # include <limits.h> | ||||
| # if !defined(ASMJIT_SUPPRESS_STD_TYPES) | ||||
| #  if (_MSC_VER < 1300) | ||||
| typedef signed char      int8_t; | ||||
| typedef signed short     int16_t; | ||||
| typedef signed int       int32_t; | ||||
| typedef signed __int64   int64_t; | ||||
| typedef unsigned char    uint8_t; | ||||
| typedef unsigned short   uint16_t; | ||||
| typedef unsigned int     uint32_t; | ||||
| typedef unsigned __int64 uint64_t; | ||||
| #  else | ||||
| typedef __int8           int8_t; | ||||
| typedef __int16          int16_t; | ||||
| typedef __int32          int32_t; | ||||
| typedef __int64          int64_t; | ||||
| typedef unsigned __int8  uint8_t; | ||||
| typedef unsigned __int16 uint16_t; | ||||
| typedef unsigned __int32 uint32_t; | ||||
| typedef unsigned __int64 uint64_t; | ||||
| #  endif | ||||
| # endif | ||||
| # define ASMJIT_INT64_C(x) (x##i64) | ||||
| # define ASMJIT_UINT64_C(x) (x##ui64) | ||||
| #else | ||||
| # include <stdint.h> | ||||
| # include <limits.h> | ||||
| # define ASMJIT_INT64_C(x) (x##ll) | ||||
| # define ASMJIT_UINT64_C(x) (x##ull) | ||||
| #endif | ||||
| // [@STDTYPES}@]
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Build - Dependencies]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #include <new> | ||||
| #include <stdarg.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #if ASMJIT_OS_POSIX | ||||
| # include <pthread.h> | ||||
| #endif // ASMJIT_OS_POSIX
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Build - Additional]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // Build host architecture if no architecture is selected.
 | ||||
| #if !defined(ASMJIT_BUILD_HOST) && \ | ||||
|     !defined(ASMJIT_BUILD_X86) && \ | ||||
|     !defined(ASMJIT_BUILD_X64) | ||||
| # define ASMJIT_BUILD_HOST | ||||
| #endif | ||||
| 
 | ||||
| // Autodetect host architecture if enabled.
 | ||||
| #if defined(ASMJIT_BUILD_HOST) | ||||
| # if ASMJIT_ARCH_X86 && !defined(ASMJIT_BUILD_X86) | ||||
| #  define ASMJIT_BUILD_X86 | ||||
| # endif // ASMJIT_ARCH_X86 && !ASMJIT_BUILD_X86
 | ||||
| # if ASMJIT_ARCH_X64 && !defined(ASMJIT_BUILD_X64) | ||||
| #  define ASMJIT_BUILD_X64 | ||||
| # endif // ASMJIT_ARCH_X64 && !ASMJIT_BUILD_X64
 | ||||
| #endif // ASMJIT_BUILD_HOST
 | ||||
| 
 | ||||
| #if defined(_MSC_VER) && _MSC_VER >= 1400 | ||||
| # define ASMJIT_ENUM(name) enum name : uint32_t | ||||
| #else | ||||
| # define ASMJIT_ENUM(name) enum name | ||||
| #endif | ||||
| 
 | ||||
| #if ASMJIT_ARCH_LE | ||||
| # define _ASMJIT_ARCH_INDEX(total, index) (index) | ||||
| #else | ||||
| # define _ASMJIT_ARCH_INDEX(total, index) ((total) - 1 - (index)) | ||||
| #endif | ||||
| 
 | ||||
| #if !defined(ASMJIT_ALLOC) && !defined(ASMJIT_REALLOC) && !defined(ASMJIT_FREE) | ||||
| # define ASMJIT_ALLOC(size) ::malloc(size) | ||||
| # define ASMJIT_REALLOC(ptr, size) ::realloc(ptr, size) | ||||
| # define ASMJIT_FREE(ptr) ::free(ptr) | ||||
| #else | ||||
| # if !defined(ASMJIT_ALLOC) || !defined(ASMJIT_REALLOC) || !defined(ASMJIT_FREE) | ||||
| #  error "[asmjit] You must provide ASMJIT_ALLOC, ASMJIT_REALLOC and ASMJIT_FREE." | ||||
| # endif | ||||
| #endif // !ASMJIT_ALLOC && !ASMJIT_REALLOC && !ASMJIT_FREE
 | ||||
| 
 | ||||
| #define ASMJIT_NO_COPY(...) \ | ||||
| private: \ | ||||
|   ASMJIT_INLINE __VA_ARGS__(const __VA_ARGS__& other) ASMJIT_NOEXCEPT; \ | ||||
|   ASMJIT_INLINE __VA_ARGS__& operator=(const __VA_ARGS__& other) ASMJIT_NOEXCEPT; \ | ||||
| public: | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Build - Relative Path]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| namespace asmjit { | ||||
| namespace DebugUtils { | ||||
| 
 | ||||
| // Workaround that is used to convert an absolute path to a relative one at
 | ||||
| // a C macro level, used by asserts and tracing. This workaround is needed
 | ||||
| // as some build systems always convert the source code files to use absolute
 | ||||
| // paths. Please note that if absolute paths are used this doesn't remove them
 | ||||
| // from the compiled binary and can be still considered a security risk.
 | ||||
| enum { | ||||
|   kSourceRelativePathOffset = int(sizeof(__FILE__) - sizeof("asmjit/build.h")) | ||||
| }; | ||||
| 
 | ||||
| // ASMJIT_TRACE is only used by sources and private headers. It's safe to make
 | ||||
| // it unavailable outside of AsmJit.
 | ||||
| #if defined(ASMJIT_EXPORTS) | ||||
| static inline int disabledTrace(...) { return 0; } | ||||
| # if defined(ASMJIT_TRACE) | ||||
| #  define ASMJIT_TSEC(section) section | ||||
| #  define ASMJIT_TLOG ::printf | ||||
| # else | ||||
| #  define ASMJIT_TSEC(section) ASMJIT_NOP | ||||
| #  define ASMJIT_TLOG 0 && ::asmjit::DebugUtils::disabledTrace | ||||
| # endif // ASMJIT_TRACE
 | ||||
| #endif // ASMJIT_EXPORTS
 | ||||
| 
 | ||||
| } // DebugUtils namespace
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::Build - Test]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| // Include a unit testing package if this is a `asmjit_test` build.
 | ||||
| #if defined(ASMJIT_TEST) | ||||
| # include "../test/broken.h" | ||||
| #endif // ASMJIT_TEST
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_BUILD_H
 | ||||
							
								
								
									
										53
									
								
								DynamicHooks/thirdparty/AsmJit/host.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								DynamicHooks/thirdparty/AsmJit/host.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_HOST_H | ||||
| #define _ASMJIT_HOST_H | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "./base.h" | ||||
| 
 | ||||
| // [X86 / X64]
 | ||||
| #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 | ||||
| #include "./x86.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // Define `asmjit::host` namespace wrapping `asmjit::x86`.
 | ||||
| namespace host { using namespace ::asmjit::x86; } | ||||
| 
 | ||||
| // Define host assembler.
 | ||||
| typedef X86Assembler HostAssembler; | ||||
| 
 | ||||
| // Define host operands.
 | ||||
| typedef X86GpReg GpReg; | ||||
| typedef X86FpReg FpReg; | ||||
| typedef X86MmReg MmReg; | ||||
| typedef X86XmmReg XmmReg; | ||||
| typedef X86YmmReg YmmReg; | ||||
| typedef X86SegReg SegReg; | ||||
| typedef X86Mem Mem; | ||||
| 
 | ||||
| // Define host compiler and related.
 | ||||
| #if !defined(ASMJIT_DISABLE_COMPILER) | ||||
| typedef X86Compiler HostCompiler; | ||||
| typedef X86CallNode HostCallNode; | ||||
| typedef X86FuncDecl HostFuncDecl; | ||||
| typedef X86FuncNode HostFuncNode; | ||||
| 
 | ||||
| typedef X86GpVar GpVar; | ||||
| typedef X86MmVar MmVar; | ||||
| typedef X86XmmVar XmmVar; | ||||
| typedef X86YmmVar YmmVar; | ||||
| #endif // !ASMJIT_DISABLE_COMPILER
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| #endif // ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_HOST_H
 | ||||
							
								
								
									
										21
									
								
								DynamicHooks/thirdparty/AsmJit/x86.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								DynamicHooks/thirdparty/AsmJit/x86.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_X86_H | ||||
| #define _ASMJIT_X86_H | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "./base.h" | ||||
| 
 | ||||
| #include "./x86/x86assembler.h" | ||||
| #include "./x86/x86compiler.h" | ||||
| #include "./x86/x86compilerfunc.h" | ||||
| #include "./x86/x86inst.h" | ||||
| #include "./x86/x86operand.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // _ASMJIT_X86_H
 | ||||
							
								
								
									
										4304
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86assembler.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4304
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86assembler.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										6717
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86assembler.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6717
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86assembler.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										860
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86compiler.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										860
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86compiler.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,860 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #include "../build.h" | ||||
| #if !defined(ASMJIT_DISABLE_COMPILER) && (defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)) | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/containers.h" | ||||
| #include "../base/utils.h" | ||||
| #include "../x86/x86assembler.h" | ||||
| #include "../x86/x86compiler.h" | ||||
| #include "../x86/x86compilercontext_p.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [Debug]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #if !defined(ASMJIT_DEBUG) | ||||
| #define ASMJIT_ASSERT_OPERAND(op) \ | ||||
|   do {} while(0) | ||||
| #else | ||||
| #define ASMJIT_ASSERT_OPERAND(op) \ | ||||
|   do { \ | ||||
|     if (op.isVar() || op.isLabel()) { \ | ||||
|       ASMJIT_ASSERT(op.getId() != kInvalidValue); \ | ||||
|     } \ | ||||
|   } while(0) | ||||
| #endif | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86VarInfo]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #define F(flag) VarInfo::kFlag##flag | ||||
| const VarInfo _x86VarInfo[] = { | ||||
|   { kVarTypeInt8    , 1 , kX86RegClassGp , kX86RegTypeGpbLo, 0              , "gpb" }, | ||||
|   { kVarTypeUInt8   , 1 , kX86RegClassGp , kX86RegTypeGpbLo, 0              , "gpb" }, | ||||
|   { kVarTypeInt16   , 2 , kX86RegClassGp , kX86RegTypeGpw  , 0              , "gpw" }, | ||||
|   { kVarTypeUInt16  , 2 , kX86RegClassGp , kX86RegTypeGpw  , 0              , "gpw" }, | ||||
|   { kVarTypeInt32   , 4 , kX86RegClassGp , kX86RegTypeGpd  , 0              , "gpd" }, | ||||
|   { kVarTypeUInt32  , 4 , kX86RegClassGp , kX86RegTypeGpd  , 0              , "gpd" }, | ||||
|   { kVarTypeInt64   , 8 , kX86RegClassGp , kX86RegTypeGpq  , 0              , "gpq" }, | ||||
|   { kVarTypeUInt64  , 8 , kX86RegClassGp , kX86RegTypeGpq  , 0              , "gpq" }, | ||||
|   { kVarTypeIntPtr  , 0 , kX86RegClassGp , 0               , 0              , ""    }, // Abstract.
 | ||||
|   { kVarTypeUIntPtr , 0 , kX86RegClassGp , 0               , 0              , ""    }, // Abstract.
 | ||||
|   { kVarTypeFp32    , 4 , kX86RegClassFp , kX86RegTypeFp   , F(SP)          , "fp"  }, | ||||
|   { kVarTypeFp64    , 8 , kX86RegClassFp , kX86RegTypeFp   , F(DP)          , "fp"  }, | ||||
|   { kX86VarTypeMm   , 8 , kX86RegClassMm , kX86RegTypeMm   , 0     | F(SIMD), "mm"  }, | ||||
|   { kX86VarTypeK    , 8 , kX86RegClassK  , kX86RegTypeK    , 0              , "k"   }, | ||||
|   { kX86VarTypeXmm  , 16, kX86RegClassXyz, kX86RegTypeXmm  , 0     | F(SIMD), "xmm" }, | ||||
|   { kX86VarTypeXmmSs, 4 , kX86RegClassXyz, kX86RegTypeXmm  , F(SP)          , "xmm" }, | ||||
|   { kX86VarTypeXmmPs, 16, kX86RegClassXyz, kX86RegTypeXmm  , F(SP) | F(SIMD), "xmm" }, | ||||
|   { kX86VarTypeXmmSd, 8 , kX86RegClassXyz, kX86RegTypeXmm  , F(DP)          , "xmm" }, | ||||
|   { kX86VarTypeXmmPd, 16, kX86RegClassXyz, kX86RegTypeXmm  , F(DP) | F(SIMD), "xmm" }, | ||||
|   { kX86VarTypeYmm  , 32, kX86RegClassXyz, kX86RegTypeYmm  , 0     | F(SIMD), "ymm" }, | ||||
|   { kX86VarTypeYmmPs, 32, kX86RegClassXyz, kX86RegTypeYmm  , F(SP) | F(SIMD), "ymm" }, | ||||
|   { kX86VarTypeYmmPd, 32, kX86RegClassXyz, kX86RegTypeYmm  , F(DP) | F(SIMD), "ymm" }, | ||||
|   { kX86VarTypeZmm  , 64, kX86RegClassXyz, kX86RegTypeZmm  , 0     | F(SIMD), "zmm" }, | ||||
|   { kX86VarTypeZmmPs, 64, kX86RegClassXyz, kX86RegTypeZmm  , F(SP) | F(SIMD), "zmm" }, | ||||
|   { kX86VarTypeZmmPd, 64, kX86RegClassXyz, kX86RegTypeZmm  , F(DP) | F(SIMD), "zmm" } | ||||
| }; | ||||
| #undef F | ||||
| 
 | ||||
| #if defined(ASMJIT_BUILD_X86) | ||||
| const uint8_t _x86VarMapping[kX86VarTypeCount] = { | ||||
|   /* 00: kVarTypeInt8     */ kVarTypeInt8, | ||||
|   /* 01: kVarTypeUInt8    */ kVarTypeUInt8, | ||||
|   /* 02: kVarTypeInt16    */ kVarTypeInt16, | ||||
|   /* 03: kVarTypeUInt16   */ kVarTypeUInt16, | ||||
|   /* 04: kVarTypeInt32    */ kVarTypeInt32, | ||||
|   /* 05: kVarTypeUInt32   */ kVarTypeUInt32, | ||||
|   /* 06: kVarTypeInt64    */ kInvalidVar,     // Invalid in 32-bit mode.
 | ||||
|   /* 07: kVarTypeUInt64   */ kInvalidVar,     // Invalid in 32-bit mode.
 | ||||
|   /* 08: kVarTypeIntPtr   */ kVarTypeInt32,   // Remapped to Int32.
 | ||||
|   /* 09: kVarTypeUIntPtr  */ kVarTypeUInt32,  // Remapped to UInt32.
 | ||||
|   /* 10: kVarTypeFp32     */ kVarTypeFp32, | ||||
|   /* 11: kVarTypeFp64     */ kVarTypeFp64, | ||||
|   /* 12: kX86VarTypeMm    */ kX86VarTypeMm, | ||||
|   /* 13: kX86VarTypeK     */ kX86VarTypeK, | ||||
|   /* 14: kX86VarTypeXmm   */ kX86VarTypeXmm, | ||||
|   /* 15: kX86VarTypeXmmSs */ kX86VarTypeXmmSs, | ||||
|   /* 16: kX86VarTypeXmmPs */ kX86VarTypeXmmPs, | ||||
|   /* 17: kX86VarTypeXmmSd */ kX86VarTypeXmmSd, | ||||
|   /* 18: kX86VarTypeXmmPd */ kX86VarTypeXmmPd, | ||||
|   /* 19: kX86VarTypeYmm   */ kX86VarTypeYmm, | ||||
|   /* 20: kX86VarTypeYmmPs */ kX86VarTypeYmmPs, | ||||
|   /* 21: kX86VarTypeYmmPd */ kX86VarTypeYmmPd, | ||||
|   /* 22: kX86VarTypeZmm   */ kX86VarTypeZmm, | ||||
|   /* 23: kX86VarTypeZmmPs */ kX86VarTypeZmmPs, | ||||
|   /* 24: kX86VarTypeZmmPd */ kX86VarTypeZmmPd | ||||
| }; | ||||
| #endif // ASMJIT_BUILD_X86
 | ||||
| 
 | ||||
| #if defined(ASMJIT_BUILD_X64) | ||||
| const uint8_t _x64VarMapping[kX86VarTypeCount] = { | ||||
|   /* 00: kVarTypeInt8     */ kVarTypeInt8, | ||||
|   /* 01: kVarTypeUInt8    */ kVarTypeUInt8, | ||||
|   /* 02: kVarTypeInt16    */ kVarTypeInt16, | ||||
|   /* 03: kVarTypeUInt16   */ kVarTypeUInt16, | ||||
|   /* 04: kVarTypeInt32    */ kVarTypeInt32, | ||||
|   /* 05: kVarTypeUInt32   */ kVarTypeUInt32, | ||||
|   /* 06: kVarTypeInt64    */ kVarTypeInt64, | ||||
|   /* 07: kVarTypeUInt64   */ kVarTypeUInt64, | ||||
|   /* 08: kVarTypeIntPtr   */ kVarTypeInt64,   // Remapped to Int64.
 | ||||
|   /* 09: kVarTypeUIntPtr  */ kVarTypeUInt64,  // Remapped to UInt64.
 | ||||
|   /* 10: kVarTypeFp32     */ kVarTypeFp32, | ||||
|   /* 11: kVarTypeFp64     */ kVarTypeFp64, | ||||
|   /* 12: kX86VarTypeMm    */ kX86VarTypeMm, | ||||
|   /* 13: kX86VarTypeK     */ kX86VarTypeK, | ||||
|   /* 14: kX86VarTypeXmm   */ kX86VarTypeXmm, | ||||
|   /* 15: kX86VarTypeXmmSs */ kX86VarTypeXmmSs, | ||||
|   /* 16: kX86VarTypeXmmPs */ kX86VarTypeXmmPs, | ||||
|   /* 17: kX86VarTypeXmmSd */ kX86VarTypeXmmSd, | ||||
|   /* 18: kX86VarTypeXmmPd */ kX86VarTypeXmmPd, | ||||
|   /* 19: kX86VarTypeYmm   */ kX86VarTypeYmm, | ||||
|   /* 20: kX86VarTypeYmmPs */ kX86VarTypeYmmPs, | ||||
|   /* 21: kX86VarTypeYmmPd */ kX86VarTypeYmmPd, | ||||
|   /* 22: kX86VarTypeZmm   */ kX86VarTypeZmm, | ||||
|   /* 23: kX86VarTypeZmmPs */ kX86VarTypeZmmPs, | ||||
|   /* 24: kX86VarTypeZmmPd */ kX86VarTypeZmmPd | ||||
| }; | ||||
| #endif // ASMJIT_BUILD_X64
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86CallNode - Arg / Ret]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| bool X86CallNode::_setArg(uint32_t i, const Operand& op) noexcept { | ||||
|   if ((i & ~kFuncArgHi) >= _x86Decl.getNumArgs()) | ||||
|     return false; | ||||
| 
 | ||||
|   _args[i] = op; | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool X86CallNode::_setRet(uint32_t i, const Operand& op) noexcept { | ||||
|   if (i >= 2) | ||||
|     return false; | ||||
| 
 | ||||
|   _ret[i] = op; | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86Compiler - Construction / Destruction]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| X86Compiler::X86Compiler(X86Assembler* assembler) noexcept | ||||
|   : Compiler(), | ||||
|     zax(NoInit), | ||||
|     zcx(NoInit), | ||||
|     zdx(NoInit), | ||||
|     zbx(NoInit), | ||||
|     zsp(NoInit), | ||||
|     zbp(NoInit), | ||||
|     zsi(NoInit), | ||||
|     zdi(NoInit) { | ||||
| 
 | ||||
|   _regCount.reset(); | ||||
|   zax = x86::noGpReg; | ||||
|   zcx = x86::noGpReg; | ||||
|   zdx = x86::noGpReg; | ||||
|   zbx = x86::noGpReg; | ||||
|   zsp = x86::noGpReg; | ||||
|   zbp = x86::noGpReg; | ||||
|   zsi = x86::noGpReg; | ||||
|   zdi = x86::noGpReg; | ||||
| 
 | ||||
|   if (assembler != nullptr) | ||||
|     attach(assembler); | ||||
| } | ||||
| 
 | ||||
| X86Compiler::~X86Compiler() noexcept { | ||||
|   reset(true); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86Compiler - Attach / Reset]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error X86Compiler::attach(Assembler* assembler) noexcept { | ||||
|   ASMJIT_ASSERT(assembler != nullptr); | ||||
| 
 | ||||
|   if (_assembler != nullptr) | ||||
|     return kErrorInvalidState; | ||||
| 
 | ||||
|   uint32_t arch = assembler->getArch(); | ||||
|   switch (arch) { | ||||
| #if defined(ASMJIT_BUILD_X86) | ||||
|     case kArchX86: | ||||
|       _targetVarMapping = _x86VarMapping; | ||||
|       break; | ||||
| #endif // ASMJIT_BUILD_X86
 | ||||
| 
 | ||||
| #if defined(ASMJIT_BUILD_X64) | ||||
|     case kArchX64: | ||||
|       _targetVarMapping = _x64VarMapping; | ||||
|       break; | ||||
| #endif // ASMJIT_BUILD_X64
 | ||||
| 
 | ||||
|     default: | ||||
|       return kErrorInvalidArch; | ||||
|   } | ||||
| 
 | ||||
|   assembler->_attached(this); | ||||
| 
 | ||||
|   _arch = static_cast<uint8_t>(arch); | ||||
|   _regSize = static_cast<uint8_t>(assembler->getRegSize()); | ||||
|   _regCount = static_cast<X86Assembler*>(assembler)->getRegCount(); | ||||
|   _finalized = false; | ||||
| 
 | ||||
|   zax = static_cast<X86Assembler*>(assembler)->zax; | ||||
|   zcx = static_cast<X86Assembler*>(assembler)->zcx; | ||||
|   zdx = static_cast<X86Assembler*>(assembler)->zdx; | ||||
|   zbx = static_cast<X86Assembler*>(assembler)->zbx; | ||||
|   zsp = static_cast<X86Assembler*>(assembler)->zsp; | ||||
|   zbp = static_cast<X86Assembler*>(assembler)->zbp; | ||||
|   zsi = static_cast<X86Assembler*>(assembler)->zsi; | ||||
|   zdi = static_cast<X86Assembler*>(assembler)->zdi; | ||||
| 
 | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| void X86Compiler::reset(bool releaseMemory) noexcept { | ||||
|   Compiler::reset(releaseMemory); | ||||
| 
 | ||||
|   _regCount.reset(); | ||||
|   zax = x86::noGpReg; | ||||
|   zcx = x86::noGpReg; | ||||
|   zdx = x86::noGpReg; | ||||
|   zbx = x86::noGpReg; | ||||
|   zsp = x86::noGpReg; | ||||
|   zbp = x86::noGpReg; | ||||
|   zsi = x86::noGpReg; | ||||
|   zdi = x86::noGpReg; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86Compiler - Finalize]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error X86Compiler::finalize() noexcept { | ||||
|   X86Assembler* assembler = getAssembler(); | ||||
|   if (assembler == nullptr) | ||||
|     return kErrorOk; | ||||
| 
 | ||||
|   // Flush the global constant pool.
 | ||||
|   if (_globalConstPoolLabel.isInitialized()) { | ||||
|     embedConstPool(_globalConstPoolLabel, _globalConstPool); | ||||
| 
 | ||||
|     _globalConstPoolLabel.reset(); | ||||
|     _globalConstPool.reset(); | ||||
|   } | ||||
| 
 | ||||
|   if (_firstNode == nullptr) | ||||
|     return kErrorOk; | ||||
| 
 | ||||
|   X86Context context(this); | ||||
|   Error error = kErrorOk; | ||||
| 
 | ||||
|   HLNode* node = _firstNode; | ||||
|   HLNode* start; | ||||
| 
 | ||||
|   // Find all functions and use the `X86Context` to translate/emit them.
 | ||||
|   do { | ||||
|     start = node; | ||||
|     _resetTokenGenerator(); | ||||
| 
 | ||||
|     if (node->getType() == HLNode::kTypeFunc) { | ||||
|       node = static_cast<X86FuncNode*>(start)->getEnd(); | ||||
|       error = context.compile(static_cast<X86FuncNode*>(start)); | ||||
| 
 | ||||
|       if (error != kErrorOk) | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     do { | ||||
|       node = node->getNext(); | ||||
|     } while (node != nullptr && node->getType() != HLNode::kTypeFunc); | ||||
| 
 | ||||
|     error = context.serialize(assembler, start, node); | ||||
|     context.cleanup(); | ||||
|     context.reset(false); | ||||
| 
 | ||||
|     if (error != kErrorOk) | ||||
|       break; | ||||
|   } while (node != nullptr); | ||||
| 
 | ||||
|   reset(false); | ||||
|   return error; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86Compiler - Inst]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! Get compiler instruction item size without operands assigned.
 | ||||
| static ASMJIT_INLINE size_t X86Compiler_getInstSize(uint32_t code) noexcept { | ||||
|   return Utils::inInterval<uint32_t>(code, _kX86InstIdJbegin, _kX86InstIdJend) ? sizeof(HLJump) : sizeof(HLInst); | ||||
| } | ||||
| 
 | ||||
| static HLInst* X86Compiler_newInst(X86Compiler* self, void* p, uint32_t code, uint32_t options, Operand* opList, uint32_t opCount) noexcept { | ||||
|   if (Utils::inInterval<uint32_t>(code, _kX86InstIdJbegin, _kX86InstIdJend)) { | ||||
|     HLJump* node = new(p) HLJump(self, code, options, opList, opCount); | ||||
|     HLLabel* jTarget = nullptr; | ||||
| 
 | ||||
|     if ((options & kInstOptionUnfollow) == 0) { | ||||
|       if (opList[0].isLabel()) | ||||
|         jTarget = self->getHLLabel(static_cast<Label&>(opList[0])); | ||||
|       else | ||||
|         options |= kInstOptionUnfollow; | ||||
|     } | ||||
| 
 | ||||
|     node->orFlags(code == kX86InstIdJmp ? HLNode::kFlagIsJmp | HLNode::kFlagIsTaken : HLNode::kFlagIsJcc); | ||||
|     node->_target = jTarget; | ||||
|     node->_jumpNext = nullptr; | ||||
| 
 | ||||
|     if (jTarget) { | ||||
|       node->_jumpNext = static_cast<HLJump*>(jTarget->_from); | ||||
|       jTarget->_from = node; | ||||
|       jTarget->addNumRefs(); | ||||
|     } | ||||
| 
 | ||||
|     // The 'jmp' is always taken, conditional jump can contain hint, we detect it.
 | ||||
|     if (code == kX86InstIdJmp) | ||||
|       node->orFlags(HLNode::kFlagIsTaken); | ||||
|     else if (options & kInstOptionTaken) | ||||
|       node->orFlags(HLNode::kFlagIsTaken); | ||||
| 
 | ||||
|     node->addOptions(options); | ||||
|     return node; | ||||
|   } | ||||
|   else { | ||||
|     HLInst* node = new(p) HLInst(self, code, options, opList, opCount); | ||||
|     node->addOptions(options); | ||||
|     return node; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::newInst(uint32_t code) noexcept { | ||||
|   size_t size = X86Compiler_getInstSize(code); | ||||
|   HLInst* inst = static_cast<HLInst*>(_zoneAllocator.alloc(size)); | ||||
| 
 | ||||
|   if (inst == nullptr) | ||||
|     goto _NoMemory; | ||||
| 
 | ||||
|   return X86Compiler_newInst(this, inst, code, getInstOptionsAndReset(), nullptr, 0); | ||||
| 
 | ||||
| _NoMemory: | ||||
|   setLastError(kErrorNoHeapMemory); | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::newInst(uint32_t code, const Operand& o0) noexcept { | ||||
|   size_t size = X86Compiler_getInstSize(code); | ||||
|   HLInst* inst = static_cast<HLInst*>(_zoneAllocator.alloc(size + 1 * sizeof(Operand))); | ||||
| 
 | ||||
|   if (inst == nullptr) | ||||
|     goto _NoMemory; | ||||
| 
 | ||||
|   { | ||||
|     Operand* opList = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(inst) + size); | ||||
|     opList[0] = o0; | ||||
|     ASMJIT_ASSERT_OPERAND(o0); | ||||
|     return X86Compiler_newInst(this, inst, code, getInstOptionsAndReset(), opList, 1); | ||||
|   } | ||||
| 
 | ||||
| _NoMemory: | ||||
|   setLastError(kErrorNoHeapMemory); | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::newInst(uint32_t code, const Operand& o0, const Operand& o1) noexcept { | ||||
|   size_t size = X86Compiler_getInstSize(code); | ||||
|   HLInst* inst = static_cast<HLInst*>(_zoneAllocator.alloc(size + 2 * sizeof(Operand))); | ||||
| 
 | ||||
|   if (inst == nullptr) | ||||
|     goto _NoMemory; | ||||
| 
 | ||||
|   { | ||||
|     Operand* opList = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(inst) + size); | ||||
|     opList[0] = o0; | ||||
|     opList[1] = o1; | ||||
|     ASMJIT_ASSERT_OPERAND(o0); | ||||
|     ASMJIT_ASSERT_OPERAND(o1); | ||||
|     return X86Compiler_newInst(this, inst, code, getInstOptionsAndReset(), opList, 2); | ||||
|   } | ||||
| 
 | ||||
| _NoMemory: | ||||
|   setLastError(kErrorNoHeapMemory); | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::newInst(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2) noexcept { | ||||
|   size_t size = X86Compiler_getInstSize(code); | ||||
|   HLInst* inst = static_cast<HLInst*>(_zoneAllocator.alloc(size + 3 * sizeof(Operand))); | ||||
| 
 | ||||
|   if (inst == nullptr) | ||||
|     goto _NoMemory; | ||||
| 
 | ||||
|   { | ||||
|     Operand* opList = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(inst) + size); | ||||
|     opList[0] = o0; | ||||
|     opList[1] = o1; | ||||
|     opList[2] = o2; | ||||
|     ASMJIT_ASSERT_OPERAND(o0); | ||||
|     ASMJIT_ASSERT_OPERAND(o1); | ||||
|     ASMJIT_ASSERT_OPERAND(o2); | ||||
|     return X86Compiler_newInst(this, inst, code, getInstOptionsAndReset(), opList, 3); | ||||
|   } | ||||
| 
 | ||||
| _NoMemory: | ||||
|   setLastError(kErrorNoHeapMemory); | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::newInst(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) noexcept { | ||||
|   size_t size = X86Compiler_getInstSize(code); | ||||
|   HLInst* inst = static_cast<HLInst*>(_zoneAllocator.alloc(size + 4 * sizeof(Operand))); | ||||
| 
 | ||||
|   if (inst == nullptr) | ||||
|     goto _NoMemory; | ||||
| 
 | ||||
|   { | ||||
|     Operand* opList = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(inst) + size); | ||||
|     opList[0] = o0; | ||||
|     opList[1] = o1; | ||||
|     opList[2] = o2; | ||||
|     opList[3] = o3; | ||||
|     ASMJIT_ASSERT_OPERAND(o0); | ||||
|     ASMJIT_ASSERT_OPERAND(o1); | ||||
|     ASMJIT_ASSERT_OPERAND(o2); | ||||
|     ASMJIT_ASSERT_OPERAND(o3); | ||||
|     return X86Compiler_newInst(this, inst, code, getInstOptionsAndReset(), opList, 4); | ||||
|   } | ||||
| 
 | ||||
| _NoMemory: | ||||
|   setLastError(kErrorNoHeapMemory); | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::newInst(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3, const Operand& o4) noexcept { | ||||
|   size_t size = X86Compiler_getInstSize(code); | ||||
|   HLInst* inst = static_cast<HLInst*>(_zoneAllocator.alloc(size + 5 * sizeof(Operand))); | ||||
| 
 | ||||
|   if (inst == nullptr) | ||||
|     goto _NoMemory; | ||||
| 
 | ||||
|   { | ||||
|     Operand* opList = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(inst) + size); | ||||
|     opList[0] = o0; | ||||
|     opList[1] = o1; | ||||
|     opList[2] = o2; | ||||
|     opList[3] = o3; | ||||
|     opList[4] = o4; | ||||
|     ASMJIT_ASSERT_OPERAND(o0); | ||||
|     ASMJIT_ASSERT_OPERAND(o1); | ||||
|     ASMJIT_ASSERT_OPERAND(o2); | ||||
|     ASMJIT_ASSERT_OPERAND(o3); | ||||
|     ASMJIT_ASSERT_OPERAND(o4); | ||||
|     return X86Compiler_newInst(this, inst, code, getInstOptionsAndReset(), opList, 5); | ||||
|   } | ||||
| 
 | ||||
| _NoMemory: | ||||
|   setLastError(kErrorNoHeapMemory); | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::emit(uint32_t code) noexcept { | ||||
|   HLInst* node = newInst(code); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<HLInst*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::emit(uint32_t code, const Operand& o0) noexcept { | ||||
|   HLInst* node = newInst(code, o0); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<HLInst*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::emit(uint32_t code, const Operand& o0, const Operand& o1) noexcept { | ||||
|   HLInst* node = newInst(code, o0, o1); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<HLInst*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2) noexcept { | ||||
|   HLInst* node = newInst(code, o0, o1, o2); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<HLInst*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) noexcept { | ||||
|   HLInst* node = newInst(code, o0, o1, o2, o3); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<HLInst*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3, const Operand& o4) noexcept { | ||||
|   HLInst* node = newInst(code, o0, o1, o2, o3, o4); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<HLInst*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::emit(uint32_t code, int o0_) noexcept { | ||||
|   Imm o0(o0_); | ||||
|   HLInst* node = newInst(code, o0); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<HLInst*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::emit(uint32_t code, uint64_t o0_) noexcept { | ||||
|   Imm o0(o0_); | ||||
|   HLInst* node = newInst(code, o0); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<HLInst*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::emit(uint32_t code, const Operand& o0, int o1_) noexcept { | ||||
|   Imm o1(o1_); | ||||
|   HLInst* node = newInst(code, o0, o1); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<HLInst*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::emit(uint32_t code, const Operand& o0, uint64_t o1_) noexcept { | ||||
|   Imm o1(o1_); | ||||
|   HLInst* node = newInst(code, o0, o1); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<HLInst*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::emit(uint32_t code, const Operand& o0, const Operand& o1, int o2_) noexcept { | ||||
|   Imm o2(o2_); | ||||
|   HLInst* node = newInst(code, o0, o1, o2); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<HLInst*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::emit(uint32_t code, const Operand& o0, const Operand& o1, uint64_t o2_) noexcept { | ||||
|   Imm o2(o2_); | ||||
|   HLInst* node = newInst(code, o0, o1, o2); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<HLInst*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int o3_) noexcept { | ||||
|   Imm o3(o3_); | ||||
|   HLInst* node = newInst(code, o0, o1, o2, o3); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<HLInst*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| HLInst* X86Compiler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, uint64_t o3_) noexcept { | ||||
|   Imm o3(o3_); | ||||
|   HLInst* node = newInst(code, o0, o1, o2, o3); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<HLInst*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86Compiler - Func]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| X86FuncNode* X86Compiler::newFunc(const FuncPrototype& p) noexcept { | ||||
|   X86FuncNode* func = newNode<X86FuncNode>(); | ||||
|   Error error; | ||||
| 
 | ||||
|   if (func == nullptr) | ||||
|     goto _NoMemory; | ||||
| 
 | ||||
|   // Create helper nodes.
 | ||||
|   func->_entryNode = newLabelNode(); | ||||
|   func->_exitNode = newLabelNode(); | ||||
|   func->_end = newNode<HLSentinel>(); | ||||
| 
 | ||||
|   if (func->_entryNode == nullptr || func->_exitNode == nullptr || func->_end == nullptr) | ||||
|     goto _NoMemory; | ||||
| 
 | ||||
|   // Function prototype.
 | ||||
|   if ((error = func->_x86Decl.setPrototype(p)) != kErrorOk) { | ||||
|     setLastError(error); | ||||
|     return nullptr; | ||||
|   } | ||||
| 
 | ||||
|   // Function arguments stack size. Since function requires _argStackSize to be
 | ||||
|   // set, we have to copy it from X86FuncDecl.
 | ||||
|   func->_argStackSize = func->_x86Decl.getArgStackSize(); | ||||
|   func->_redZoneSize = static_cast<uint16_t>(func->_x86Decl.getRedZoneSize()); | ||||
|   func->_spillZoneSize = static_cast<uint16_t>(func->_x86Decl.getSpillZoneSize()); | ||||
| 
 | ||||
|   // Expected/Required stack alignment.
 | ||||
|   func->_expectedStackAlignment = getRuntime()->getStackAlignment(); | ||||
|   func->_requiredStackAlignment = 0; | ||||
| 
 | ||||
|   // Allocate space for function arguments.
 | ||||
|   func->_args = nullptr; | ||||
|   if (func->getNumArgs() != 0) { | ||||
|     func->_args = _zoneAllocator.allocT<VarData*>(func->getNumArgs() * sizeof(VarData*)); | ||||
|     if (func->_args == nullptr) | ||||
|       goto _NoMemory; | ||||
|     ::memset(func->_args, 0, func->getNumArgs() * sizeof(VarData*)); | ||||
|   } | ||||
| 
 | ||||
|   return func; | ||||
| 
 | ||||
| _NoMemory: | ||||
|   setLastError(kErrorNoHeapMemory); | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| X86FuncNode* X86Compiler::addFunc(const FuncPrototype& p) noexcept { | ||||
|   X86FuncNode* func = newFunc(p); | ||||
| 
 | ||||
|   if (func == nullptr) { | ||||
|     setLastError(kErrorNoHeapMemory); | ||||
|     return nullptr; | ||||
|   } | ||||
| 
 | ||||
|   return static_cast<X86FuncNode*>(addFunc(func)); | ||||
| } | ||||
| 
 | ||||
| HLSentinel* X86Compiler::endFunc() noexcept { | ||||
|   X86FuncNode* func = getFunc(); | ||||
|   ASMJIT_ASSERT(func != nullptr); | ||||
| 
 | ||||
|   // Add local constant pool at the end of the function (if exist).
 | ||||
|   setCursor(func->getExitNode()); | ||||
| 
 | ||||
|   if (_localConstPoolLabel.isInitialized()) { | ||||
|     embedConstPool(_localConstPoolLabel, _localConstPool); | ||||
|     _localConstPoolLabel.reset(); | ||||
|     _localConstPool.reset(); | ||||
|   } | ||||
| 
 | ||||
|   // Finalize.
 | ||||
|   func->addFuncFlags(kFuncFlagIsFinished); | ||||
|   _func = nullptr; | ||||
| 
 | ||||
|   setCursor(func->getEnd()); | ||||
|   return func->getEnd(); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86Compiler - Ret]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| HLRet* X86Compiler::newRet(const Operand& o0, const Operand& o1) noexcept { | ||||
|   HLRet* node = newNode<HLRet>(o0, o1); | ||||
|   if (node == nullptr) | ||||
|     goto _NoMemory; | ||||
|   return node; | ||||
| 
 | ||||
| _NoMemory: | ||||
|   setLastError(kErrorNoHeapMemory); | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| HLRet* X86Compiler::addRet(const Operand& o0, const Operand& o1) noexcept { | ||||
|   HLRet* node = newRet(o0, o1); | ||||
|   if (node == nullptr) | ||||
|     return node; | ||||
|   return static_cast<HLRet*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86Compiler - Call]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| X86CallNode* X86Compiler::newCall(const Operand& o0, const FuncPrototype& p) noexcept { | ||||
|   X86CallNode* node = newNode<X86CallNode>(o0); | ||||
|   Error error; | ||||
|   uint32_t nArgs; | ||||
| 
 | ||||
|   if (node == nullptr) | ||||
|     goto _NoMemory; | ||||
| 
 | ||||
|   if ((error = node->_x86Decl.setPrototype(p)) != kErrorOk) { | ||||
|     setLastError(error); | ||||
|     return nullptr; | ||||
|   } | ||||
| 
 | ||||
|   // If there are no arguments skip the allocation.
 | ||||
|   if ((nArgs = p.getNumArgs()) == 0) | ||||
|     return node; | ||||
| 
 | ||||
|   node->_args = static_cast<Operand*>(_zoneAllocator.alloc(nArgs * sizeof(Operand))); | ||||
|   if (node->_args == nullptr) | ||||
|     goto _NoMemory; | ||||
| 
 | ||||
|   ::memset(node->_args, 0, nArgs * sizeof(Operand)); | ||||
|   return node; | ||||
| 
 | ||||
| _NoMemory: | ||||
|   setLastError(kErrorNoHeapMemory); | ||||
|   return nullptr; | ||||
| } | ||||
| 
 | ||||
| X86CallNode* X86Compiler::addCall(const Operand& o0, const FuncPrototype& p) noexcept { | ||||
|   X86CallNode* node = newCall(o0, p); | ||||
|   if (node == nullptr) | ||||
|     return nullptr; | ||||
|   return static_cast<X86CallNode*>(addNode(node)); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86Compiler - Vars]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error X86Compiler::setArg(uint32_t argIndex, const Var& var) noexcept { | ||||
|   X86FuncNode* func = getFunc(); | ||||
| 
 | ||||
|   if (func == nullptr) | ||||
|     return kErrorInvalidArgument; | ||||
| 
 | ||||
|   if (!isVarValid(var)) | ||||
|     return kErrorInvalidState; | ||||
| 
 | ||||
|   VarData* vd = getVd(var); | ||||
|   func->setArg(argIndex, vd); | ||||
| 
 | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| Error X86Compiler::_newVar(Var* var, uint32_t vType, const char* name) noexcept { | ||||
|   ASMJIT_ASSERT(vType < kX86VarTypeCount); | ||||
|   vType = _targetVarMapping[vType]; | ||||
|   ASMJIT_ASSERT(vType != kInvalidVar); | ||||
| 
 | ||||
|   // The assertion won't be compiled in release build, however, we want to check
 | ||||
|   // this anyway.
 | ||||
|   if (vType == kInvalidVar) { | ||||
|     static_cast<X86Var*>(var)->reset(); | ||||
|     return kErrorInvalidArgument; | ||||
|   } | ||||
| 
 | ||||
|   const VarInfo& vInfo = _x86VarInfo[vType]; | ||||
|   VarData* vd = _newVd(vInfo, name); | ||||
| 
 | ||||
|   if (vd == nullptr) { | ||||
|     static_cast<X86Var*>(var)->reset(); | ||||
|     return getLastError(); | ||||
|   } | ||||
| 
 | ||||
|   var->_init_packed_op_sz_w0_id(Operand::kTypeVar, vInfo.getSize(), vInfo.getRegType() << 8, vd->getId()); | ||||
|   var->_vreg.vType = vType; | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| Error X86Compiler::_newVar(Var* var, uint32_t vType, const char* fmt, va_list ap) noexcept { | ||||
|   char name[64]; | ||||
| 
 | ||||
|   vsnprintf(name, ASMJIT_ARRAY_SIZE(name), fmt, ap); | ||||
|   name[ASMJIT_ARRAY_SIZE(name) - 1] = '\0'; | ||||
|   return _newVar(var, vType, name); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86Compiler - Stack]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error X86Compiler::_newStack(BaseMem* mem, uint32_t size, uint32_t alignment, const char* name) noexcept { | ||||
|   if (size == 0) | ||||
|     return kErrorInvalidArgument; | ||||
| 
 | ||||
|   if (alignment > 64) | ||||
|     alignment = 64; | ||||
| 
 | ||||
|   VarInfo vi = { kInvalidVar, 0, kInvalidReg , kInvalidReg, 0, "" }; | ||||
|   VarData* vd = _newVd(vi, name); | ||||
| 
 | ||||
|   if (vd == nullptr) { | ||||
|     static_cast<X86Mem*>(mem)->reset(); | ||||
|     return getLastError(); | ||||
|   } | ||||
| 
 | ||||
|   vd->_size = size; | ||||
|   vd->_isStack = true; | ||||
|   vd->_alignment = static_cast<uint8_t>(alignment); | ||||
| 
 | ||||
|   static_cast<X86Mem*>(mem)->_init(kMemTypeStackIndex, vd->getId(), 0, 0); | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86Compiler - Const]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| Error X86Compiler::_newConst(BaseMem* mem, uint32_t scope, const void* data, size_t size) noexcept { | ||||
|   Error error = kErrorOk; | ||||
|   size_t offset; | ||||
| 
 | ||||
|   Label* dstLabel; | ||||
|   ConstPool* dstPool; | ||||
| 
 | ||||
|   if (scope == kConstScopeLocal) { | ||||
|     dstLabel = &_localConstPoolLabel; | ||||
|     dstPool = &_localConstPool; | ||||
|   } | ||||
|   else if (scope == kConstScopeGlobal) { | ||||
|     dstLabel = &_globalConstPoolLabel; | ||||
|     dstPool = &_globalConstPool; | ||||
|   } | ||||
|   else { | ||||
|     error = kErrorInvalidArgument; | ||||
|     goto _OnError; | ||||
|   } | ||||
| 
 | ||||
|   error = dstPool->add(data, size, offset); | ||||
|   if (error != kErrorOk) | ||||
|     goto _OnError; | ||||
| 
 | ||||
|   if (dstLabel->getId() == kInvalidValue) { | ||||
|     *dstLabel = newLabel(); | ||||
|     if (!dstLabel->isInitialized()) { | ||||
|       error = kErrorNoHeapMemory; | ||||
|       goto _OnError; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   *static_cast<X86Mem*>(mem) = x86::ptr(*dstLabel, static_cast<int32_t>(offset), static_cast<uint32_t>(size)); | ||||
|   return kErrorOk; | ||||
| 
 | ||||
| _OnError: | ||||
|   return error; | ||||
| } | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // !ASMJIT_DISABLE_COMPILER && (ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64)
 | ||||
							
								
								
									
										7496
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86compiler.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7496
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86compiler.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										5921
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86compilercontext.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5921
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86compilercontext.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										726
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86compilercontext_p.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										726
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86compilercontext_p.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,726 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_X86_X86COMPILERCONTEXT_P_H | ||||
| #define _ASMJIT_X86_X86COMPILERCONTEXT_P_H | ||||
| 
 | ||||
| #include "../build.h" | ||||
| #if !defined(ASMJIT_DISABLE_COMPILER) | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/compiler.h" | ||||
| #include "../base/compilercontext_p.h" | ||||
| #include "../base/utils.h" | ||||
| #include "../x86/x86assembler.h" | ||||
| #include "../x86/x86compiler.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| //! \addtogroup asmjit_x86
 | ||||
| //! \{
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86VarMap]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| struct X86VarMap : public VarMap { | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get variable-attributes list as VarAttr data.
 | ||||
|   ASMJIT_INLINE VarAttr* getVaList() const { | ||||
|     return const_cast<VarAttr*>(_list); | ||||
|   } | ||||
| 
 | ||||
|   //! Get variable-attributes list as VarAttr data (by class).
 | ||||
|   ASMJIT_INLINE VarAttr* getVaListByClass(uint32_t rc) const { | ||||
|     return const_cast<VarAttr*>(_list) + _start.get(rc); | ||||
|   } | ||||
| 
 | ||||
|   //! Get position of variables (by class).
 | ||||
|   ASMJIT_INLINE uint32_t getVaStart(uint32_t rc) const { | ||||
|     return _start.get(rc); | ||||
|   } | ||||
| 
 | ||||
|   //! Get count of variables (by class).
 | ||||
|   ASMJIT_INLINE uint32_t getVaCountByClass(uint32_t rc) const { | ||||
|     return _count.get(rc); | ||||
|   } | ||||
| 
 | ||||
|   //! Get VarAttr at `index`.
 | ||||
|   ASMJIT_INLINE VarAttr* getVa(uint32_t index) const { | ||||
|     ASMJIT_ASSERT(index < _vaCount); | ||||
|     return getVaList() + index; | ||||
|   } | ||||
| 
 | ||||
|   //! Get VarAttr of `c` class at `index`.
 | ||||
|   ASMJIT_INLINE VarAttr* getVaByClass(uint32_t rc, uint32_t index) const { | ||||
|     ASMJIT_ASSERT(index < _count._regs[rc]); | ||||
|     return getVaListByClass(rc) + index; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Utils]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Find VarAttr.
 | ||||
|   ASMJIT_INLINE VarAttr* findVa(VarData* vd) const { | ||||
|     VarAttr* list = getVaList(); | ||||
|     uint32_t count = getVaCount(); | ||||
| 
 | ||||
|     for (uint32_t i = 0; i < count; i++) | ||||
|       if (list[i].getVd() == vd) | ||||
|         return &list[i]; | ||||
| 
 | ||||
|     return nullptr; | ||||
|   } | ||||
| 
 | ||||
|   //! Find VarAttr (by class).
 | ||||
|   ASMJIT_INLINE VarAttr* findVaByClass(uint32_t rc, VarData* vd) const { | ||||
|     VarAttr* list = getVaListByClass(rc); | ||||
|     uint32_t count = getVaCountByClass(rc); | ||||
| 
 | ||||
|     for (uint32_t i = 0; i < count; i++) | ||||
|       if (list[i].getVd() == vd) | ||||
|         return &list[i]; | ||||
| 
 | ||||
|     return nullptr; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Special registers on input.
 | ||||
|   //!
 | ||||
|   //! Special register(s) restricted to one or more physical register. If there
 | ||||
|   //! is more than one special register it means that we have to duplicate the
 | ||||
|   //! variable content to all of them (it means that the same varible was used
 | ||||
|   //! by two or more operands). We forget about duplicates after the register
 | ||||
|   //! allocation finishes and marks all duplicates as non-assigned.
 | ||||
|   X86RegMask _inRegs; | ||||
| 
 | ||||
|   //! Special registers on output.
 | ||||
|   //!
 | ||||
|   //! Special register(s) used on output. Each variable can have only one
 | ||||
|   //! special register on the output, 'X86VarMap' contains all registers from
 | ||||
|   //! all 'VarAttr's.
 | ||||
|   X86RegMask _outRegs; | ||||
| 
 | ||||
|   //! Clobbered registers (by a function call).
 | ||||
|   X86RegMask _clobberedRegs; | ||||
| 
 | ||||
|   //! Start indexes of variables per register class.
 | ||||
|   X86RegCount _start; | ||||
|   //! Count of variables per register class.
 | ||||
|   X86RegCount _count; | ||||
| 
 | ||||
|   //! VarAttr list.
 | ||||
|   VarAttr _list[1]; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86StateCell]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! X86/X64 state-cell.
 | ||||
| union X86StateCell { | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE uint32_t getState() const { | ||||
|     return _state; | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE void setState(uint32_t state) { | ||||
|     _state = static_cast<uint8_t>(state); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Reset]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE void reset() { _packed = 0; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   uint8_t _packed; | ||||
| 
 | ||||
|   struct { | ||||
|     uint8_t _state : 2; | ||||
|     uint8_t _unused : 6; | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86VarState]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! X86/X64 state.
 | ||||
| struct X86VarState : VarState { | ||||
|   enum { | ||||
|     //! Base index of GP registers.
 | ||||
|     kGpIndex = 0, | ||||
|     //! Count of GP registers.
 | ||||
|     kGpCount = 16, | ||||
| 
 | ||||
|     //! Base index of MMX registers.
 | ||||
|     kMmIndex = kGpIndex + kGpCount, | ||||
|     //! Count of Mm registers.
 | ||||
|     kMmCount = 8, | ||||
| 
 | ||||
|     //! Base index of XMM registers.
 | ||||
|     kXmmIndex = kMmIndex + kMmCount, | ||||
|     //! Count of XMM registers.
 | ||||
|     kXmmCount = 16, | ||||
| 
 | ||||
|     //! Count of all registers in `X86VarState`.
 | ||||
|     kAllCount = kXmmIndex + kXmmCount | ||||
|   }; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE VarData** getList() { | ||||
|     return _list; | ||||
|   } | ||||
| 
 | ||||
|   ASMJIT_INLINE VarData** getListByClass(uint32_t rc) { | ||||
|     switch (rc) { | ||||
|       case kX86RegClassGp : return _listGp; | ||||
|       case kX86RegClassMm : return _listMm; | ||||
|       case kX86RegClassXyz: return _listXmm; | ||||
| 
 | ||||
|       default: | ||||
|         return nullptr; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Clear]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE void reset(size_t numCells) { | ||||
|     ::memset(this, 0, kAllCount * sizeof(VarData*) + | ||||
|                       2         * sizeof(X86RegMask) + | ||||
|                       numCells  * sizeof(X86StateCell)); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   union { | ||||
|     //! List of all allocated variables in one array.
 | ||||
|     VarData* _list[kAllCount]; | ||||
| 
 | ||||
|     struct { | ||||
|       //! Allocated GP registers.
 | ||||
|       VarData* _listGp[kGpCount]; | ||||
|       //! Allocated MMX registers.
 | ||||
|       VarData* _listMm[kMmCount]; | ||||
|       //! Allocated XMM registers.
 | ||||
|       VarData* _listXmm[kXmmCount]; | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   //! Occupied registers (mask).
 | ||||
|   X86RegMask _occupied; | ||||
|   //! Modified registers (mask).
 | ||||
|   X86RegMask _modified; | ||||
| 
 | ||||
|   //! Variables data, the length is stored in `X86Context`.
 | ||||
|   X86StateCell _cells[1]; | ||||
| }; | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86Context]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #if defined(ASMJIT_DEBUG) | ||||
| # define ASMJIT_X86_CHECK_STATE _checkState(); | ||||
| #else | ||||
| # define ASMJIT_X86_CHECK_STATE | ||||
| #endif // ASMJIT_DEBUG
 | ||||
| 
 | ||||
| //! \internal
 | ||||
| //!
 | ||||
| //! Compiler context, used by `X86Compiler`.
 | ||||
| //!
 | ||||
| //! Compiler context takes care of generating function prolog and epilog, and
 | ||||
| //! also performs register allocation. It's used during the compilation phase
 | ||||
| //! and considered an implementation detail and asmjit consumers don't have
 | ||||
| //! access to it. The context is used once per function and it's reset after
 | ||||
| //! the function is processed.
 | ||||
| struct X86Context : public Context { | ||||
|   ASMJIT_NO_COPY(X86Context) | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Create a new `X86Context` instance.
 | ||||
|   X86Context(X86Compiler* compiler); | ||||
|   //! Destroy the `X86Context` instance.
 | ||||
|   virtual ~X86Context(); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Reset]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   virtual void reset(bool releaseMemory = false) override; | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Arch]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE bool isX64() const { return _zsp.getSize() == 16; } | ||||
|   ASMJIT_INLINE uint32_t getRegSize() const { return _zsp.getSize(); } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get compiler as `X86Compiler`.
 | ||||
|   ASMJIT_INLINE X86Compiler* getCompiler() const { return static_cast<X86Compiler*>(_compiler); } | ||||
|   //! Get function as `X86FuncNode`.
 | ||||
|   ASMJIT_INLINE X86FuncNode* getFunc() const { return reinterpret_cast<X86FuncNode*>(_func); } | ||||
|   //! Get clobbered registers (global).
 | ||||
|   ASMJIT_INLINE uint32_t getClobberedRegs(uint32_t rc) { return _clobberedRegs.get(rc); } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Helpers]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE X86VarMap* newVarMap(uint32_t vaCount) { | ||||
|     return static_cast<X86VarMap*>( | ||||
|       _zoneAllocator.alloc(sizeof(X86VarMap) + vaCount * sizeof(VarAttr))); | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Emit]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   void emitLoad(VarData* vd, uint32_t regIndex, const char* reason); | ||||
|   void emitSave(VarData* vd, uint32_t regIndex, const char* reason); | ||||
|   void emitMove(VarData* vd, uint32_t toRegIndex, uint32_t fromRegIndex, const char* reason); | ||||
|   void emitSwapGp(VarData* aVd, VarData* bVd, uint32_t aIndex, uint32_t bIndex, const char* reason); | ||||
| 
 | ||||
|   void emitPushSequence(uint32_t regs); | ||||
|   void emitPopSequence(uint32_t regs); | ||||
| 
 | ||||
|   void emitConvertVarToVar(uint32_t dstType, uint32_t dstIndex, uint32_t srcType, uint32_t srcIndex); | ||||
|   void emitMoveVarOnStack(uint32_t dstType, const X86Mem* dst, uint32_t srcType, uint32_t srcIndex); | ||||
|   void emitMoveImmOnStack(uint32_t dstType, const X86Mem* dst, const Imm* src); | ||||
| 
 | ||||
|   void emitMoveImmToReg(uint32_t dstType, uint32_t dstIndex, const Imm* src); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Register Management]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   void _checkState(); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Attach / Detach]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Attach.
 | ||||
|   //!
 | ||||
|   //! Attach a register to the 'VarData', changing 'VarData' members to show
 | ||||
|   //! that the variable is currently alive and linking variable with the
 | ||||
|   //! current 'X86VarState'.
 | ||||
|   template<int C> | ||||
|   ASMJIT_INLINE void attach(VarData* vd, uint32_t regIndex, bool modified) { | ||||
|     ASMJIT_ASSERT(vd->getClass() == C); | ||||
|     ASMJIT_ASSERT(regIndex != kInvalidReg); | ||||
| 
 | ||||
|     // Prevent Esp allocation if C==Gp.
 | ||||
|     ASMJIT_ASSERT(C != kX86RegClassGp || regIndex != kX86RegIndexSp); | ||||
| 
 | ||||
|     uint32_t regMask = Utils::mask(regIndex); | ||||
| 
 | ||||
|     vd->setState(kVarStateReg); | ||||
|     vd->setModified(modified); | ||||
|     vd->setRegIndex(regIndex); | ||||
|     vd->addHomeIndex(regIndex); | ||||
| 
 | ||||
|     _x86State.getListByClass(C)[regIndex] = vd; | ||||
|     _x86State._occupied.or_(C, regMask); | ||||
|     _x86State._modified.or_(C, static_cast<uint32_t>(modified) << regIndex); | ||||
| 
 | ||||
|     ASMJIT_X86_CHECK_STATE | ||||
|   } | ||||
| 
 | ||||
|   //! Detach.
 | ||||
|   //!
 | ||||
|   //! The opposite of 'Attach'. Detach resets the members in 'VarData'
 | ||||
|   //! (regIndex, state and changed flags) and unlinks the variable with the
 | ||||
|   //! current 'X86VarState'.
 | ||||
|   template<int C> | ||||
|   ASMJIT_INLINE void detach(VarData* vd, uint32_t regIndex, uint32_t vState) { | ||||
|     ASMJIT_ASSERT(vd->getClass() == C); | ||||
|     ASMJIT_ASSERT(vd->getRegIndex() == regIndex); | ||||
|     ASMJIT_ASSERT(vState != kVarStateReg); | ||||
| 
 | ||||
|     uint32_t regMask = Utils::mask(regIndex); | ||||
| 
 | ||||
|     vd->setState(vState); | ||||
|     vd->resetRegIndex(); | ||||
|     vd->setModified(false); | ||||
| 
 | ||||
|     _x86State.getListByClass(C)[regIndex] = nullptr; | ||||
|     _x86State._occupied.andNot(C, regMask); | ||||
|     _x86State._modified.andNot(C, regMask); | ||||
| 
 | ||||
|     ASMJIT_X86_CHECK_STATE | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Rebase]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Rebase.
 | ||||
|   //!
 | ||||
|   //! Change the register of the 'VarData' changing also the current 'X86VarState'.
 | ||||
|   //! Rebase is nearly identical to 'Detach' and 'Attach' sequence, but doesn't
 | ||||
|   //! change the `VarData`s modified flag.
 | ||||
|   template<int C> | ||||
|   ASMJIT_INLINE void rebase(VarData* vd, uint32_t newRegIndex, uint32_t oldRegIndex) { | ||||
|     ASMJIT_ASSERT(vd->getClass() == C); | ||||
| 
 | ||||
|     uint32_t newRegMask = Utils::mask(newRegIndex); | ||||
|     uint32_t oldRegMask = Utils::mask(oldRegIndex); | ||||
|     uint32_t bothRegMask = newRegMask ^ oldRegMask; | ||||
| 
 | ||||
|     vd->setRegIndex(newRegIndex); | ||||
| 
 | ||||
|     _x86State.getListByClass(C)[oldRegIndex] = nullptr; | ||||
|     _x86State.getListByClass(C)[newRegIndex] = vd; | ||||
| 
 | ||||
|     _x86State._occupied.xor_(C, bothRegMask); | ||||
|     _x86State._modified.xor_(C, bothRegMask & -static_cast<int32_t>(vd->isModified())); | ||||
| 
 | ||||
|     ASMJIT_X86_CHECK_STATE | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Load / Save]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Load.
 | ||||
|   //!
 | ||||
|   //! Load variable from its memory slot to a register, emitting 'Load'
 | ||||
|   //! instruction and changing the variable state to allocated.
 | ||||
|   template<int C> | ||||
|   ASMJIT_INLINE void load(VarData* vd, uint32_t regIndex) { | ||||
|     // Can be only called if variable is not allocated.
 | ||||
|     ASMJIT_ASSERT(vd->getClass() == C); | ||||
|     ASMJIT_ASSERT(vd->getState() != kVarStateReg); | ||||
|     ASMJIT_ASSERT(vd->getRegIndex() == kInvalidReg); | ||||
| 
 | ||||
|     emitLoad(vd, regIndex, "Load"); | ||||
|     attach<C>(vd, regIndex, false); | ||||
| 
 | ||||
|     ASMJIT_X86_CHECK_STATE | ||||
|   } | ||||
| 
 | ||||
|   //! Save.
 | ||||
|   //!
 | ||||
|   //! Save the variable into its home location, but keep it as allocated.
 | ||||
|   template<int C> | ||||
|   ASMJIT_INLINE void save(VarData* vd) { | ||||
|     ASMJIT_ASSERT(vd->getClass() == C); | ||||
|     ASMJIT_ASSERT(vd->getState() == kVarStateReg); | ||||
|     ASMJIT_ASSERT(vd->getRegIndex() != kInvalidReg); | ||||
| 
 | ||||
|     uint32_t regIndex = vd->getRegIndex(); | ||||
|     uint32_t regMask = Utils::mask(regIndex); | ||||
| 
 | ||||
|     emitSave(vd, regIndex, "Save"); | ||||
| 
 | ||||
|     vd->setModified(false); | ||||
|     _x86State._modified.andNot(C, regMask); | ||||
| 
 | ||||
|     ASMJIT_X86_CHECK_STATE | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Move / Swap]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Move a register.
 | ||||
|   //!
 | ||||
|   //! Move register from one index to another, emitting 'Move' if needed. This
 | ||||
|   //! function does nothing if register is already at the given index.
 | ||||
|   template<int C> | ||||
|   ASMJIT_INLINE void move(VarData* vd, uint32_t regIndex) { | ||||
|     ASMJIT_ASSERT(vd->getClass() == C); | ||||
|     ASMJIT_ASSERT(vd->getState() == kVarStateReg); | ||||
|     ASMJIT_ASSERT(vd->getRegIndex() != kInvalidReg); | ||||
| 
 | ||||
|     uint32_t oldIndex = vd->getRegIndex(); | ||||
|     if (regIndex != oldIndex) { | ||||
|       emitMove(vd, regIndex, oldIndex, "Move"); | ||||
|       rebase<C>(vd, regIndex, oldIndex); | ||||
|     } | ||||
| 
 | ||||
|     ASMJIT_X86_CHECK_STATE | ||||
|   } | ||||
| 
 | ||||
|   //! Swap two registers
 | ||||
|   //!
 | ||||
|   //! It's only possible to swap Gp registers.
 | ||||
|   ASMJIT_INLINE void swapGp(VarData* aVd, VarData* bVd) { | ||||
|     ASMJIT_ASSERT(aVd != bVd); | ||||
| 
 | ||||
|     ASMJIT_ASSERT(aVd->getClass() == kX86RegClassGp); | ||||
|     ASMJIT_ASSERT(aVd->getState() == kVarStateReg); | ||||
|     ASMJIT_ASSERT(aVd->getRegIndex() != kInvalidReg); | ||||
| 
 | ||||
|     ASMJIT_ASSERT(bVd->getClass() == kX86RegClassGp); | ||||
|     ASMJIT_ASSERT(bVd->getState() == kVarStateReg); | ||||
|     ASMJIT_ASSERT(bVd->getRegIndex() != kInvalidReg); | ||||
| 
 | ||||
|     uint32_t aIndex = aVd->getRegIndex(); | ||||
|     uint32_t bIndex = bVd->getRegIndex(); | ||||
| 
 | ||||
|     emitSwapGp(aVd, bVd, aIndex, bIndex, "Swap"); | ||||
| 
 | ||||
|     aVd->setRegIndex(bIndex); | ||||
|     bVd->setRegIndex(aIndex); | ||||
| 
 | ||||
|     _x86State.getListByClass(kX86RegClassGp)[aIndex] = bVd; | ||||
|     _x86State.getListByClass(kX86RegClassGp)[bIndex] = aVd; | ||||
| 
 | ||||
|     uint32_t m = aVd->isModified() ^ bVd->isModified(); | ||||
|     _x86State._modified.xor_(kX86RegClassGp, (m << aIndex) | (m << bIndex)); | ||||
| 
 | ||||
|     ASMJIT_X86_CHECK_STATE | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Alloc / Spill]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Alloc.
 | ||||
|   template<int C> | ||||
|   ASMJIT_INLINE void alloc(VarData* vd, uint32_t regIndex) { | ||||
|     ASMJIT_ASSERT(vd->getClass() == C); | ||||
|     ASMJIT_ASSERT(regIndex != kInvalidReg); | ||||
| 
 | ||||
|     uint32_t oldRegIndex = vd->getRegIndex(); | ||||
|     uint32_t oldState = vd->getState(); | ||||
|     uint32_t regMask = Utils::mask(regIndex); | ||||
| 
 | ||||
|     ASMJIT_ASSERT(_x86State.getListByClass(C)[regIndex] == nullptr || regIndex == oldRegIndex); | ||||
| 
 | ||||
|     if (oldState != kVarStateReg) { | ||||
|       if (oldState == kVarStateMem) | ||||
|         emitLoad(vd, regIndex, "Alloc"); | ||||
|       vd->setModified(false); | ||||
|     } | ||||
|     else if (oldRegIndex != regIndex) { | ||||
|       emitMove(vd, regIndex, oldRegIndex, "Alloc"); | ||||
| 
 | ||||
|       _x86State.getListByClass(C)[oldRegIndex] = nullptr; | ||||
|       regMask ^= Utils::mask(oldRegIndex); | ||||
|     } | ||||
|     else { | ||||
|       ASMJIT_X86_CHECK_STATE | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     vd->setState(kVarStateReg); | ||||
|     vd->setRegIndex(regIndex); | ||||
|     vd->addHomeIndex(regIndex); | ||||
| 
 | ||||
|     _x86State.getListByClass(C)[regIndex] = vd; | ||||
|     _x86State._occupied.xor_(C, regMask); | ||||
|     _x86State._modified.xor_(C, regMask & -static_cast<int32_t>(vd->isModified())); | ||||
| 
 | ||||
|     ASMJIT_X86_CHECK_STATE | ||||
|   } | ||||
| 
 | ||||
|   //! Spill.
 | ||||
|   //!
 | ||||
|   //! Spill variable/register, saves the content to the memory-home if modified.
 | ||||
|   template<int C> | ||||
|   ASMJIT_INLINE void spill(VarData* vd) { | ||||
|     ASMJIT_ASSERT(vd->getClass() == C); | ||||
| 
 | ||||
|     if (vd->getState() != kVarStateReg) { | ||||
|       ASMJIT_X86_CHECK_STATE | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     uint32_t regIndex = vd->getRegIndex(); | ||||
| 
 | ||||
|     ASMJIT_ASSERT(regIndex != kInvalidReg); | ||||
|     ASMJIT_ASSERT(_x86State.getListByClass(C)[regIndex] == vd); | ||||
| 
 | ||||
|     if (vd->isModified()) | ||||
|       emitSave(vd, regIndex, "Spill"); | ||||
|     detach<C>(vd, regIndex, kVarStateMem); | ||||
| 
 | ||||
|     ASMJIT_X86_CHECK_STATE | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Modify]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   template<int C> | ||||
|   ASMJIT_INLINE void modify(VarData* vd) { | ||||
|     ASMJIT_ASSERT(vd->getClass() == C); | ||||
| 
 | ||||
|     uint32_t regIndex = vd->getRegIndex(); | ||||
|     uint32_t regMask = Utils::mask(regIndex); | ||||
| 
 | ||||
|     vd->setModified(true); | ||||
|     _x86State._modified.or_(C, regMask); | ||||
| 
 | ||||
|     ASMJIT_X86_CHECK_STATE | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Unuse]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Unuse.
 | ||||
|   //!
 | ||||
|   //! Unuse variable, it will be detached it if it's allocated then its state
 | ||||
|   //! will be changed to kVarStateNone.
 | ||||
|   template<int C> | ||||
|   ASMJIT_INLINE void unuse(VarData* vd, uint32_t vState = kVarStateNone) { | ||||
|     ASMJIT_ASSERT(vd->getClass() == C); | ||||
|     ASMJIT_ASSERT(vState != kVarStateReg); | ||||
| 
 | ||||
|     uint32_t regIndex = vd->getRegIndex(); | ||||
|     if (regIndex != kInvalidReg) | ||||
|       detach<C>(vd, regIndex, vState); | ||||
|     else | ||||
|       vd->setState(vState); | ||||
| 
 | ||||
|     ASMJIT_X86_CHECK_STATE | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [State]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get state as `X86VarState`.
 | ||||
|   ASMJIT_INLINE X86VarState* getState() const { | ||||
|     return const_cast<X86VarState*>(&_x86State); | ||||
|   } | ||||
| 
 | ||||
|   virtual void loadState(VarState* src); | ||||
|   virtual VarState* saveState(); | ||||
| 
 | ||||
|   virtual void switchState(VarState* src); | ||||
|   virtual void intersectStates(VarState* a, VarState* b); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Memory]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_INLINE X86Mem getVarMem(VarData* vd) { | ||||
|     (void)getVarCell(vd); | ||||
| 
 | ||||
|     X86Mem mem(_memSlot); | ||||
|     mem.setBase(vd->getId()); | ||||
|     return mem; | ||||
|   } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Fetch]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   virtual Error fetch(); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Annotate]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   virtual Error annotate(); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Translate]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   virtual Error translate(); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Serialize]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   virtual Error serialize(Assembler* assembler, HLNode* start, HLNode* stop); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Count of X86/X64 registers.
 | ||||
|   X86RegCount _regCount; | ||||
|   //! X86/X64 stack-pointer (esp or rsp).
 | ||||
|   X86GpReg _zsp; | ||||
|   //! X86/X64 frame-pointer (ebp or rbp).
 | ||||
|   X86GpReg _zbp; | ||||
|   //! Temporary memory operand.
 | ||||
|   X86Mem _memSlot; | ||||
| 
 | ||||
|   //! X86/X64 specific compiler state, linked to `_state`.
 | ||||
|   X86VarState _x86State; | ||||
|   //! Clobbered registers (for the whole function).
 | ||||
|   X86RegMask _clobberedRegs; | ||||
| 
 | ||||
|   //! Memory cell where is stored address used to restore manually
 | ||||
|   //! aligned stack.
 | ||||
|   VarCell* _stackFrameCell; | ||||
| 
 | ||||
|   //! Global allocable registers mask.
 | ||||
|   uint32_t _gaRegs[kX86RegClassCount]; | ||||
| 
 | ||||
|   //! Function arguments base pointer (register).
 | ||||
|   uint8_t _argBaseReg; | ||||
|   //! Function variables base pointer (register).
 | ||||
|   uint8_t _varBaseReg; | ||||
|   //! Whether to emit comments.
 | ||||
|   uint8_t _emitComments; | ||||
| 
 | ||||
|   //! Function arguments base offset.
 | ||||
|   int32_t _argBaseOffset; | ||||
|   //! Function variables base offset.
 | ||||
|   int32_t _varBaseOffset; | ||||
| 
 | ||||
|   //! Function arguments displacement.
 | ||||
|   int32_t _argActualDisp; | ||||
|   //! Function variables displacement.
 | ||||
|   int32_t _varActualDisp; | ||||
| 
 | ||||
|   //! Temporary string builder used for logging.
 | ||||
|   StringBuilderTmp<256> _stringBuilder; | ||||
| }; | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // !ASMJIT_DISABLE_COMPILER
 | ||||
| #endif // _ASMJIT_X86_X86COMPILERCONTEXT_P_H
 | ||||
							
								
								
									
										551
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86compilerfunc.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										551
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86compilerfunc.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,551 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #include "../build.h" | ||||
| #if !defined(ASMJIT_DISABLE_COMPILER) && (defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)) | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../x86/x86compiler.h" | ||||
| #include "../x86/x86compilerfunc.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86FuncDecl - Helpers]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| static ASMJIT_INLINE bool x86ArgIsInt(uint32_t aType) { | ||||
|   ASMJIT_ASSERT(aType < kX86VarTypeCount); | ||||
|   return Utils::inInterval<uint32_t>(aType, _kVarTypeIntStart, _kVarTypeIntEnd); | ||||
| } | ||||
| 
 | ||||
| static ASMJIT_INLINE bool x86ArgIsFp(uint32_t aType) { | ||||
|   ASMJIT_ASSERT(aType < kX86VarTypeCount); | ||||
|   return Utils::inInterval<uint32_t>(aType, _kVarTypeFpStart, _kVarTypeFpEnd); | ||||
| } | ||||
| 
 | ||||
| static ASMJIT_INLINE uint32_t x86ArgTypeToXmmType(uint32_t aType) { | ||||
|   if (aType == kVarTypeFp32) return kX86VarTypeXmmSs; | ||||
|   if (aType == kVarTypeFp64) return kX86VarTypeXmmSd; | ||||
|   return aType; | ||||
| } | ||||
| 
 | ||||
| //! Get an architecture depending on the calling convention `callConv`.
 | ||||
| //!
 | ||||
| //! Returns `kArchNone`, `kArchX86`, or `kArchX64`.
 | ||||
| static ASMJIT_INLINE uint32_t x86GetArchFromCConv(uint32_t callConv) { | ||||
|   if (Utils::inInterval<uint32_t>(callConv, _kCallConvX86Start, _kCallConvX86End)) return kArchX86; | ||||
|   if (Utils::inInterval<uint32_t>(callConv, _kCallConvX64Start, _kCallConvX64End)) return kArchX64; | ||||
| 
 | ||||
|   return kArchNone; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86FuncDecl - SetPrototype]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #define R(_Index_) kX86RegIndex##_Index_ | ||||
| static uint32_t X86FuncDecl_initConv(X86FuncDecl* self, uint32_t arch, uint32_t callConv) { | ||||
|   // Setup defaults.
 | ||||
|   self->_argStackSize = 0; | ||||
|   self->_redZoneSize = 0; | ||||
|   self->_spillZoneSize = 0; | ||||
| 
 | ||||
|   self->_callConv = static_cast<uint8_t>(callConv); | ||||
|   self->_calleePopsStack = false; | ||||
|   self->_argsDirection = kFuncDirRTL; | ||||
| 
 | ||||
|   self->_passed.reset(); | ||||
|   self->_preserved.reset(); | ||||
| 
 | ||||
|   ::memset(self->_passedOrderGp, kInvalidReg, ASMJIT_ARRAY_SIZE(self->_passedOrderGp)); | ||||
|   ::memset(self->_passedOrderXyz, kInvalidReg, ASMJIT_ARRAY_SIZE(self->_passedOrderXyz)); | ||||
| 
 | ||||
|   switch (arch) { | ||||
|     // ------------------------------------------------------------------------
 | ||||
|     // [X86 Support]
 | ||||
|     // ------------------------------------------------------------------------
 | ||||
| 
 | ||||
| #if defined(ASMJIT_BUILD_X86) | ||||
|     case kArchX86: { | ||||
|       self->_preserved.set(kX86RegClassGp, Utils::mask(R(Bx), R(Sp), R(Bp), R(Si), R(Di))); | ||||
| 
 | ||||
|       switch (callConv) { | ||||
|         case kCallConvX86CDecl: | ||||
|           break; | ||||
| 
 | ||||
|         case kCallConvX86StdCall: | ||||
|           self->_calleePopsStack = true; | ||||
|           break; | ||||
| 
 | ||||
|         case kCallConvX86MsThisCall: | ||||
|           self->_calleePopsStack = true; | ||||
|           self->_passed.set(kX86RegClassGp, Utils::mask(R(Cx))); | ||||
|           self->_passedOrderGp[0] = R(Cx); | ||||
|           break; | ||||
| 
 | ||||
|         case kCallConvX86MsFastCall: | ||||
|           self->_calleePopsStack = true; | ||||
|           self->_passed.set(kX86RegClassGp, Utils::mask(R(Cx), R(Cx))); | ||||
|           self->_passedOrderGp[0] = R(Cx); | ||||
|           self->_passedOrderGp[1] = R(Dx); | ||||
|           break; | ||||
| 
 | ||||
|         case kCallConvX86BorlandFastCall: | ||||
|           self->_calleePopsStack = true; | ||||
|           self->_argsDirection = kFuncDirLTR; | ||||
|           self->_passed.set(kX86RegClassGp, Utils::mask(R(Ax), R(Dx), R(Cx))); | ||||
|           self->_passedOrderGp[0] = R(Ax); | ||||
|           self->_passedOrderGp[1] = R(Dx); | ||||
|           self->_passedOrderGp[2] = R(Cx); | ||||
|           break; | ||||
| 
 | ||||
|         case kCallConvX86GccFastCall: | ||||
|           self->_calleePopsStack = true; | ||||
|           self->_passed.set(kX86RegClassGp, Utils::mask(R(Cx), R(Dx))); | ||||
|           self->_passedOrderGp[0] = R(Cx); | ||||
|           self->_passedOrderGp[1] = R(Dx); | ||||
|           break; | ||||
| 
 | ||||
|         case kCallConvX86GccRegParm1: | ||||
|           self->_passed.set(kX86RegClassGp, Utils::mask(R(Ax))); | ||||
|           self->_passedOrderGp[0] = R(Ax); | ||||
|           break; | ||||
| 
 | ||||
|         case kCallConvX86GccRegParm2: | ||||
|           self->_passed.set(kX86RegClassGp, Utils::mask(R(Ax), R(Dx))); | ||||
|           self->_passedOrderGp[0] = R(Ax); | ||||
|           self->_passedOrderGp[1] = R(Dx); | ||||
|           break; | ||||
| 
 | ||||
|         case kCallConvX86GccRegParm3: | ||||
|           self->_passed.set(kX86RegClassGp, Utils::mask(R(Ax), R(Dx), R(Cx))); | ||||
|           self->_passedOrderGp[0] = R(Ax); | ||||
|           self->_passedOrderGp[1] = R(Dx); | ||||
|           self->_passedOrderGp[2] = R(Cx); | ||||
|           break; | ||||
| 
 | ||||
|         default: | ||||
|           return kErrorInvalidArgument; | ||||
|       } | ||||
| 
 | ||||
|       return kErrorOk; | ||||
|     } | ||||
| #endif // ASMJIT_BUILD_X86
 | ||||
| 
 | ||||
|     // ------------------------------------------------------------------------
 | ||||
|     // [X64 Support]
 | ||||
|     // ------------------------------------------------------------------------
 | ||||
| 
 | ||||
| #if defined(ASMJIT_BUILD_X64) | ||||
|     case kArchX64: { | ||||
|       switch (callConv) { | ||||
|         case kCallConvX64Win: | ||||
|           self->_spillZoneSize = 32; | ||||
| 
 | ||||
|           self->_passed.set(kX86RegClassGp, Utils::mask(R(Cx), R(Dx), 8, 9)); | ||||
|           self->_passedOrderGp[0] = R(Cx); | ||||
|           self->_passedOrderGp[1] = R(Dx); | ||||
|           self->_passedOrderGp[2] = 8; | ||||
|           self->_passedOrderGp[3] = 9; | ||||
| 
 | ||||
|           self->_passed.set(kX86RegClassXyz, Utils::mask(0, 1, 2, 3)); | ||||
|           self->_passedOrderXyz[0] = 0; | ||||
|           self->_passedOrderXyz[1] = 1; | ||||
|           self->_passedOrderXyz[2] = 2; | ||||
|           self->_passedOrderXyz[3] = 3; | ||||
| 
 | ||||
|           self->_preserved.set(kX86RegClassGp , Utils::mask(R(Bx), R(Sp), R(Bp), R(Si), R(Di), 12, 13, 14, 15)); | ||||
|           self->_preserved.set(kX86RegClassXyz, Utils::mask(6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); | ||||
|           break; | ||||
| 
 | ||||
|         case kCallConvX64Unix: | ||||
|           self->_redZoneSize = 128; | ||||
| 
 | ||||
|           self->_passed.set(kX86RegClassGp, Utils::mask(R(Di), R(Si), R(Dx), R(Cx), 8, 9)); | ||||
|           self->_passedOrderGp[0] = R(Di); | ||||
|           self->_passedOrderGp[1] = R(Si); | ||||
|           self->_passedOrderGp[2] = R(Dx); | ||||
|           self->_passedOrderGp[3] = R(Cx); | ||||
|           self->_passedOrderGp[4] = 8; | ||||
|           self->_passedOrderGp[5] = 9; | ||||
| 
 | ||||
|           self->_passed.set(kX86RegClassXyz, Utils::mask(0, 1, 2, 3, 4, 5, 6, 7)); | ||||
|           self->_passedOrderXyz[0] = 0; | ||||
|           self->_passedOrderXyz[1] = 1; | ||||
|           self->_passedOrderXyz[2] = 2; | ||||
|           self->_passedOrderXyz[3] = 3; | ||||
|           self->_passedOrderXyz[4] = 4; | ||||
|           self->_passedOrderXyz[5] = 5; | ||||
|           self->_passedOrderXyz[6] = 6; | ||||
|           self->_passedOrderXyz[7] = 7; | ||||
| 
 | ||||
|           self->_preserved.set(kX86RegClassGp, Utils::mask(R(Bx), R(Sp), R(Bp), 12, 13, 14, 15)); | ||||
|           break; | ||||
| 
 | ||||
|         default: | ||||
|           return kErrorInvalidArgument; | ||||
|       } | ||||
| 
 | ||||
|       return kErrorOk; | ||||
|     } | ||||
| #endif // ASMJIT_BUILD_X64
 | ||||
| 
 | ||||
|     default: | ||||
|       return kErrorInvalidArgument; | ||||
|   } | ||||
| } | ||||
| #undef R | ||||
| 
 | ||||
| static Error X86FuncDecl_initFunc(X86FuncDecl* self, uint32_t arch, | ||||
|   uint32_t ret, const uint32_t* args, uint32_t numArgs) { | ||||
| 
 | ||||
|   ASMJIT_ASSERT(numArgs <= kFuncArgCount); | ||||
| 
 | ||||
|   uint32_t callConv = self->_callConv; | ||||
|   uint32_t regSize = (arch == kArchX86) ? 4 : 8; | ||||
| 
 | ||||
|   int32_t i = 0; | ||||
|   int32_t gpPos = 0; | ||||
|   int32_t xmmPos = 0; | ||||
|   int32_t stackOffset = 0; | ||||
|   const uint8_t* varMapping = nullptr; | ||||
| 
 | ||||
| #if defined(ASMJIT_BUILD_X86) | ||||
|   if (arch == kArchX86) | ||||
|     varMapping = _x86VarMapping; | ||||
| #endif // ASMJIT_BUILD_X86
 | ||||
| 
 | ||||
| #if defined(ASMJIT_BUILD_X64) | ||||
|   if (arch == kArchX64) | ||||
|     varMapping = _x64VarMapping; | ||||
| #endif // ASMJIT_BUILD_X64
 | ||||
| 
 | ||||
|   ASMJIT_ASSERT(varMapping != nullptr); | ||||
|   self->_numArgs = static_cast<uint8_t>(numArgs); | ||||
|   self->_retCount = 0; | ||||
| 
 | ||||
|   for (i = 0; i < static_cast<int32_t>(numArgs); i++) { | ||||
|     FuncInOut& arg = self->getArg(i); | ||||
|     arg._varType = static_cast<uint8_t>(varMapping[args[i]]); | ||||
|     arg._regIndex = kInvalidReg; | ||||
|     arg._stackOffset = kFuncStackInvalid; | ||||
|   } | ||||
| 
 | ||||
|   for (; i < kFuncArgCount; i++) { | ||||
|     self->_args[i].reset(); | ||||
|   } | ||||
| 
 | ||||
|   self->_rets[0].reset(); | ||||
|   self->_rets[1].reset(); | ||||
|   self->_argStackSize = 0; | ||||
|   self->_used.reset(); | ||||
| 
 | ||||
|   if (ret != kInvalidVar) { | ||||
|     ret = varMapping[ret]; | ||||
|     switch (ret) { | ||||
|       case kVarTypeInt64: | ||||
|       case kVarTypeUInt64: | ||||
|         // 64-bit value is returned in EDX:EAX on x86.
 | ||||
| #if defined(ASMJIT_BUILD_X86) | ||||
|         if (arch == kArchX86) { | ||||
|           self->_retCount = 2; | ||||
|           self->_rets[0]._varType = kVarTypeUInt32; | ||||
|           self->_rets[0]._regIndex = kX86RegIndexAx; | ||||
|           self->_rets[1]._varType = static_cast<uint8_t>(ret - 2); | ||||
|           self->_rets[1]._regIndex = kX86RegIndexDx; | ||||
|         } | ||||
|         ASMJIT_FALLTHROUGH; | ||||
| #endif // ASMJIT_BUILD_X86
 | ||||
| 
 | ||||
|       case kVarTypeInt8: | ||||
|       case kVarTypeUInt8: | ||||
|       case kVarTypeInt16: | ||||
|       case kVarTypeUInt16: | ||||
|       case kVarTypeInt32: | ||||
|       case kVarTypeUInt32: | ||||
|         self->_retCount = 1; | ||||
|         self->_rets[0]._varType = static_cast<uint8_t>(ret); | ||||
|         self->_rets[0]._regIndex = kX86RegIndexAx; | ||||
|         break; | ||||
| 
 | ||||
|       case kX86VarTypeMm: | ||||
|         self->_retCount = 1; | ||||
|         self->_rets[0]._varType = static_cast<uint8_t>(ret); | ||||
|         self->_rets[0]._regIndex = 0; | ||||
|         break; | ||||
| 
 | ||||
|       case kVarTypeFp32: | ||||
|         self->_retCount = 1; | ||||
|         if (arch == kArchX86) { | ||||
|           self->_rets[0]._varType = kVarTypeFp32; | ||||
|           self->_rets[0]._regIndex = 0; | ||||
|         } | ||||
|         else { | ||||
|           self->_rets[0]._varType = kX86VarTypeXmmSs; | ||||
|           self->_rets[0]._regIndex = 0; | ||||
|         } | ||||
|         break; | ||||
| 
 | ||||
|       case kVarTypeFp64: | ||||
|         self->_retCount = 1; | ||||
|         if (arch == kArchX86) { | ||||
|           self->_rets[0]._varType = kVarTypeFp64; | ||||
|           self->_rets[0]._regIndex = 0; | ||||
|         } | ||||
|         else { | ||||
|           self->_rets[0]._varType = kX86VarTypeXmmSd; | ||||
|           self->_rets[0]._regIndex = 0; | ||||
|           break; | ||||
|         } | ||||
|         break; | ||||
| 
 | ||||
|       case kX86VarTypeXmm: | ||||
|       case kX86VarTypeXmmSs: | ||||
|       case kX86VarTypeXmmSd: | ||||
|       case kX86VarTypeXmmPs: | ||||
|       case kX86VarTypeXmmPd: | ||||
|         self->_retCount = 1; | ||||
|         self->_rets[0]._varType = static_cast<uint8_t>(ret); | ||||
|         self->_rets[0]._regIndex = 0; | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (self->_numArgs == 0) | ||||
|     return kErrorOk; | ||||
| 
 | ||||
| #if defined(ASMJIT_BUILD_X86) | ||||
|   if (arch == kArchX86) { | ||||
|     // Register arguments (Integer), always left-to-right.
 | ||||
|     for (i = 0; i != static_cast<int32_t>(numArgs); i++) { | ||||
|       FuncInOut& arg = self->getArg(i); | ||||
|       uint32_t varType = varMapping[arg.getVarType()]; | ||||
| 
 | ||||
|       if (!x86ArgIsInt(varType) || gpPos >= ASMJIT_ARRAY_SIZE(self->_passedOrderGp)) | ||||
|         continue; | ||||
| 
 | ||||
|       if (self->_passedOrderGp[gpPos] == kInvalidReg) | ||||
|         continue; | ||||
| 
 | ||||
|       arg._regIndex = self->_passedOrderGp[gpPos++]; | ||||
|       self->_used.or_(kX86RegClassGp, Utils::mask(arg.getRegIndex())); | ||||
|     } | ||||
| 
 | ||||
|     // Stack arguments.
 | ||||
|     int32_t iStart = static_cast<int32_t>(numArgs - 1); | ||||
|     int32_t iEnd   = -1; | ||||
|     int32_t iStep  = -1; | ||||
| 
 | ||||
|     if (self->_argsDirection == kFuncDirLTR) { | ||||
|       iStart = 0; | ||||
|       iEnd   = static_cast<int32_t>(numArgs); | ||||
|       iStep  = 1; | ||||
|     } | ||||
| 
 | ||||
|     for (i = iStart; i != iEnd; i += iStep) { | ||||
|       FuncInOut& arg = self->getArg(i); | ||||
|       uint32_t varType = varMapping[arg.getVarType()]; | ||||
| 
 | ||||
|       if (arg.hasRegIndex()) | ||||
|         continue; | ||||
| 
 | ||||
|       if (x86ArgIsInt(varType)) { | ||||
|         stackOffset -= 4; | ||||
|         arg._stackOffset = static_cast<int16_t>(stackOffset); | ||||
|       } | ||||
|       else if (x86ArgIsFp(varType)) { | ||||
|         int32_t size = static_cast<int32_t>(_x86VarInfo[varType].getSize()); | ||||
|         stackOffset -= size; | ||||
|         arg._stackOffset = static_cast<int16_t>(stackOffset); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| #endif // ASMJIT_BUILD_X86
 | ||||
| 
 | ||||
| #if defined(ASMJIT_BUILD_X64) | ||||
|   if (arch == kArchX64) { | ||||
|     if (callConv == kCallConvX64Win) { | ||||
|       int32_t argMax = Utils::iMin<int32_t>(numArgs, 4); | ||||
| 
 | ||||
|       // Register arguments (GP/XMM), always left-to-right.
 | ||||
|       for (i = 0; i != argMax; i++) { | ||||
|         FuncInOut& arg = self->getArg(i); | ||||
|         uint32_t varType = varMapping[arg.getVarType()]; | ||||
| 
 | ||||
|         if (x86ArgIsInt(varType) && i < ASMJIT_ARRAY_SIZE(self->_passedOrderGp)) { | ||||
|           arg._regIndex = self->_passedOrderGp[i]; | ||||
|           self->_used.or_(kX86RegClassGp, Utils::mask(arg.getRegIndex())); | ||||
|           continue; | ||||
|         } | ||||
| 
 | ||||
|         if (x86ArgIsFp(varType) && i < ASMJIT_ARRAY_SIZE(self->_passedOrderXyz)) { | ||||
|           arg._varType = static_cast<uint8_t>(x86ArgTypeToXmmType(varType)); | ||||
|           arg._regIndex = self->_passedOrderXyz[i]; | ||||
|           self->_used.or_(kX86RegClassXyz, Utils::mask(arg.getRegIndex())); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       // Stack arguments (always right-to-left).
 | ||||
|       for (i = numArgs - 1; i != -1; i--) { | ||||
|         FuncInOut& arg = self->getArg(i); | ||||
|         uint32_t varType = varMapping[arg.getVarType()]; | ||||
| 
 | ||||
|         if (arg.hasRegIndex()) | ||||
|           continue; | ||||
| 
 | ||||
|         if (x86ArgIsInt(varType)) { | ||||
|           stackOffset -= 8; // Always 8 bytes.
 | ||||
|           arg._stackOffset = stackOffset; | ||||
|         } | ||||
|         else if (x86ArgIsFp(varType)) { | ||||
|           stackOffset -= 8; // Always 8 bytes (float/double).
 | ||||
|           arg._stackOffset = stackOffset; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       // 32 bytes shadow space (X64W calling convention specific).
 | ||||
|       stackOffset -= 4 * 8; | ||||
|     } | ||||
|     else { | ||||
|       // Register arguments (Gp), always left-to-right.
 | ||||
|       for (i = 0; i != static_cast<int32_t>(numArgs); i++) { | ||||
|         FuncInOut& arg = self->getArg(i); | ||||
|         uint32_t varType = varMapping[arg.getVarType()]; | ||||
| 
 | ||||
|         if (!x86ArgIsInt(varType) || gpPos >= ASMJIT_ARRAY_SIZE(self->_passedOrderGp)) | ||||
|           continue; | ||||
| 
 | ||||
|         if (self->_passedOrderGp[gpPos] == kInvalidReg) | ||||
|           continue; | ||||
| 
 | ||||
|         arg._regIndex = self->_passedOrderGp[gpPos++]; | ||||
|         self->_used.or_(kX86RegClassGp, Utils::mask(arg.getRegIndex())); | ||||
|       } | ||||
| 
 | ||||
|       // Register arguments (XMM), always left-to-right.
 | ||||
|       for (i = 0; i != static_cast<int32_t>(numArgs); i++) { | ||||
|         FuncInOut& arg = self->getArg(i); | ||||
|         uint32_t varType = varMapping[arg.getVarType()]; | ||||
| 
 | ||||
|         if (x86ArgIsFp(varType)) { | ||||
|           arg._varType = static_cast<uint8_t>(x86ArgTypeToXmmType(varType)); | ||||
|           arg._regIndex = self->_passedOrderXyz[xmmPos++]; | ||||
|           self->_used.or_(kX86RegClassXyz, Utils::mask(arg.getRegIndex())); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       // Stack arguments.
 | ||||
|       for (i = numArgs - 1; i != -1; i--) { | ||||
|         FuncInOut& arg = self->getArg(i); | ||||
|         uint32_t varType = varMapping[arg.getVarType()]; | ||||
| 
 | ||||
|         if (arg.hasRegIndex()) | ||||
|           continue; | ||||
| 
 | ||||
|         if (x86ArgIsInt(varType)) { | ||||
|           stackOffset -= 8; | ||||
|           arg._stackOffset = static_cast<int16_t>(stackOffset); | ||||
|         } | ||||
|         else if (x86ArgIsFp(varType)) { | ||||
|           int32_t size = static_cast<int32_t>(_x86VarInfo[varType].getSize()); | ||||
| 
 | ||||
|           stackOffset -= size; | ||||
|           arg._stackOffset = static_cast<int16_t>(stackOffset); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| #endif // ASMJIT_BUILD_X64
 | ||||
| 
 | ||||
|   // Modify the stack offset, thus in result all parameters would have positive
 | ||||
|   // non-zero stack offset.
 | ||||
|   for (i = 0; i < static_cast<int32_t>(numArgs); i++) { | ||||
|     FuncInOut& arg = self->getArg(i); | ||||
|     if (!arg.hasRegIndex()) { | ||||
|       arg._stackOffset += static_cast<uint16_t>(static_cast<int32_t>(regSize) - stackOffset); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   self->_argStackSize = static_cast<uint32_t>(-stackOffset); | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| Error X86FuncDecl::setPrototype(const FuncPrototype& p) { | ||||
|   uint32_t callConv = p.getCallConv(); | ||||
|   uint32_t arch = x86GetArchFromCConv(callConv); | ||||
| 
 | ||||
|   if (arch == kArchNone) | ||||
|     return kErrorInvalidArgument; | ||||
| 
 | ||||
|   if (p.getNumArgs() > kFuncArgCount) | ||||
|     return kErrorInvalidArgument; | ||||
| 
 | ||||
|   // Validate that the required convention is supported by the current asmjit
 | ||||
|   // configuration, if only one target is compiled.
 | ||||
| #if defined(ASMJIT_BUILD_X86) && !defined(ASMJIT_BUILD_X64) | ||||
|   if (arch == kArchX64) | ||||
|     return kErrorInvalidState; | ||||
| #endif // ASMJIT_BUILD_X86 && !ASMJIT_BUILD_X64
 | ||||
| 
 | ||||
| #if !defined(ASMJIT_BUILD_X86) && defined(ASMJIT_BUILD_X64) | ||||
|   if (arch == kArchX86) | ||||
|     return kErrorInvalidState; | ||||
| #endif // !ASMJIT_BUILD_X86 && ASMJIT_BUILD_X64
 | ||||
| 
 | ||||
|   ASMJIT_PROPAGATE_ERROR(X86FuncDecl_initConv(this, arch, callConv)); | ||||
|   ASMJIT_PROPAGATE_ERROR(X86FuncDecl_initFunc(this, arch, p.getRet(), p.getArgs(), p.getNumArgs())); | ||||
| 
 | ||||
|   return kErrorOk; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86FuncDecl - Reset]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| void X86FuncDecl::reset() { | ||||
|   uint32_t i; | ||||
| 
 | ||||
|   _callConv = kCallConvNone; | ||||
|   _calleePopsStack = false; | ||||
|   _argsDirection = kFuncDirRTL; | ||||
|   _reserved0 = 0; | ||||
| 
 | ||||
|   _numArgs = 0; | ||||
|   _retCount = 0; | ||||
| 
 | ||||
|   _argStackSize = 0; | ||||
|   _redZoneSize = 0; | ||||
|   _spillZoneSize = 0; | ||||
| 
 | ||||
|   for (i = 0; i < ASMJIT_ARRAY_SIZE(_args); i++) | ||||
|     _args[i].reset(); | ||||
| 
 | ||||
|   _rets[0].reset(); | ||||
|   _rets[1].reset(); | ||||
| 
 | ||||
|   _used.reset(); | ||||
|   _passed.reset(); | ||||
|   _preserved.reset(); | ||||
| 
 | ||||
|   ::memset(_passedOrderGp, kInvalidReg, ASMJIT_ARRAY_SIZE(_passedOrderGp)); | ||||
|   ::memset(_passedOrderXyz, kInvalidReg, ASMJIT_ARRAY_SIZE(_passedOrderXyz)); | ||||
| } | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // !ASMJIT_DISABLE_COMPILER && (ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64)
 | ||||
							
								
								
									
										133
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86compilerfunc.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86compilerfunc.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,133 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #ifndef _ASMJIT_X86_X86COMPILERFUNC_P_H | ||||
| #define _ASMJIT_X86_X86COMPILERFUNC_P_H | ||||
| 
 | ||||
| #include "../build.h" | ||||
| #if !defined(ASMJIT_DISABLE_COMPILER) | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../base/compilerfunc.h" | ||||
| #include "../x86/x86operand.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| //! \addtogroup asmjit_x86
 | ||||
| //! \{
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::TypeId]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #if !defined(ASMJIT_DOCGEN) | ||||
| ASMJIT_TYPE_ID(X86MmReg, kX86VarTypeMm); | ||||
| ASMJIT_TYPE_ID(X86MmVar, kX86VarTypeMm); | ||||
| ASMJIT_TYPE_ID(X86XmmReg, kX86VarTypeXmm); | ||||
| ASMJIT_TYPE_ID(X86XmmVar, kX86VarTypeXmm); | ||||
| ASMJIT_TYPE_ID(X86YmmReg, kX86VarTypeYmm); | ||||
| ASMJIT_TYPE_ID(X86YmmVar, kX86VarTypeYmm); | ||||
| ASMJIT_TYPE_ID(X86ZmmReg, kX86VarTypeZmm); | ||||
| ASMJIT_TYPE_ID(X86ZmmVar, kX86VarTypeZmm); | ||||
| #endif // !ASMJIT_DOCGEN
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86FuncDecl]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| //! X86 function, including calling convention, arguments and their
 | ||||
| //! register indices or stack positions.
 | ||||
| struct X86FuncDecl : public FuncDecl { | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Construction / Destruction]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Create a new `X86FuncDecl` instance.
 | ||||
|   ASMJIT_INLINE X86FuncDecl() { reset(); } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Accessors - X86]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Get used registers mask for the given register class `rc`.
 | ||||
|   //!
 | ||||
|   //! NOTE: The result depends on the function calling convention AND the
 | ||||
|   //! function prototype. Returned mask contains only registers actually used
 | ||||
|   //! to pass function arguments.
 | ||||
|   ASMJIT_INLINE uint32_t getUsed(uint32_t rc) const { return _used.get(rc); } | ||||
| 
 | ||||
|   //! Get passed registers mask for the given register class `rc`.
 | ||||
|   //!
 | ||||
|   //! NOTE: The result depends on the function calling convention used; the
 | ||||
|   //! prototype of the function doesn't affect the mask returned.
 | ||||
|   ASMJIT_INLINE uint32_t getPassed(uint32_t rc) const { return _passed.get(rc); } | ||||
| 
 | ||||
|   //! Get preserved registers mask for the given register class `rc`.
 | ||||
|   //!
 | ||||
|   //! NOTE: The result depends on the function calling convention used; the
 | ||||
|   //! prototype of the function doesn't affect the mask returned.
 | ||||
|   ASMJIT_INLINE uint32_t getPreserved(uint32_t rc) const { return _preserved.get(rc); } | ||||
| 
 | ||||
|   //! Get ther order of passed registers (GP).
 | ||||
|   //!
 | ||||
|   //! NOTE: The result depends on the function calling convention used; the
 | ||||
|   //! prototype of the function doesn't affect the mask returned.
 | ||||
|   ASMJIT_INLINE const uint8_t* getPassedOrderGp() const { return _passedOrderGp; } | ||||
| 
 | ||||
|   //! Get ther order of passed registers (XMM/YMM/ZMM).
 | ||||
|   //!
 | ||||
|   //! NOTE: The result depends on the function calling convention used; the
 | ||||
|   //! prototype of the function doesn't affect the mask returned.
 | ||||
|   ASMJIT_INLINE const uint8_t* getPassedOrderXyz() const { return _passedOrderXyz; } | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [SetPrototype]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Set function prototype.
 | ||||
|   //!
 | ||||
|   //! This will set function calling convention and setup arguments variables.
 | ||||
|   //!
 | ||||
|   //! NOTE: This function will allocate variables, it can be called only once.
 | ||||
|   ASMJIT_API Error setPrototype(const FuncPrototype& p); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Reset]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   ASMJIT_API void reset(); | ||||
| 
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
|   // [Members]
 | ||||
|   // --------------------------------------------------------------------------
 | ||||
| 
 | ||||
|   //! Used registers.
 | ||||
|   X86RegMask _used; | ||||
|   //! Passed registers (defined by the calling convention).
 | ||||
|   X86RegMask _passed; | ||||
|   //! Preserved registers (defined by the calling convention).
 | ||||
|   X86RegMask _preserved; | ||||
| 
 | ||||
|   //! Order of registers used to pass GP function arguments.
 | ||||
|   uint8_t _passedOrderGp[8]; | ||||
|   //! Order of registers used to pass XMM/YMM/ZMM function arguments.
 | ||||
|   uint8_t _passedOrderXyz[8]; | ||||
| }; | ||||
| 
 | ||||
| //! \}
 | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // !ASMJIT_DISABLE_COMPILER
 | ||||
| #endif // _ASMJIT_X86_X86COMPILERFUNC_P_H
 | ||||
							
								
								
									
										3094
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86inst.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3094
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86inst.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2192
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86inst.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2192
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86inst.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										85
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86operand.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86operand.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #include "../build.h" | ||||
| #if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64) | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../x86/x86operand.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| namespace x86 { | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // [asmjit::X86Mem - abs[]]
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| X86Mem ptr_abs(Ptr p, int32_t disp, uint32_t size) noexcept { | ||||
|   X86Mem m(NoInit); | ||||
| 
 | ||||
|   m._init_packed_op_sz_b0_b1_id(Operand::kTypeMem, size, kMemTypeAbsolute, 0, kInvalidValue); | ||||
|   m._vmem.index = kInvalidValue; | ||||
|   m._vmem.displacement = static_cast<int32_t>((intptr_t)(p + disp)); | ||||
| 
 | ||||
|   return m; | ||||
| } | ||||
| 
 | ||||
| X86Mem ptr_abs(Ptr p, const X86Reg& index, uint32_t shift, int32_t disp, uint32_t size) noexcept { | ||||
|   X86Mem m(NoInit); | ||||
|   uint32_t flags = shift << kX86MemShiftIndex; | ||||
| 
 | ||||
|   if (index.isGp()) | ||||
|     flags |= X86Mem::_getGpdFlags(index); | ||||
|   else if (index.isXmm()) | ||||
|     flags |= kX86MemVSibXmm << kX86MemVSibIndex; | ||||
|   else if (index.isYmm()) | ||||
|     flags |= kX86MemVSibYmm << kX86MemVSibIndex; | ||||
| 
 | ||||
|   m._init_packed_op_sz_b0_b1_id(Operand::kTypeMem, size, kMemTypeAbsolute, flags, kInvalidValue); | ||||
|   m._vmem.index = index.getRegIndex(); | ||||
|   m._vmem.displacement = static_cast<int32_t>((intptr_t)(p + disp)); | ||||
| 
 | ||||
|   return m; | ||||
| } | ||||
| 
 | ||||
| #if !defined(ASMJIT_DISABLE_COMPILER) | ||||
| X86Mem ptr_abs(Ptr p, const X86Var& index, uint32_t shift, int32_t disp, uint32_t size) noexcept { | ||||
|   X86Mem m(NoInit); | ||||
|   uint32_t flags = shift << kX86MemShiftIndex; | ||||
| 
 | ||||
|   const Var& index_ = reinterpret_cast<const Var&>(index); | ||||
|   uint32_t indexRegType = index_.getRegType(); | ||||
| 
 | ||||
|   if (indexRegType <= kX86RegTypeGpq) | ||||
|     flags |= X86Mem::_getGpdFlags(reinterpret_cast<const Var&>(index)); | ||||
|   else if (indexRegType == kX86RegTypeXmm) | ||||
|     flags |= kX86MemVSibXmm << kX86MemVSibIndex; | ||||
|   else if (indexRegType == kX86RegTypeYmm) | ||||
|     flags |= kX86MemVSibYmm << kX86MemVSibIndex; | ||||
| 
 | ||||
|   m._init_packed_op_sz_b0_b1_id(Operand::kTypeMem, size, kMemTypeAbsolute, flags, kInvalidValue); | ||||
|   m._vmem.index = index_.getId(); | ||||
|   m._vmem.displacement = static_cast<int32_t>((intptr_t)(p + disp)); | ||||
| 
 | ||||
|   return m; | ||||
| } | ||||
| #endif // !ASMJIT_DISABLE_COMPILER
 | ||||
| 
 | ||||
| } // x86 namespace
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
 | ||||
							
								
								
									
										2592
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86operand.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2592
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86operand.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										84
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86operand_regs.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								DynamicHooks/thirdparty/AsmJit/x86/x86operand_regs.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | ||||
| // [AsmJit]
 | ||||
| // Complete x86/x64 JIT and Remote Assembler for C++.
 | ||||
| //
 | ||||
| // [License]
 | ||||
| // Zlib - See LICENSE.md file in the package.
 | ||||
| 
 | ||||
| // [Export]
 | ||||
| #define ASMJIT_EXPORTS | ||||
| #define ASMJIT_EXPORTS_X86_REGS | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #include "../build.h" | ||||
| #if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64) | ||||
| 
 | ||||
| // [Dependencies]
 | ||||
| #include "../x86/x86operand.h" | ||||
| 
 | ||||
| // [Api-Begin]
 | ||||
| #include "../apibegin.h" | ||||
| 
 | ||||
| namespace asmjit { | ||||
| 
 | ||||
| #define REG(type, index, size) {{{ \ | ||||
|   Operand::kTypeReg, size, { ((type) << 8) + index }, kInvalidValue, {{ kInvalidVar, 0 }} \ | ||||
| }}} | ||||
| 
 | ||||
| #define REG_LIST_04(type, start, size) \ | ||||
|   REG(type, start + 0, size), \ | ||||
|   REG(type, start + 1, size), \ | ||||
|   REG(type, start + 2, size), \ | ||||
|   REG(type, start + 3, size) | ||||
| 
 | ||||
| #define REG_LIST_08(type, start, size) \ | ||||
|   REG_LIST_04(type, start + 0, size), \ | ||||
|   REG_LIST_04(type, start + 4, size) | ||||
| 
 | ||||
| #define REG_LIST_16(type, start, size) \ | ||||
|   REG_LIST_08(type, start + 0, size), \ | ||||
|   REG_LIST_08(type, start + 8, size) | ||||
| 
 | ||||
| #define REG_LIST_32(type, start, size) \ | ||||
|   REG_LIST_16(type, start + 0, size), \ | ||||
|   REG_LIST_16(type, start + 16, size) | ||||
| 
 | ||||
| const X86RegData x86RegData = { | ||||
|   { REG_LIST_16(kX86RegTypeGpd  , 0,  4) }, | ||||
|   { REG_LIST_16(kX86RegTypeGpq  , 0,  8) }, | ||||
|   { REG_LIST_16(kX86RegTypeGpbLo, 0,  1) }, | ||||
|   { REG_LIST_04(kX86RegTypeGpbHi, 0,  1) }, | ||||
|   { REG_LIST_16(kX86RegTypeGpw  , 0,  2) }, | ||||
|   { REG_LIST_32(kX86RegTypeXmm  , 0, 16) }, | ||||
|   { REG_LIST_32(kX86RegTypeYmm  , 0, 32) }, | ||||
|   { REG_LIST_32(kX86RegTypeZmm  , 0, 64) }, | ||||
|   { REG_LIST_08(kX86RegTypeK    , 0,  8) }, | ||||
|   { REG_LIST_08(kX86RegTypeFp   , 0, 10) }, | ||||
|   { REG_LIST_08(kX86RegTypeMm   , 0,  8) }, | ||||
| 
 | ||||
|   { | ||||
|     REG(kX86RegTypeSeg, 0, 2), // Default.
 | ||||
|     REG(kX86RegTypeSeg, 1, 2), // ES.
 | ||||
|     REG(kX86RegTypeSeg, 2, 2), // CS.
 | ||||
|     REG(kX86RegTypeSeg, 3, 2), // SS.
 | ||||
|     REG(kX86RegTypeSeg, 4, 2), // DS.
 | ||||
|     REG(kX86RegTypeSeg, 5, 2), // FS.
 | ||||
|     REG(kX86RegTypeSeg, 6, 2)  // GS.
 | ||||
|   }, | ||||
| 
 | ||||
|   REG(kInvalidReg, kInvalidReg, 0), // NoGp.
 | ||||
|   REG(kX86RegTypeRip, 0, 0),        // RIP.
 | ||||
| }; | ||||
| 
 | ||||
| #undef REG_LIST_32 | ||||
| #undef REG_LIST_16 | ||||
| #undef REG_LIST_08 | ||||
| #undef REG_LIST_04 | ||||
| #undef REG | ||||
| 
 | ||||
| } // asmjit namespace
 | ||||
| 
 | ||||
| // [Api-End]
 | ||||
| #include "../apiend.h" | ||||
| 
 | ||||
| // [Guard]
 | ||||
| #endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
 | ||||
							
								
								
									
										70
									
								
								DynamicHooks/utilities.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								DynamicHooks/utilities.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> INCLUDES
 | ||||
| // ============================================================================
 | ||||
| #ifdef _WIN32 | ||||
| 	#include <windows.h> | ||||
| #endif | ||||
| 
 | ||||
| #ifdef __linux__ | ||||
| 	#include <sys/mman.h> | ||||
| 	#include <unistd.h> | ||||
| 	#define PAGE_SIZE 4096 | ||||
| 	#define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1)) | ||||
| 	#define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC | ||||
| #endif | ||||
| 
 | ||||
| #include "asm.h" | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> ParseParams
 | ||||
| // ============================================================================
 | ||||
| void SetMemPatchable(void* pAddr, size_t size) | ||||
| { | ||||
| #if defined __linux__ | ||||
| 	mprotect((void *) ALIGN(pAddr), sysconf(_SC_PAGESIZE), PAGE_EXECUTE_READWRITE); | ||||
| #elif defined _WIN32 | ||||
| 	DWORD old_prot; | ||||
| 	VirtualProtect(pAddr, size, PAGE_EXECUTE_READWRITE, &old_prot); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> WriteJMP
 | ||||
| // ============================================================================
 | ||||
| void WriteJMP(unsigned char* src, void* dest) | ||||
| { | ||||
| 	SetMemPatchable(src, 20); | ||||
| 	inject_jmp((void *)src, dest); | ||||
| } | ||||
							
								
								
									
										40
									
								
								DynamicHooks/utilities.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								DynamicHooks/utilities.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | ||||
| /**
 | ||||
| * ============================================================================= | ||||
| * DynamicHooks | ||||
| * Copyright (C) 2015 Robin Gohmert. All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied warranty. | ||||
| * In no event will the authors be held liable for any damages arising from  | ||||
| * the use of this software. | ||||
| *  | ||||
| * Permission is granted to anyone to use this software for any purpose,  | ||||
| * including commercial applications, and to alter it and redistribute it  | ||||
| * freely, subject to the following restrictions: | ||||
| * | ||||
| * 1. The origin of this software must not be misrepresented; you must not  | ||||
| * claim that you wrote the original software. If you use this software in a  | ||||
| * product, an acknowledgment in the product documentation would be  | ||||
| * appreciated but is not required. | ||||
| * | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| * asm.h/cpp from devmaster.net (thanks cybermind) edited by pRED* to handle gcc | ||||
| * -fPIC thunks correctly | ||||
| * | ||||
| * Idea and trampoline code taken from DynDetours (thanks your-name-here). | ||||
| */ | ||||
| 
 | ||||
| #ifndef _UTILITIES_H | ||||
| #define _UTILITIES_H | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // >> FUNCTIONS
 | ||||
| // ============================================================================
 | ||||
| void SetMemPatchable(void* pAddr, size_t size); | ||||
| void WriteJMP(unsigned char* src, void* dest); | ||||
| 
 | ||||
| #endif // _UTILITIES_H
 | ||||
							
								
								
									
										560
									
								
								dynhooks_sourcepawn.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										560
									
								
								dynhooks_sourcepawn.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,560 @@ | ||||
| #include "dynhooks_sourcepawn.h" | ||||
| #include "util.h" | ||||
| #include <am-autoptr.h> | ||||
| 
 | ||||
| #include "conventions/x86MsCdecl.h" | ||||
| #include "conventions/x86MsThiscall.h" | ||||
| #include "conventions/x86MsStdcall.h" | ||||
| #include "conventions/x86GccCdecl.h" | ||||
| #include "conventions/x86GccThiscall.h" | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| typedef x86MsCdecl x86DetourCdecl; | ||||
| typedef x86MsThiscall x86DetourThisCall; | ||||
| typedef x86MsStdcall x86DetourStdCall; | ||||
| #else | ||||
| typedef x86GccCdecl x86DetourCdecl; | ||||
| typedef x86GccThiscall x86DetourThisCall; | ||||
| // Uhm
 | ||||
| typedef x86MsStdcall x86DetourStdCall; | ||||
| #endif | ||||
| 
 | ||||
| //ke::Vector<CHook *> g_pDetours;
 | ||||
| //CallbackMap g_pPluginPreDetours;
 | ||||
| //CallbackMap g_pPluginPostDetours;
 | ||||
| DetourMap g_pPreDetours; | ||||
| DetourMap g_pPostDetours; | ||||
| 
 | ||||
| void UnhookFunction(HookType_t hookType, CHook *pDetour) | ||||
| { | ||||
| 	CHookManager *pDetourManager = GetHookManager(); | ||||
| 	pDetour->RemoveCallback(hookType, (HookHandlerFn *)(void *)&HandleDetour); | ||||
| 	if (!pDetour->AreCallbacksRegistered()) | ||||
| 		pDetourManager->UnhookFunction(pDetour->m_pFunc); | ||||
| } | ||||
| 
 | ||||
| bool AddDetourPluginHook(HookType_t hookType, CHook *pDetour, HookSetup *setup, IPluginFunction *pCallback) | ||||
| { | ||||
| 	DetourMap *map; | ||||
| 	if (hookType == HOOKTYPE_PRE) | ||||
| 		map = &g_pPreDetours; | ||||
| 	else | ||||
| 		map = &g_pPostDetours; | ||||
| 
 | ||||
| 	// See if we already have this detour in our list.
 | ||||
| 	PluginCallbackList *wrappers; | ||||
| 	DetourMap::Insert f = map->findForAdd(pDetour); | ||||
| 	if (f.found()) | ||||
| 	{ | ||||
| 		wrappers = f->value; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		// Create a vector to store all the plugin callbacks in.
 | ||||
| 		wrappers = new PluginCallbackList; | ||||
| 		if (!map->add(f, pDetour, wrappers)) | ||||
| 		{ | ||||
| 			delete wrappers; | ||||
| 			UnhookFunction(hookType, pDetour); | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	CDynamicHooksSourcePawn *pWrapper = new CDynamicHooksSourcePawn(setup, pDetour, pCallback, hookType == HOOKTYPE_POST); | ||||
| 	if (!wrappers->append(pWrapper)) | ||||
| 	{ | ||||
| 		if (wrappers->empty()) | ||||
| 		{ | ||||
| 			delete wrappers; | ||||
| 			UnhookFunction(hookType, pDetour); | ||||
| 			map->remove(f); | ||||
| 		} | ||||
| 		delete pWrapper; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool RemoveDetourPluginHook(HookType_t hookType, CHook *pDetour, IPluginFunction *pCallback) | ||||
| { | ||||
| 	DetourMap *map; | ||||
| 	if (hookType == HOOKTYPE_PRE) | ||||
| 		map = &g_pPreDetours; | ||||
| 	else | ||||
| 		map = &g_pPostDetours; | ||||
| 
 | ||||
| 	DetourMap::Result res = map->find(pDetour); | ||||
| 	if (!res.found()) | ||||
| 		return false; | ||||
| 
 | ||||
| 	// Remove the plugin's callback
 | ||||
| 	bool bRemoved = false; | ||||
| 	PluginCallbackList *wrappers = res->value; | ||||
| 	for (int i = wrappers->length()-1; i >= 0 ; i--) | ||||
| 	{ | ||||
| 		CDynamicHooksSourcePawn *pWrapper = wrappers->at(i); | ||||
| 		if (pWrapper->plugin_callback == pCallback) | ||||
| 		{ | ||||
| 			bRemoved = true; | ||||
| 			delete pWrapper; | ||||
| 			wrappers->remove(i--); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// No more plugin hooks on this callback. Free our structures.
 | ||||
| 	if (wrappers->empty()) | ||||
| 	{ | ||||
| 		delete wrappers; | ||||
| 		UnhookFunction(hookType, pDetour); | ||||
| 		map->remove(res); | ||||
| 	} | ||||
| 
 | ||||
| 	return bRemoved; | ||||
| } | ||||
| 
 | ||||
| void RemoveAllCallbacksForContext(HookType_t hookType, DetourMap *map, IPluginContext *pContext) | ||||
| { | ||||
| 	PluginCallbackList *wrappers; | ||||
| 	CDynamicHooksSourcePawn *pWrapper; | ||||
| 	DetourMap::iterator it = map->iter(); | ||||
| 	// Run through all active detours we added.
 | ||||
| 	for (; !it.empty(); it.next()) | ||||
| 	{ | ||||
| 		wrappers = it->value; | ||||
| 		// See if there are callbacks of this plugin context registered
 | ||||
| 		// and remove them.
 | ||||
| 		for (int i = wrappers->length() - 1; i >= 0; i--) | ||||
| 		{ | ||||
| 			pWrapper = wrappers->at(i); | ||||
| 			if (pWrapper->plugin_callback->GetParentContext() != pContext) | ||||
| 				continue; | ||||
| 
 | ||||
| 			delete pWrapper; | ||||
| 			wrappers->remove(i--); | ||||
| 		} | ||||
| 
 | ||||
| 		// No plugin interested in this hook anymore. unhook.
 | ||||
| 		if (wrappers->empty()) | ||||
| 		{ | ||||
| 			delete wrappers; | ||||
| 			UnhookFunction(hookType, it->key); | ||||
| 			it.erase(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void RemoveAllCallbacksForContext(IPluginContext *pContext) | ||||
| { | ||||
| 	RemoveAllCallbacksForContext(HOOKTYPE_PRE, &g_pPreDetours, pContext); | ||||
| 	RemoveAllCallbacksForContext(HOOKTYPE_POST, &g_pPostDetours, pContext); | ||||
| } | ||||
| 
 | ||||
| ICallingConvention *ConstructCallingConvention(HookSetup *setup) | ||||
| { | ||||
| 	std::vector<DataTypeSized_t> vecArgTypes; | ||||
| 	for (size_t i = 0; i < setup->params.size(); i++) | ||||
| 	{ | ||||
| 		ParamInfo &info = setup->params[i]; | ||||
| 		DataTypeSized_t type; | ||||
| 		type.type = DynamicHooks_ConvertParamTypeFrom(info.type); | ||||
| 		type.size = info.size; | ||||
| 		vecArgTypes.push_back(type); | ||||
| 	} | ||||
| 
 | ||||
| 	DataTypeSized_t returnType; | ||||
| 	returnType.type = DynamicHooks_ConvertReturnTypeFrom(setup->returnType); | ||||
| 	returnType.size = 0; | ||||
| 
 | ||||
| 	ICallingConvention *pCallConv = nullptr; | ||||
| 	switch (setup->callConv) | ||||
| 	{ | ||||
| 	case CallConv_CDECL: | ||||
| 		pCallConv = new x86DetourCdecl(vecArgTypes, returnType); | ||||
| 		break; | ||||
| 	case CallConv_THISCALL: | ||||
| 		pCallConv = new x86DetourThisCall(vecArgTypes, returnType); | ||||
| 		break; | ||||
| 	case CallConv_STDCALL: | ||||
| 		pCallConv = new x86DetourStdCall(vecArgTypes, returnType); | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	return pCallConv; | ||||
| } | ||||
| 
 | ||||
| bool HandleDetour(HookType_t hookType, CHook* pDetour) | ||||
| { | ||||
| 	DetourMap *map; | ||||
| 	if (hookType == HOOKTYPE_PRE) | ||||
| 		map = &g_pPreDetours; | ||||
| 	else | ||||
| 		map = &g_pPostDetours; | ||||
| 
 | ||||
| 	// Find the callback list for this detour.
 | ||||
| 	DetourMap::Result r = map->find(pDetour); | ||||
| 	if (!r.found()) | ||||
| 		return false; | ||||
| 
 | ||||
| 	// List of all callbacks.
 | ||||
| 	PluginCallbackList *wrappers = r->value; | ||||
| 
 | ||||
| 	HookReturnStruct *returnStruct = NULL; | ||||
| 	Handle_t rHndl = BAD_HANDLE; | ||||
| 
 | ||||
| 	HookParamsStruct *paramStruct = NULL; | ||||
| 	Handle_t pHndl = BAD_HANDLE; | ||||
| 
 | ||||
| 	int argNum = pDetour->m_pCallingConvention->m_vecArgTypes.size(); | ||||
| 	MRESReturn finalRet = MRES_Ignored; | ||||
| 	ke::AutoPtr<void> finalRetBuf(new uint8_t[pDetour->m_pCallingConvention->m_returnType.size]); | ||||
| 
 | ||||
| 	// Call all the plugin functions..
 | ||||
| 	for (size_t i = 0; i < wrappers->length(); i++) | ||||
| 	{ | ||||
| 		CDynamicHooksSourcePawn *pWrapper = wrappers->at(i); | ||||
| 		IPluginFunction *pCallback = pWrapper->plugin_callback; | ||||
| 		MRESReturn tempRet = MRES_Ignored; | ||||
| 		ke::AutoPtr<void> tempRetBuf(new uint8_t[pDetour->m_pCallingConvention->m_returnType.size]); | ||||
| 
 | ||||
| 		// Find the this pointer.
 | ||||
| 		if (pWrapper->callConv == CallConv_THISCALL) | ||||
| 		{ | ||||
| 			void *thisPtr = pDetour->GetArgument<void *>(0); | ||||
| 			cell_t thisAddr = GetThisPtr(thisPtr, pWrapper->thisType); | ||||
| 			pCallback->PushCell(thisAddr); | ||||
| 		} | ||||
| 
 | ||||
| 		if (pWrapper->returnType != ReturnType_Void) | ||||
| 		{ | ||||
| 			returnStruct = pWrapper->GetReturnStruct(); | ||||
| 			HandleError err; | ||||
| 			rHndl = handlesys->CreateHandle(g_HookReturnHandle, returnStruct, pCallback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), &err); | ||||
| 			if (!rHndl) | ||||
| 			{ | ||||
| 				pCallback->Cancel(); | ||||
| 				pCallback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(pCallback, "Error creating ReturnHandle in preparation to call hook callback. (error %d)", err); | ||||
| 
 | ||||
| 				if (returnStruct) | ||||
| 					delete returnStruct; | ||||
| 
 | ||||
| 				// Don't call more callbacks. They will probably fail too.
 | ||||
| 				break; | ||||
| 			} | ||||
| 			pCallback->PushCell(rHndl); | ||||
| 		} | ||||
| 
 | ||||
| 		if (argNum > 0) | ||||
| 		{ | ||||
| 			paramStruct = pWrapper->GetParamStruct(); | ||||
| 			HandleError err; | ||||
| 			pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, pCallback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), &err); | ||||
| 			if (!pHndl) | ||||
| 			{ | ||||
| 				pCallback->Cancel(); | ||||
| 				pCallback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(pCallback, "Error creating ThisHandle in preparation to call hook callback. (error %d)", err); | ||||
| 
 | ||||
| 				// Don't leak our own handles here!
 | ||||
| 				if (rHndl) | ||||
| 				{ | ||||
| 					HandleSecurity sec(pCallback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity()); | ||||
| 					handlesys->FreeHandle(rHndl, &sec); | ||||
| 					rHndl = BAD_HANDLE; | ||||
| 				} | ||||
| 
 | ||||
| 				if (paramStruct) | ||||
| 					delete paramStruct; | ||||
| 
 | ||||
| 				// Don't call more callbacks. They will probably fail too.
 | ||||
| 				break; | ||||
| 			} | ||||
| 			pCallback->PushCell(pHndl); | ||||
| 		} | ||||
| 
 | ||||
| 		cell_t result = (cell_t)MRES_Ignored; | ||||
| 		pCallback->Execute(&result); | ||||
| 
 | ||||
| 		switch ((MRESReturn)result) | ||||
| 		{ | ||||
| 		case MRES_Handled: | ||||
| 			tempRet = MRES_Handled; | ||||
| 			break; | ||||
| 		case MRES_ChangedHandled: | ||||
| 			tempRet = MRES_Handled; | ||||
| 			pWrapper->UpdateParamsFromStruct(paramStruct); | ||||
| 			break; | ||||
| 		case MRES_ChangedOverride: | ||||
| 			if (pWrapper->returnType != ReturnType_Void) | ||||
| 			{ | ||||
| 				if (returnStruct->isChanged) | ||||
| 				{ | ||||
| 					if (pWrapper->returnType == ReturnType_String || pWrapper->returnType == ReturnType_Int || pWrapper->returnType == ReturnType_Bool) | ||||
| 					{ | ||||
| 						tempRetBuf = *(void **)returnStruct->newResult; | ||||
| 					} | ||||
| 					else if (pWrapper->returnType == ReturnType_Float) | ||||
| 					{ | ||||
| 						*(float *)tempRetBuf.get() = *(float *)returnStruct->newResult; | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						tempRetBuf = returnStruct->newResult; | ||||
| 					} | ||||
| 				} | ||||
| 				else //Throw an error if no override was set
 | ||||
| 				{ | ||||
| 					tempRet = MRES_Ignored; | ||||
| 					pCallback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(pCallback, "Tried to override return value without return value being set"); | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			// TODO: Introduce that override concept in dyndetours.
 | ||||
| 			// This doesn't call the original function at the moment, but just returns the given return value.
 | ||||
| 			tempRet = MRES_Override; | ||||
| 			pWrapper->UpdateParamsFromStruct(paramStruct); | ||||
| 			break; | ||||
| 		case MRES_Override: | ||||
| 			if (pWrapper->returnType != ReturnType_Void) | ||||
| 			{ | ||||
| 				if (returnStruct->isChanged) | ||||
| 				{ | ||||
| 					// TODO: Introduce that override concept in dyndetours.
 | ||||
| 					// This doesn't call the original function at the moment, but just returns the given return value.
 | ||||
| 					tempRet = MRES_Override; | ||||
| 					if (pWrapper->returnType == ReturnType_String || pWrapper->returnType == ReturnType_Int || pWrapper->returnType == ReturnType_Bool) | ||||
| 					{ | ||||
| 						tempRetBuf = *(void **)returnStruct->newResult; | ||||
| 					} | ||||
| 					else if (pWrapper->returnType == ReturnType_Float) | ||||
| 					{ | ||||
| 						*(float *)tempRetBuf.get() = *(float *)returnStruct->newResult; | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						tempRetBuf = returnStruct->newResult; | ||||
| 					} | ||||
| 				} | ||||
| 				else //Throw an error if no override was set
 | ||||
| 				{ | ||||
| 					tempRet = MRES_Ignored; | ||||
| 					pCallback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(pCallback, "Tried to override return value without return value being set"); | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
| 		case MRES_Supercede: | ||||
| 			if (pWrapper->returnType != ReturnType_Void) | ||||
| 			{ | ||||
| 				if (returnStruct->isChanged) | ||||
| 				{ | ||||
| 					tempRet = MRES_Supercede; | ||||
| 					if (pWrapper->returnType == ReturnType_String || pWrapper->returnType == ReturnType_Int || pWrapper->returnType == ReturnType_Bool) | ||||
| 					{ | ||||
| 						tempRetBuf = *(void **)returnStruct->newResult; | ||||
| 					} | ||||
| 					else if (pWrapper->returnType == ReturnType_Float) | ||||
| 					{ | ||||
| 						*(float *)tempRetBuf.get() = *(float *)returnStruct->newResult; | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						tempRetBuf = returnStruct->newResult; | ||||
| 					} | ||||
| 				} | ||||
| 				else //Throw an error if no override was set
 | ||||
| 				{ | ||||
| 					tempRet = MRES_Ignored; | ||||
| 					pCallback->GetParentRuntime()->GetDefaultContext()->BlamePluginError(pCallback, "Tried to override return value without return value being set"); | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				tempRet = MRES_Supercede; | ||||
| 			} | ||||
| 			break; | ||||
| 		default: | ||||
| 			tempRet = MRES_Ignored; | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		// Prioritize the actions. 
 | ||||
| 		if (finalRet <= tempRet) { | ||||
| 
 | ||||
| 			// ------------------------------------		
 | ||||
| 			// Copy the action and return value.
 | ||||
| 			// ------------------------------------
 | ||||
| 			finalRet = tempRet; | ||||
| 			memcpy(*finalRetBuf, *tempRetBuf, pDetour->m_pCallingConvention->m_returnType.size); | ||||
| 		} | ||||
| 
 | ||||
| 		// Free the handles again.
 | ||||
| 		HandleSecurity sec(pCallback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity()); | ||||
| 
 | ||||
| 		if (returnStruct) | ||||
| 		{ | ||||
| 			handlesys->FreeHandle(rHndl, &sec); | ||||
| 		} | ||||
| 		if (paramStruct) | ||||
| 		{ | ||||
| 			handlesys->FreeHandle(pHndl, &sec); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (finalRet >= MRES_Override) | ||||
| 	{ | ||||
| 		void* pPtr = pDetour->m_pCallingConvention->GetReturnPtr(pDetour->m_pRegisters); | ||||
| 		memcpy(pPtr, *finalRetBuf, pDetour->m_pCallingConvention->m_returnType.size); | ||||
| 		pDetour->m_pCallingConvention->ReturnPtrChanged(pDetour->m_pRegisters, pPtr); | ||||
| 	} | ||||
| 
 | ||||
| 	return finalRet == MRES_Supercede; | ||||
| } | ||||
| 
 | ||||
| CDynamicHooksSourcePawn::CDynamicHooksSourcePawn(HookSetup *setup, CHook *pDetour, IPluginFunction *pCallback, bool post) | ||||
| { | ||||
| 	this->params = setup->params; | ||||
| 	this->offset = -1; | ||||
| 	this->returnFlag = setup->returnFlag; | ||||
| 	this->returnType = setup->returnType; | ||||
| 	this->post = post; | ||||
| 	this->plugin_callback = pCallback; | ||||
| 	this->entity = -1; | ||||
| 	this->thisType = setup->thisType; | ||||
| 	this->hookType = setup->hookType; | ||||
| 	this->m_pDetour = pDetour; | ||||
| 	this->callConv = setup->callConv; | ||||
| } | ||||
| 
 | ||||
| HookReturnStruct *CDynamicHooksSourcePawn::GetReturnStruct() | ||||
| { | ||||
| 	HookReturnStruct *res = new HookReturnStruct(); | ||||
| 	res->isChanged = false; | ||||
| 	res->type = this->returnType; | ||||
| 	res->orgResult = NULL; | ||||
| 	res->newResult = NULL; | ||||
| 
 | ||||
| 	if (this->post) | ||||
| 	{ | ||||
| 		switch (this->returnType) | ||||
| 		{ | ||||
| 		case ReturnType_String: | ||||
| 			res->orgResult = malloc(sizeof(string_t)); | ||||
| 			res->newResult = malloc(sizeof(string_t)); | ||||
| 			*(string_t *)res->orgResult = m_pDetour->GetReturnValue<string_t>(); | ||||
| 			break; | ||||
| 		case ReturnType_Int: | ||||
| 			res->orgResult = malloc(sizeof(int)); | ||||
| 			res->newResult = malloc(sizeof(int)); | ||||
| 			*(int *)res->orgResult = m_pDetour->GetReturnValue<int>(); | ||||
| 			break; | ||||
| 		case ReturnType_Bool: | ||||
| 			res->orgResult = malloc(sizeof(bool)); | ||||
| 			res->newResult = malloc(sizeof(bool)); | ||||
| 			*(bool *)res->orgResult = m_pDetour->GetReturnValue<bool>(); | ||||
| 			break; | ||||
| 		case ReturnType_Float: | ||||
| 			res->orgResult = malloc(sizeof(float)); | ||||
| 			res->newResult = malloc(sizeof(float)); | ||||
| 			*(float *)res->orgResult = m_pDetour->GetReturnValue<float>(); | ||||
| 			break; | ||||
| 		case ReturnType_Vector: | ||||
| 		{ | ||||
| 			res->orgResult = malloc(sizeof(SDKVector)); | ||||
| 			res->newResult = malloc(sizeof(SDKVector)); | ||||
| 			SDKVector vec = m_pDetour->GetReturnValue<SDKVector>(); | ||||
| 			*(SDKVector *)res->orgResult = vec; | ||||
| 			break; | ||||
| 		} | ||||
| 		default: | ||||
| 			res->orgResult = m_pDetour->GetReturnValue<void *>(); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		switch (this->returnType) | ||||
| 		{ | ||||
| 		case ReturnType_String: | ||||
| 			res->orgResult = malloc(sizeof(string_t)); | ||||
| 			res->newResult = malloc(sizeof(string_t)); | ||||
| 			*(string_t *)res->orgResult = NULL_STRING; | ||||
| 			break; | ||||
| 		case ReturnType_Vector: | ||||
| 			res->orgResult = malloc(sizeof(SDKVector)); | ||||
| 			res->newResult = malloc(sizeof(SDKVector)); | ||||
| 			*(SDKVector *)res->orgResult = SDKVector(); | ||||
| 			break; | ||||
| 		case ReturnType_Int: | ||||
| 			res->orgResult = malloc(sizeof(int)); | ||||
| 			res->newResult = malloc(sizeof(int)); | ||||
| 			*(int *)res->orgResult = 0; | ||||
| 			break; | ||||
| 		case ReturnType_Bool: | ||||
| 			res->orgResult = malloc(sizeof(bool)); | ||||
| 			res->newResult = malloc(sizeof(bool)); | ||||
| 			*(bool *)res->orgResult = false; | ||||
| 			break; | ||||
| 		case ReturnType_Float: | ||||
| 			res->orgResult = malloc(sizeof(float)); | ||||
| 			res->newResult = malloc(sizeof(float)); | ||||
| 			*(float *)res->orgResult = 0.0; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return res; | ||||
| } | ||||
| 
 | ||||
| HookParamsStruct *CDynamicHooksSourcePawn::GetParamStruct() | ||||
| { | ||||
| 	HookParamsStruct *params = new HookParamsStruct(); | ||||
| 	params->dg = this; | ||||
| 	 | ||||
| 	size_t paramsSize = this->m_pDetour->m_pCallingConvention->GetArgStackSize(); | ||||
| 	std::vector<DataTypeSized_t> &argTypes = m_pDetour->m_pCallingConvention->m_vecArgTypes; | ||||
| 	int numArgs = argTypes.size(); | ||||
| 
 | ||||
| 	params->orgParams = (void **)malloc(paramsSize); | ||||
| 	params->newParams = (void **)malloc(paramsSize); | ||||
| 	params->isChanged = (bool *)malloc(numArgs * sizeof(bool)); | ||||
| 
 | ||||
| 	size_t offset = 0; | ||||
| 	for (int i = 0; i < numArgs; i++) | ||||
| 	{ | ||||
| 		void *pArgPtr = m_pDetour->m_pCallingConvention->GetStackArgumentPtr(m_pDetour->m_pRegisters); | ||||
| 		memcpy(params->orgParams, pArgPtr, paramsSize); | ||||
| 		 | ||||
| 		*(void **)((intptr_t)params->newParams + offset) = NULL; | ||||
| 		params->isChanged[i] = false; | ||||
| 
 | ||||
| 		offset += argTypes[i].size; | ||||
| 	} | ||||
| 
 | ||||
| 	return params; | ||||
| } | ||||
| 
 | ||||
| void CDynamicHooksSourcePawn::UpdateParamsFromStruct(HookParamsStruct *params) | ||||
| { | ||||
| 	// Function had no params to update now.
 | ||||
| 	if (!params) | ||||
| 		return; | ||||
| 
 | ||||
| 	std::vector<DataTypeSized_t> &argTypes = m_pDetour->m_pCallingConvention->m_vecArgTypes; | ||||
| 	int numArgs = argTypes.size(); | ||||
| 
 | ||||
| 	int firstArg = 0; | ||||
| 	if (callConv == CallConv_THISCALL) | ||||
| 		firstArg = 1; | ||||
| 
 | ||||
| 	size_t offset = 0; | ||||
| 	for (int i = 0; i < numArgs; i++) | ||||
| 	{ | ||||
| 		int size = argTypes[i].size;; | ||||
| 		if (params->isChanged[i]) | ||||
| 		{ | ||||
| 			void *paramAddr = (void *)((intptr_t)params->newParams + offset); | ||||
| 			void *stackAddr = m_pDetour->m_pCallingConvention->GetArgumentPtr(i + firstArg, m_pDetour->m_pRegisters); | ||||
| 			memcpy(stackAddr, paramAddr, size); | ||||
| 		} | ||||
| 		offset += size; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										41
									
								
								dynhooks_sourcepawn.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								dynhooks_sourcepawn.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| #ifndef _INCLUDE_DYNHOOKS_SP_H_ | ||||
| #define _INCLUDE_DYNHOOKS_SP_H_ | ||||
| 
 | ||||
| #include "manager.h" | ||||
| #include "vhook.h" | ||||
| #include <am-vector.h> | ||||
| #include <am-hashmap.h> | ||||
| 
 | ||||
| class CDynamicHooksSourcePawn; | ||||
| typedef ke::HashMap<IPluginFunction *, CDynamicHooksSourcePawn *, ke::PointerPolicy<IPluginFunction>> CallbackMap; | ||||
| typedef ke::Vector<CDynamicHooksSourcePawn *> PluginCallbackList; | ||||
| typedef ke::HashMap<CHook *, PluginCallbackList *, ke::PointerPolicy<CHook>> DetourMap; | ||||
| 
 | ||||
| //extern ke::Vector<CHook *> g_pDetours;
 | ||||
| // Keep a list of plugin callback -> Hook wrapper for easily removing plugin hooks
 | ||||
| //extern CallbackMap g_pPluginPreDetours;
 | ||||
| //extern CallbackMap g_pPluginPostDetours;
 | ||||
| // Keep a list of hook -> callbacks for calling in the detour handler
 | ||||
| extern DetourMap g_pPreDetours; | ||||
| extern DetourMap g_pPostDetours; | ||||
| 
 | ||||
| class CDynamicHooksSourcePawn : public DHooksInfo { | ||||
| public: | ||||
| 	CDynamicHooksSourcePawn(HookSetup *setup, CHook *pDetour, IPluginFunction *pCallback, bool post); | ||||
| 
 | ||||
| 	HookReturnStruct *GetReturnStruct(); | ||||
| 	HookParamsStruct *CDynamicHooksSourcePawn::GetParamStruct(); | ||||
| 	void UpdateParamsFromStruct(HookParamsStruct *params); | ||||
| 
 | ||||
| public: | ||||
| 	CHook *m_pDetour; | ||||
| 	CallingConvention callConv; | ||||
| }; | ||||
| 
 | ||||
| ICallingConvention *ConstructCallingConvention(HookSetup *setup); | ||||
| bool HandleDetour(HookType_t hookType, CHook* pDetour); | ||||
| bool AddDetourPluginHook(HookType_t hookType, CHook *pDetour, HookSetup *setup, IPluginFunction *pCallback); | ||||
| bool RemoveDetourPluginHook(HookType_t hookType, CHook *pDetour, IPluginFunction *pCallback); | ||||
| void RemoveAllCallbacksForContext(IPluginContext *pContext); | ||||
| 
 | ||||
| #endif | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "extension.h" | ||||
| #include "listeners.h" | ||||
| #include "dynhooks_sourcepawn.h" | ||||
| 
 | ||||
| DHooks g_DHooksIface;		/**< Global singleton for extension's main interface */ | ||||
| SMEXT_LINK(&g_DHooksIface); | ||||
| @ -35,6 +36,18 @@ bool DHooks::SDK_OnLoad(char *error, size_t maxlength, bool late) | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!g_pPreDetours.init()) | ||||
| 	{ | ||||
| 		snprintf(error, maxlength, "Could not initialize pre hook detours hashmap."); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!g_pPostDetours.init()) | ||||
| 	{ | ||||
| 		snprintf(error, maxlength, "Could not initialize post hook detours hashmap."); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	sharesys->AddDependency(myself, "bintools.ext", true, true); | ||||
| 	sharesys->AddDependency(myself, "sdktools.ext", true, true); | ||||
| 	sharesys->AddDependency(myself, "sdkhooks.ext", true, true); | ||||
| @ -76,6 +89,8 @@ void DHooks::SDK_OnAllLoaded() | ||||
| void DHooks::SDK_OnUnload() | ||||
| { | ||||
| 	CleanupHooks(); | ||||
| 	// FIXME: Unhook only functions that are hooked by a plugin. + cleanup
 | ||||
| 	GetHookManager()->UnhookAllFunctions(); | ||||
| 	if(g_pEntityListener) | ||||
| 	{ | ||||
| 		g_pEntityListener->CleanupListeners(); | ||||
| @ -102,6 +117,7 @@ bool DHooks::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, boo | ||||
| void DHooks::OnPluginUnloaded(IPlugin *plugin) | ||||
| { | ||||
| 	CleanupHooks(plugin->GetBaseContext()); | ||||
| 	RemoveAllCallbacksForContext(plugin->GetBaseContext()); | ||||
| 	if(g_pEntityListener) | ||||
| 	{ | ||||
| 		g_pEntityListener->CleanupListeners(plugin->GetBaseContext()); | ||||
|  | ||||
| @ -3,6 +3,7 @@ | ||||
| 
 | ||||
| #include "extension.h" | ||||
| #include "vhook.h" | ||||
| #include <am-vector.h> | ||||
| 
 | ||||
| enum ListenType | ||||
| { | ||||
|  | ||||
							
								
								
									
										180
									
								
								natives.cpp
									
									
									
									
									
								
							
							
						
						
									
										180
									
								
								natives.cpp
									
									
									
									
									
								
							| @ -1,5 +1,14 @@ | ||||
| #include "natives.h" | ||||
| #include "util.h" | ||||
| #include "dynhooks_sourcepawn.h" | ||||
| 
 | ||||
| // Must match same enum in sdktools.inc
 | ||||
| enum SDKFuncConfSource | ||||
| { | ||||
| 	SDKConf_Virtual, | ||||
| 	SDKConf_Signature, | ||||
| 	SDKConf_Address | ||||
| }; | ||||
| 
 | ||||
| bool GetHandleIfValidOrError(HandleType_t type, void **object, IPluginContext *pContext, cell_t param) | ||||
| { | ||||
| @ -38,6 +47,77 @@ cell_t Native_CreateHook(IPluginContext *pContext, const cell_t *params) | ||||
| 
 | ||||
| 	return hndl; | ||||
| } | ||||
| 
 | ||||
| //native Handle:DHookCreateDetour(Address:funcaddr, CallingConvention callConv, ReturnType:returntype, ThisPointerType:thistype);
 | ||||
| cell_t Native_CreateDetour(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	HookSetup *setup = new HookSetup((ReturnType)params[3], PASSFLAG_BYVAL, (CallingConvention)params[2], (ThisPointerType)params[4], (void *)params[1]); | ||||
| 
 | ||||
| 	Handle_t hndl = handlesys->CreateHandle(g_HookSetupHandle, setup, pContext->GetIdentity(), myself->GetIdentity(), NULL); | ||||
| 
 | ||||
| 	if (!hndl) | ||||
| 	{ | ||||
| 		delete setup; | ||||
| 		return pContext->ThrowNativeError("Failed to create hook"); | ||||
| 	} | ||||
| 
 | ||||
| 	return hndl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //native bool:DHookSetFromConf(Handle:setup, Handle:gameconf, SDKFuncConfSource:source, const String:name[]);
 | ||||
| cell_t Native_SetFromConf(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	HookSetup *setup; | ||||
| 	if (!GetHandleIfValidOrError(g_HookSetupHandle, (void **)&setup, pContext, params[1])) | ||||
| 	{ | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	IGameConfig *conf; | ||||
| 	HandleError err; | ||||
| 	if ((conf = gameconfs->ReadHandle(params[2], pContext->GetIdentity(), &err)) == nullptr) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[2], err); | ||||
| 	} | ||||
| 
 | ||||
| 	char *key; | ||||
| 	pContext->LocalToString(params[4], &key); | ||||
| 
 | ||||
| 	int offset = -1; | ||||
| 	void *addr = nullptr;; | ||||
| 	switch (params[3]) | ||||
| 	{ | ||||
| 	case SDKConf_Virtual: | ||||
| 		if (!conf->GetOffset(key, &offset)) | ||||
| 		{ | ||||
| 			return 0; | ||||
| 		} | ||||
| 		break; | ||||
| 	case SDKConf_Signature: | ||||
| 		if (!conf->GetMemSig(key, &addr) || !addr) | ||||
| 		{ | ||||
| 			return 0; | ||||
| 		} | ||||
| 		break; | ||||
| 	case SDKConf_Address: | ||||
| 		if (!conf->GetAddress(key, &addr) || !addr) | ||||
| 		{ | ||||
| 			return 0; | ||||
| 		} | ||||
| 		break; | ||||
| 	default: | ||||
| 		return pContext->ThrowNativeError("Unknown SDKFuncConfSource: %d", params[3]); | ||||
| 	} | ||||
| 
 | ||||
| 	// Save the new info. This always invalidates the other option.
 | ||||
| 	// Detour or vhook.
 | ||||
| 	setup->funcAddr = addr; | ||||
| 	setup->offset = offset; | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| //native bool:DHookAddParam(Handle:setup, HookParamType:type); OLD
 | ||||
| //native bool:DHookAddParam(Handle:setup, HookParamType:type, size=-1, DHookPassFlag:flag=DHookPass_ByVal);
 | ||||
| cell_t Native_AddParam(IPluginContext *pContext, const cell_t *params) | ||||
| @ -80,6 +160,87 @@ cell_t Native_AddParam(IPluginContext *pContext, const cell_t *params) | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // native bool:DHookEnableDetour(Handle:setup, bool:post, DHookCallback:callback);
 | ||||
| cell_t Native_EnableDetour(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	HookSetup *setup; | ||||
| 
 | ||||
| 	if (!GetHandleIfValidOrError(g_HookSetupHandle, (void **)&setup, pContext, params[1])) | ||||
| 	{ | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (setup->funcAddr == nullptr) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Hook not setup for a detour."); | ||||
| 	} | ||||
| 
 | ||||
| 	IPluginFunction *callback = pContext->GetFunctionById(params[3]); | ||||
| 	if (!callback) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Failed to retrieve function by id"); | ||||
| 	} | ||||
| 
 | ||||
| 	bool post = params[2] != 0; | ||||
| 	HookType_t hookType = post ? HOOKTYPE_POST : HOOKTYPE_PRE; | ||||
| 
 | ||||
| 	// Check if we already detoured that function.
 | ||||
| 	CHookManager *pDetourManager = GetHookManager(); | ||||
| 	CHook* pDetour = pDetourManager->FindHook(setup->funcAddr); | ||||
| 
 | ||||
| 	// If there is no detour on this function yet, create it.
 | ||||
| 	if (!pDetour) | ||||
| 	{ | ||||
| 		ICallingConvention *pCallConv = ConstructCallingConvention(setup); | ||||
| 		pDetour = pDetourManager->HookFunction(setup->funcAddr, pCallConv); | ||||
| 	} | ||||
| 
 | ||||
| 	// Register our pre/post handler.
 | ||||
| 	pDetour->AddCallback(hookType, (HookHandlerFn *)&HandleDetour); | ||||
| 
 | ||||
| 	// Add the plugin callback to the map.
 | ||||
| 	return AddDetourPluginHook(hookType, pDetour, setup, callback); | ||||
| } | ||||
| 
 | ||||
| // native bool:DHookDisableDetour(Handle:setup, bool:post, DHookCallback:callback);
 | ||||
| cell_t Native_DisableDetour(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	HookSetup *setup; | ||||
| 
 | ||||
| 	if (!GetHandleIfValidOrError(g_HookSetupHandle, (void **)&setup, pContext, params[1])) | ||||
| 	{ | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (setup->funcAddr == nullptr) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Hook not setup for a detour."); | ||||
| 	} | ||||
| 
 | ||||
| 	IPluginFunction *callback = pContext->GetFunctionById(params[3]); | ||||
| 	if (!callback) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Failed to retrieve function by id"); | ||||
| 	} | ||||
| 
 | ||||
| 	bool post = params[2] != 0; | ||||
| 	HookType_t hookType = post ? HOOKTYPE_POST : HOOKTYPE_PRE; | ||||
| 
 | ||||
| 	// Check if we already detoured that function.
 | ||||
| 	CHookManager *pDetourManager = GetHookManager(); | ||||
| 	CHook* pDetour = pDetourManager->FindHook(setup->funcAddr); | ||||
| 
 | ||||
| 	if (!pDetour || !pDetour->IsCallbackRegistered(hookType, (HookHandlerFn *)&HandleDetour)) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Function not detoured."); | ||||
| 	} | ||||
| 
 | ||||
| 	// Remove the callback from the hook.
 | ||||
| 	return RemoveDetourPluginHook(hookType, pDetour, callback); | ||||
| } | ||||
| 
 | ||||
| // native DHookEntity(Handle:setup, bool:post, entity, DHookRemovalCB:removalcb);
 | ||||
| cell_t Native_HookEntity(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| @ -90,6 +251,11 @@ cell_t Native_HookEntity(IPluginContext *pContext, const cell_t *params) | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (setup->offset == -1) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Hook not setup for a virtual hook."); | ||||
| 	} | ||||
| 
 | ||||
| 	if(setup->hookType != HookType_Entity) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Hook is not an entity hook"); | ||||
| @ -133,6 +299,11 @@ cell_t Native_HookGamerules(IPluginContext *pContext, const cell_t *params) | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (setup->offset == -1) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Hook not setup for a virtual hook."); | ||||
| 	} | ||||
| 
 | ||||
| 	if(setup->hookType != HookType_GameRules) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Hook is not a gamerules hook"); | ||||
| @ -178,6 +349,11 @@ cell_t Native_HookRaw(IPluginContext *pContext, const cell_t *params) | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (setup->offset == -1) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Hook not setup for a virtual hook."); | ||||
| 	} | ||||
| 
 | ||||
| 	if(setup->hookType != HookType_Raw) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Hook is not a raw hook"); | ||||
| @ -1036,7 +1212,11 @@ cell_t Native_IsNullParam(IPluginContext *pContext, const cell_t *params) | ||||
| sp_nativeinfo_t g_Natives[] =  | ||||
| { | ||||
| 	{"DHookCreate",							Native_CreateHook}, | ||||
| 	{"DHookCreateDetour",					Native_CreateDetour}, | ||||
| 	{"DHookSetFromConf",					Native_SetFromConf }, | ||||
| 	{"DHookAddParam",						Native_AddParam}, | ||||
| 	{"DHookEnableDetour",					Native_EnableDetour}, | ||||
| 	//{"DHookDisableDetour",					Native_DisableDetour},
 | ||||
| 	{"DHookEntity",							Native_HookEntity}, | ||||
| 	{"DHookGamerules",						Native_HookGamerules}, | ||||
| 	{"DHookRaw",							Native_HookRaw}, | ||||
|  | ||||
| @ -63,7 +63,7 @@ | ||||
| #define SMEXT_ENABLE_HANDLESYS | ||||
| #define SMEXT_ENABLE_PLAYERHELPERS | ||||
| //#define SMEXT_ENABLE_DBMANAGER
 | ||||
| //#define SMEXT_ENABLE_GAMECONF
 | ||||
| #define SMEXT_ENABLE_GAMECONF | ||||
| //#define SMEXT_ENABLE_MEMUTILS
 | ||||
| #define SMEXT_ENABLE_GAMEHELPERS | ||||
| //#define SMEXT_ENABLE_TIMERSYS
 | ||||
|  | ||||
| @ -72,6 +72,13 @@ enum HookType | ||||
| 	HookType_Raw | ||||
| }; | ||||
| 
 | ||||
| enum CallingConvention | ||||
| { | ||||
| 	CallConv_CDECL, | ||||
| 	CallConv_THISCALL, | ||||
| 	CallConv_STDCALL, | ||||
| }; | ||||
| 
 | ||||
| enum MRESReturn | ||||
| { | ||||
| 	MRES_ChangedHandled = -2,	// Use changed values and return MRES_Handled
 | ||||
| @ -176,6 +183,10 @@ native bool DHookRemoveEntityListener(ListenType type, ListenCB callback); | ||||
| */ | ||||
| native Handle DHookCreate(int offset, HookType hooktype, ReturnType returntype, ThisPointerType thistype, DHookCallback callback); | ||||
| 
 | ||||
| native Handle DHookCreateDetour(Address funcaddr, CallingConvention callConv, ReturnType returntype, ThisPointerType thistype); | ||||
| native bool DHookSetFromConf(Handle setup, Handle gameconf, SDKFuncConfSource source, const char[] name); | ||||
| native bool:DHookEnableDetour(Handle:setup, bool:post, DHookCallback callback); | ||||
| 
 | ||||
| /* Adds param to a hook setup | ||||
|  * | ||||
|  * @param setup			Setup handle to add the param to. | ||||
|  | ||||
							
								
								
									
										53
									
								
								util.cpp
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								util.cpp
									
									
									
									
									
								
							| @ -46,3 +46,56 @@ size_t GetParamsSize(DHooksCallback *dg)//Get the full size, this is for creatin | ||||
| 
 | ||||
| 	return res; | ||||
| } | ||||
| 
 | ||||
| DataType_t DynamicHooks_ConvertParamTypeFrom(HookParamType type) | ||||
| { | ||||
| 	switch (type) | ||||
| 	{ | ||||
| 	case HookParamType_Int: | ||||
| 		return DATA_TYPE_INT; | ||||
| 	case HookParamType_Bool: | ||||
| 		return DATA_TYPE_BOOL; | ||||
| 	case HookParamType_Float: | ||||
| 		return DATA_TYPE_FLOAT; | ||||
| 	case HookParamType_StringPtr: | ||||
| 	case HookParamType_CharPtr: | ||||
| 	case HookParamType_VectorPtr: | ||||
| 	case HookParamType_CBaseEntity: | ||||
| 	case HookParamType_ObjectPtr: | ||||
| 	case HookParamType_Edict: | ||||
| 		return DATA_TYPE_POINTER; | ||||
| 	case HookParamType_Object: | ||||
| 		return DATA_TYPE_OBJECT; | ||||
| 	default: | ||||
| 		smutils->LogError(myself, "Unhandled parameter type %d!", type); | ||||
| 	} | ||||
| 
 | ||||
| 	return DATA_TYPE_POINTER; | ||||
| } | ||||
| 
 | ||||
| DataType_t DynamicHooks_ConvertReturnTypeFrom(ReturnType type) | ||||
| { | ||||
| 	switch (type) | ||||
| 	{ | ||||
| 	case ReturnType_Void: | ||||
| 		return DATA_TYPE_VOID; | ||||
| 	case ReturnType_Int: | ||||
| 		return DATA_TYPE_INT; | ||||
| 	case ReturnType_Bool: | ||||
| 		return DATA_TYPE_BOOL; | ||||
| 	case ReturnType_Float: | ||||
| 		return DATA_TYPE_FLOAT; | ||||
| 	case ReturnType_StringPtr: | ||||
| 	case ReturnType_CharPtr: | ||||
| 	case ReturnType_VectorPtr: | ||||
| 	case ReturnType_CBaseEntity: | ||||
| 	case ReturnType_Edict: | ||||
| 		return DATA_TYPE_POINTER; | ||||
| 	case ReturnType_Vector: | ||||
| 		return DATA_TYPE_OBJECT; | ||||
| 	default: | ||||
| 		smutils->LogError(myself, "Unhandled return type %d!", type); | ||||
| 	} | ||||
| 
 | ||||
| 	return DATA_TYPE_VOID; | ||||
| } | ||||
|  | ||||
							
								
								
									
										4
									
								
								util.h
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								util.h
									
									
									
									
									
								
							| @ -2,9 +2,13 @@ | ||||
| #define _INCLUDE_UTIL_FUNCTIONS_H_ | ||||
| 
 | ||||
| #include "vhook.h" | ||||
| #include "convention.h" | ||||
| 
 | ||||
| size_t GetParamOffset(HookParamsStruct *params, unsigned int index); | ||||
| void * GetObjectAddr(HookParamType type, unsigned int flags, void **params, size_t offset); | ||||
| size_t GetParamTypeSize(HookParamType type); | ||||
| size_t GetParamsSize(DHooksCallback *dg); | ||||
| 
 | ||||
| DataType_t DynamicHooks_ConvertParamTypeFrom(HookParamType type); | ||||
| DataType_t DynamicHooks_ConvertReturnTypeFrom(ReturnType type); | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										114
									
								
								vhook.cpp
									
									
									
									
									
								
							
							
						
						
									
										114
									
								
								vhook.cpp
									
									
									
									
									
								
							| @ -1,6 +1,7 @@ | ||||
| #include "vhook.h" | ||||
| #include "vfunc_call.h" | ||||
| #include "util.h" | ||||
| #include <macro-assembler-x86.h> | ||||
| 
 | ||||
| SourceHook::IHookManagerAutoGen *g_pHookManager = NULL; | ||||
| 
 | ||||
| @ -14,6 +15,95 @@ using namespace SourceHook; | ||||
| #define OBJECT_OFFSET (sizeof(void *)*2) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef  WIN32 | ||||
| void *GenerateThunk(ReturnType type) | ||||
| { | ||||
| 	sp::MacroAssembler masm; | ||||
| 	static const size_t kStackNeeded = (2) * 4; // 2 args max
 | ||||
| 	static const size_t kReserve = ke::Align(kStackNeeded + 8, 16) - 8; | ||||
| 
 | ||||
| 	masm.push(ebp); | ||||
| 	masm.movl(ebp, esp); | ||||
| 	masm.subl(esp, kReserve); | ||||
| 	if (type != ReturnType_String && type != ReturnType_Vector) | ||||
| 	{ | ||||
| 		masm.lea(eax, Operand(ebp, 12)); // grab the incoming caller argument vector
 | ||||
| 		masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
 | ||||
| 		masm.movl(eax, Operand(ebp, 8)); // grab the |this|
 | ||||
| 		masm.movl(Operand(esp, 0 * 4), eax); // set |this| as the 1st argument*/
 | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		masm.lea(eax, Operand(ebp, 8)); // grab the incoming caller argument vector
 | ||||
| 		masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
 | ||||
| 		masm.movl(eax, Operand(ebp, 12)); // grab the |this|
 | ||||
| 		masm.movl(Operand(esp, 0 * 4), eax); // set |this| as the 1st argument*/
 | ||||
| 	} | ||||
| 	if (type == ReturnType_Float) | ||||
| 	{ | ||||
| 		masm.call(ExternalAddress((void *)Callback_float)); | ||||
| 	} | ||||
| 	else if (type == ReturnType_Vector) | ||||
| 	{ | ||||
| 		masm.call(ExternalAddress((void *)Callback_vector)); | ||||
| 	} | ||||
| 	else if (type == ReturnType_String) | ||||
| 	{ | ||||
| 		masm.call(ExternalAddress((void *)Callback_stringt)); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		masm.call(ExternalAddress((void *)Callback)); | ||||
| 	} | ||||
| 	masm.addl(esp, kReserve); | ||||
| 	masm.pop(ebp); // restore ebp
 | ||||
| 	masm.ret(); | ||||
| 
 | ||||
| 	void *base = g_pSM->GetScriptingEngine()->AllocatePageMemory(masm.length()); | ||||
| 	masm.emitToExecutableMemory(base); | ||||
| 	return base; | ||||
| } | ||||
| #else | ||||
| // HUGE THANKS TO BAILOPAN (dvander)!
 | ||||
| void *GenerateThunk(ReturnType type) | ||||
| { | ||||
| 	sp::MacroAssembler masm; | ||||
| 	static const size_t kStackNeeded = (3 + 1) * 4; // 3 args max, 1 locals max
 | ||||
| 	static const size_t kReserve = ke::Align(kStackNeeded + 8, 16) - 8; | ||||
| 
 | ||||
| 	masm.push(ebp); | ||||
| 	masm.movl(ebp, esp); | ||||
| 	masm.subl(esp, kReserve); | ||||
| 	masm.lea(eax, Operand(esp, 3 * 4)); // ptr to 2nd var after argument space
 | ||||
| 	masm.movl(Operand(esp, 2 * 4), eax); // set the ptr as the third argument
 | ||||
| 	masm.lea(eax, Operand(ebp, 8)); // grab the incoming caller argument vector
 | ||||
| 	masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
 | ||||
| 	masm.movl(Operand(esp, 0 * 4), ecx); // set |this| as the 1st argument
 | ||||
| 	if (type == ReturnType_Float) | ||||
| 	{ | ||||
| 		masm.call(ExternalAddress(Callback_float)); | ||||
| 	} | ||||
| 	else if (type == ReturnType_Vector) | ||||
| 	{ | ||||
| 		masm.call(ExternalAddress(Callback_vector)); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		masm.call(ExternalAddress(Callback)); | ||||
| 	} | ||||
| 	masm.movl(ecx, Operand(esp, 3 * 4)); | ||||
| 	masm.addl(esp, kReserve); | ||||
| 	masm.pop(ebp); // restore ebp
 | ||||
| 	masm.pop(edx); // grab return address in edx
 | ||||
| 	masm.addl(esp, ecx); // remove arguments
 | ||||
| 	masm.jmp(edx); // return to caller
 | ||||
| 
 | ||||
| 	void *base = g_pSM->GetScriptingEngine()->AllocatePageMemory(masm.length()); | ||||
| 	masm.emitToExecutableMemory(base); | ||||
| 	return base; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| DHooksManager::DHooksManager(HookSetup *setup, void *iface, IPluginFunction *remove_callback, bool post) | ||||
| { | ||||
| 	this->callback = MakeHandler(setup->returnType); | ||||
| @ -121,6 +211,27 @@ size_t GetStackArgsSize(DHooksCallback *dg) | ||||
| 	return res; | ||||
| } | ||||
| 
 | ||||
| HookReturnStruct::~HookReturnStruct() | ||||
| { | ||||
| 	if (this->type == ReturnType_String || this->type == ReturnType_Int || this->type == ReturnType_Bool || this->type == ReturnType_Float || this->type == ReturnType_Vector) | ||||
| 	{ | ||||
| 		free(this->newResult); | ||||
| 		free(this->orgResult); | ||||
| 	} | ||||
| 	else if (this->isChanged) | ||||
| 	{ | ||||
| 		if (this->type == ReturnType_CharPtr) | ||||
| 		{ | ||||
| 			delete[](char *)this->newResult; | ||||
| 		} | ||||
| 		else if (this->type == ReturnType_VectorPtr) | ||||
| 		{ | ||||
| 			delete (SDKVector *)this->newResult; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| HookParamsStruct::~HookParamsStruct() | ||||
| { | ||||
| 	if (this->orgParams != NULL) | ||||
| @ -329,7 +440,8 @@ void *Callback(DHooksCallback *dg, void **argStack) | ||||
| 			dg->plugin_callback->Cancel(); | ||||
| 			if(returnStruct) | ||||
| 			{ | ||||
| 				delete returnStruct; | ||||
| 				HandleSecurity sec(dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity()); | ||||
| 				handlesys->FreeHandle(rHndl, &sec); | ||||
| 			} | ||||
| 			if(paramStruct) | ||||
| 			{ | ||||
|  | ||||
							
								
								
									
										143
									
								
								vhook.h
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								vhook.h
									
									
									
									
									
								
							| @ -3,7 +3,13 @@ | ||||
| 
 | ||||
| #include "extension.h" | ||||
| #include <sourcehook.h> | ||||
| #include <macro-assembler-x86.h> | ||||
| 
 | ||||
| enum CallingConvention | ||||
| { | ||||
| 	CallConv_CDECL, | ||||
| 	CallConv_THISCALL, | ||||
| 	CallConv_STDCALL, | ||||
| }; | ||||
| 
 | ||||
| enum MRESReturn | ||||
| { | ||||
| @ -86,29 +92,16 @@ struct ParamInfo | ||||
| 	SourceHook::PassInfo::PassType pass_type; | ||||
| }; | ||||
| 
 | ||||
| #ifdef  WIN32 | ||||
| #define OBJECT_OFFSET sizeof(void *) | ||||
| #else | ||||
| #define OBJECT_OFFSET (sizeof(void *)*2) | ||||
| #endif | ||||
| 
 | ||||
| class HookReturnStruct | ||||
| { | ||||
| public: | ||||
| 	~HookReturnStruct() | ||||
| 	{ | ||||
| 		if(this->type == ReturnType_String || this->type == ReturnType_Int || this->type == ReturnType_Bool || this->type == ReturnType_Float || this->type == ReturnType_Vector) | ||||
| 		{ | ||||
| 			free(this->newResult); | ||||
| 			free(this->orgResult); | ||||
| 		} | ||||
| 		else if(this->isChanged) | ||||
| 		{ | ||||
| 			if(this->type == ReturnType_CharPtr) | ||||
| 			{ | ||||
| 				delete [] (char *)this->newResult; | ||||
| 			} | ||||
| 			else if(this->type == ReturnType_VectorPtr) | ||||
| 			{ | ||||
| 				delete (SDKVector *)this->newResult; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| 	~HookReturnStruct(); | ||||
| public: | ||||
| 	ReturnType type; | ||||
| 	bool isChanged; | ||||
| @ -162,95 +155,7 @@ bool SetupHookManager(ISmmAPI *ismm); | ||||
| void CleanupHooks(IPluginContext *pContext = NULL); | ||||
| size_t GetParamTypeSize(HookParamType type); | ||||
| SourceHook::PassInfo::PassType GetParamTypePassType(HookParamType type); | ||||
| 
 | ||||
| #ifndef  WIN32 | ||||
| static void *GenerateThunk(ReturnType type) | ||||
| { | ||||
| 	sp::MacroAssemblerX86 masm; | ||||
| 	static const size_t kStackNeeded = (2) * 4; // 2 args max
 | ||||
| 	static const size_t kReserve = ke::Align(kStackNeeded+8, 16)-8; | ||||
| 
 | ||||
| 	masm.push(ebp); | ||||
| 	masm.movl(ebp, esp); | ||||
| 	masm.subl(esp, kReserve); | ||||
| 	if(type != ReturnType_String && type != ReturnType_Vector) | ||||
| 	{ | ||||
| 		masm.lea(eax, Operand(ebp, 12)); // grab the incoming caller argument vector
 | ||||
| 		masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
 | ||||
| 		masm.movl(eax, Operand(ebp, 8)); // grab the |this|
 | ||||
| 		masm.movl(Operand(esp, 0 * 4), eax); // set |this| as the 1st argument*/
 | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		masm.lea(eax, Operand(ebp, 8)); // grab the incoming caller argument vector
 | ||||
| 		masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
 | ||||
| 		masm.movl(eax, Operand(ebp, 12)); // grab the |this|
 | ||||
| 		masm.movl(Operand(esp, 0 * 4), eax); // set |this| as the 1st argument*/
 | ||||
| 	} | ||||
| 	if(type == ReturnType_Float) | ||||
| 	{ | ||||
| 		masm.call(ExternalAddress((void *)Callback_float)); | ||||
| 	} | ||||
| 	else if(type == ReturnType_Vector) | ||||
| 	{ | ||||
| 		masm.call(ExternalAddress((void *)Callback_vector)); | ||||
| 	} | ||||
| 	else if(type == ReturnType_String) | ||||
| 	{ | ||||
| 		masm.call(ExternalAddress((void *)Callback_stringt)); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		masm.call(ExternalAddress((void *)Callback)); | ||||
| 	} | ||||
| 	masm.addl(esp, kReserve); | ||||
| 	masm.pop(ebp); // restore ebp
 | ||||
| 	masm.ret(); | ||||
| 
 | ||||
| 	void *base =  g_pSM->GetScriptingEngine()->AllocatePageMemory(masm.length()); | ||||
| 	masm.emitToExecutableMemory(base); | ||||
| 	return base; | ||||
| } | ||||
| #else | ||||
| // HUGE THANKS TO BAILOPAN (dvander)!
 | ||||
| static void *GenerateThunk(ReturnType type) | ||||
| { | ||||
| 	sp::MacroAssemblerX86 masm; | ||||
| 	static const size_t kStackNeeded = (3 + 1) * 4; // 3 args max, 1 locals max
 | ||||
| 	static const size_t kReserve = ke::Align(kStackNeeded+8, 16)-8; | ||||
| 
 | ||||
| 	masm.push(ebp); | ||||
| 	masm.movl(ebp, esp); | ||||
| 	masm.subl(esp, kReserve); | ||||
| 	masm.lea(eax, Operand(esp, 3 * 4)); // ptr to 2nd var after argument space
 | ||||
| 	masm.movl(Operand(esp, 2 * 4), eax); // set the ptr as the third argument
 | ||||
| 	masm.lea(eax, Operand(ebp, 8)); // grab the incoming caller argument vector
 | ||||
| 	masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument
 | ||||
| 	masm.movl(Operand(esp, 0 * 4), ecx); // set |this| as the 1st argument
 | ||||
| 	if(type == ReturnType_Float) | ||||
| 	{ | ||||
| 		masm.call(ExternalAddress(Callback_float)); | ||||
| 	} | ||||
| 	else if(type == ReturnType_Vector) | ||||
| 	{ | ||||
| 		masm.call(ExternalAddress(Callback_vector)); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		masm.call(ExternalAddress(Callback)); | ||||
| 	} | ||||
| 	masm.movl(ecx, Operand(esp, 3*4)); | ||||
| 	masm.addl(esp, kReserve); | ||||
| 	masm.pop(ebp); // restore ebp
 | ||||
| 	masm.pop(edx); // grab return address in edx
 | ||||
| 	masm.addl(esp, ecx); // remove arguments
 | ||||
| 	masm.jmp(edx); // return to caller
 | ||||
|   | ||||
| 	void *base =  g_pSM->GetScriptingEngine()->AllocatePageMemory(masm.length()); | ||||
| 	masm.emitToExecutableMemory(base); | ||||
| 	return base; | ||||
| } | ||||
| #endif | ||||
| void *GenerateThunk(ReturnType type); | ||||
| 
 | ||||
| static DHooksCallback *MakeHandler(ReturnType type) | ||||
| { | ||||
| @ -280,7 +185,7 @@ public: | ||||
| 	void **orgParams; | ||||
| 	void **newParams; | ||||
| 	bool *isChanged; | ||||
| 	DHooksCallback *dg; | ||||
| 	DHooksInfo *dg; | ||||
| }; | ||||
| 
 | ||||
| class HookSetup | ||||
| @ -291,18 +196,33 @@ public: | ||||
| 		this->returnType = returnType; | ||||
| 		this->returnFlag = returnFlag; | ||||
| 		this->hookType = hookType; | ||||
| 		this->callConv = CallConv_THISCALL; | ||||
| 		this->thisType = thisType; | ||||
| 		this->offset = offset; | ||||
| 		this->funcAddr = nullptr; | ||||
| 		this->callback = callback; | ||||
| 	}; | ||||
| 	HookSetup(ReturnType returnType, unsigned int returnFlag, CallingConvention callConv, ThisPointerType thisType, void *funcAddr) | ||||
| 	{ | ||||
| 		this->returnType = returnType; | ||||
| 		this->returnFlag = returnFlag; | ||||
| 		this->hookType = HookType_Raw; | ||||
| 		this->callConv = callConv; | ||||
| 		this->thisType = thisType; | ||||
| 		this->offset = -1; | ||||
| 		this->funcAddr = funcAddr; | ||||
| 		this->callback = nullptr; | ||||
| 	}; | ||||
| 	~HookSetup(){}; | ||||
| public: | ||||
| 	unsigned int returnFlag; | ||||
| 	ReturnType returnType; | ||||
| 	HookType hookType; | ||||
| 	CallingConvention callConv; | ||||
| 	ThisPointerType thisType; | ||||
| 	SourceHook::CVector<ParamInfo> params; | ||||
| 	int offset; | ||||
| 	void *funcAddr; | ||||
| 	IPluginFunction *callback; | ||||
| }; | ||||
| 
 | ||||
| @ -335,6 +255,7 @@ public: | ||||
| }; | ||||
| 
 | ||||
| size_t GetStackArgsSize(DHooksCallback *dg); | ||||
| cell_t GetThisPtr(void *iface, ThisPointerType type); | ||||
| 
 | ||||
| extern IBinTools *g_pBinTools; | ||||
| extern HandleType_t g_HookParamsHandle; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user