├── README.md ├── as_jit.cpp ├── as_jit.h ├── virtual_asm.h ├── virtual_asm_linux.cpp ├── virtual_asm_windows.cpp ├── virtual_asm_x64.cpp └── virtual_asm_x86.cpp /README.md: -------------------------------------------------------------------------------- 1 | Angelscript JIT Compiler 2 | ======================== 3 | A Just-In-Time Compiler for use with AngelScript. 4 | 5 | Currently supports x86 and x86_64 processors on both Windows (using MSVC 2010 or later) and Linux (using GCC 4.6.2 or later) 6 | 7 | Compatible with version of 2.31.0 of the AngelScript library. 8 | 9 | License (MIT) 10 | ------------- 11 | 12 | Copyright (C) 2012-2016 Blind Mind Studios 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | 20 | Utilizing the JIT 21 | ----------------- 22 | 23 | The JIT makes extensive use of C++11 additions, such as Lambdas and the auto keyword. For GCC, use "-std=c++11" to force the new standard. MSVC 2010 is compatible with all C++11 features utilized. 24 | 25 | This short example shows the basics of utilizing the JIT. The folder containing "angelscript.h" should be an include path in the project. 26 | When including files into the project, choose one of "virtual_asm_windows.cpp" and "virtual_asm_linux.cpp" depending on your intended platform. 27 | 28 | #include "angelscript.h" 29 | #include "as_jit.h" 30 | 31 | int main() { 32 | asIScriptEngine* engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); 33 | 34 | //Create the JIT Compiler. The build flags are explained below, 35 | //as well as in as_jit.h 36 | asCJITCompiler* jit = new asCJITCompiler(0); 37 | 38 | //Enable JIT helper instructions; without these, 39 | //the JIT will not be invoked 40 | engine->SetEngineProperty(asEP_INCLUDE_JIT_INSTRUCTIONS, 1); 41 | 42 | //Bind the JIT compiler to the engine 43 | engine->SetJITCompiler(jit); 44 | 45 | //Load your scripts. The JIT will allocate code pages and build 46 | //native code; note that some native execution will occur 47 | //(e.g. for global variables) 48 | //The JIT is thread-safe, so multiple engines can use the same 49 | //JIT Compiler, and multiple engines can be compiling at once 50 | LoadAndCompileScripts(); 51 | 52 | //Optionally, you can finalize the JIT's code pages, 53 | //preventing any alteration to the native code 54 | jit->finalizePages(); 55 | 56 | //Now that the JIT is in place, the scripts will be executed 57 | //almost entirely in native code 58 | RunScripts(); 59 | 60 | //Clean up your engine. Code pages will automatically be cleared 61 | //by the JIT when the engine is released. 62 | DiscardModules(); 63 | engine->Release(); 64 | delete jit; 65 | 66 | return 0; 67 | } 68 | 69 | Build Flags 70 | ----------- 71 | 72 | *JIT_NO_SUSPEND* 73 | 74 | The JIT will not check for suspend events. Even if the AngelScript engine is set for fewer suspensions, some will remain, so this option is still useful. 75 | 76 | *JIT_SYSCALL_FPU_NORESET* 77 | 78 | Disables the FPU reset around functions for platforms that always clean up the FPU. MSVC appears to work fine without FPU resets, and the result will be slightly faster. 79 | 80 | *JIT_SYSCALL_NO_ERRORS* 81 | 82 | If system functions never set exceptions on a script context, this produces a smaller and faster output. Setting exceptions with this option enabled will likely result in crashes. 83 | 84 | *JIT_ALLOC_SIMPLE* 85 | 86 | When using simple allocation (e.g. default new/delete or malloc/free) that does not read any script states, this produces smaller and faster outputs. 87 | 88 | *JIT_NO_SWITCHES* 89 | 90 | Disables native switch statements in the JIT. Disable this option for a smaller, but slower, output. 91 | 92 | *JIT_NO_SCRIPT_CALLS* 93 | 94 | Disables native script calls in the JIT. Native script calls are slightly faster, but may break on angelscript updates; disable this as a temporary workaround if they do. 95 | 96 | *JIT_FAST_REFCOUNT* 97 | 98 | Reduces overhead involved in reference counting. No reference counting function may alter or inspect script contexts. 99 | -------------------------------------------------------------------------------- /as_jit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "angelscript.h" 3 | #include 4 | #include 5 | 6 | namespace assembler { 7 | struct CodePage; 8 | struct CriticalSection; 9 | }; 10 | 11 | enum JITSettings { 12 | //Should the JIT attempt to suspend? (Slightly faster, but makes suspension very rare if it occurs at all) 13 | JIT_NO_SUSPEND = 0x01, 14 | //Should the JIT reset the FPU entering System calls? (Slightly faster, may not work on all platforms) 15 | JIT_SYSCALL_FPU_NORESET = 0x02, 16 | //Should the JIT support error events from System calls? (Faster, but exceptions will generally be ignored, possibly leading to crashes) 17 | JIT_SYSCALL_NO_ERRORS = 0x04, 18 | //Do allocation/deallocation functions inspect the script context? (Faster, but won't work correctly if you try to get information about the script system during allocations) 19 | JIT_ALLOC_SIMPLE = 0x08, 20 | //Fall back to AngelScript to perform switch logic? (Slower, but uses less memory) 21 | JIT_NO_SWITCHES = 0x10, 22 | //Fall back to AngelScript to perform script calls 23 | // Slower, but can be used as a temporary workaround for angelscript changes 24 | JIT_NO_SCRIPT_CALLS = 0x20, 25 | //Make calling reference counting functions faster in common situations 26 | // Reference counting functions which access the script context will produce undefined results 27 | JIT_FAST_REFCOUNT = 0x40, 28 | }; 29 | 30 | class asCJITCompiler : public asIJITCompiler { 31 | assembler::CodePage* activePage; 32 | std::multimap pages; 33 | 34 | assembler::CriticalSection* lock; 35 | 36 | unsigned flags; 37 | 38 | std::multimap jumpTables; 39 | unsigned char** activeJumpTable; 40 | unsigned currentTableSize; 41 | 42 | struct DeferredCodePointer { 43 | void** jitFunction; 44 | void** jitEntry; 45 | }; 46 | std::multimap deferredPointers; 47 | public: 48 | asCJITCompiler(unsigned Flags = 0); 49 | ~asCJITCompiler(); 50 | int CompileFunction(asIScriptFunction *function, asJITFunction *output); 51 | void ReleaseJITFunction(asJITFunction func); 52 | void finalizePages(); 53 | }; 54 | -------------------------------------------------------------------------------- /virtual_asm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include 5 | 6 | namespace assembler { 7 | 8 | typedef unsigned char byte; 9 | 10 | struct Register; 11 | struct MemAddress; 12 | 13 | enum RegCode : byte { 14 | EAX = 0, 15 | ECX = 1, 16 | EDX = 2, 17 | EBX = 3, 18 | ESP = 4, SIB = 4, 19 | EBP = 5, ADDR = 5, 20 | ESI = 6, 21 | EDI = 7, 22 | 23 | R8 = 8, 24 | R9 = 9, 25 | R10 = 10, 26 | R12 = 12, 27 | R13 = 13, 28 | R14 = 14, 29 | R15 = 15, 30 | 31 | //R11 is supervolatile. Can change in between 32 | //virtual asm ops (used as a temporary), so be careful 33 | //with using it. 34 | R11 = 11, 35 | 36 | //XMM registers have unique numbers so we can recognize them 37 | XMM0 = 16, 38 | XMM1 = 17, 39 | XMM2 = 18, 40 | XMM3 = 19, 41 | XMM4 = 20, 42 | XMM5 = 21, 43 | XMM6 = 22, 44 | XMM7 = 23, 45 | 46 | XMM8 = 24, 47 | XMM9 = 25, 48 | XMM10 = 26, 49 | XMM11 = 27, 50 | XMM12 = 28, 51 | XMM13 = 29, 52 | XMM14 = 30, 53 | XMM15 = 31, 54 | 55 | NONE = 0, 56 | }; 57 | 58 | //Floating Point Register codes representing the stack registers on the FPU 59 | // The top of the stack is always FPU_0 60 | enum FloatReg : byte { 61 | FPU_0 = 0, 62 | FPU_1 = 1, 63 | FPU_2 = 2, 64 | FPU_3 = 3, 65 | FPU_4 = 4, 66 | FPU_5 = 5, 67 | FPU_6 = 6, 68 | FPU_7 = 7, 69 | }; 70 | 71 | enum JumpType { 72 | Overflow, 73 | NotOverflow, 74 | Below, Carry = Below, 75 | NotBelow, NotCarry = NotBelow, 76 | Equal, Zero = Equal, 77 | NotEqual, NotZero = NotEqual, 78 | NotAbove, 79 | Above, 80 | Sign, 81 | NotSign, 82 | Parity, 83 | NotParity, 84 | Less, 85 | GreaterOrEqual, 86 | LessOrEqual, 87 | Greater, 88 | Jump, 89 | 90 | JumpTypeCount 91 | }; 92 | 93 | 94 | //Handles thread safety for the JIT 95 | struct CriticalSection { 96 | void* pLock; 97 | 98 | void enter(); 99 | void leave(); 100 | 101 | CriticalSection(); 102 | ~CriticalSection(); 103 | }; 104 | 105 | struct AddrPrefix { 106 | MemAddress& adr; 107 | bool defLong; 108 | unsigned char further; 109 | 110 | AddrPrefix(MemAddress& Adr, bool DefLong, unsigned char Further) 111 | : adr(Adr), defLong(DefLong), further(Further) { 112 | } 113 | }; 114 | 115 | struct RegPrefix { 116 | Register& reg; 117 | unsigned short other; 118 | bool defLong; 119 | 120 | RegPrefix(Register& Reg, unsigned short Other, bool DefLong) 121 | : reg(Reg), other(Other), defLong(DefLong) { 122 | } 123 | }; 124 | 125 | //Stores information about the code page 126 | // Generates an executable page in memory when created 127 | // Deletes the asssociated page when deleted 128 | //Implementation in virtual_asm_.cpp (e.g. virtual_asm_windows.cpp) 129 | struct CodePage { 130 | void* page; 131 | unsigned int size, used, references; 132 | bool final; 133 | 134 | CodePage(unsigned int Size, void* requestedStart = 0); 135 | ~CodePage(); 136 | 137 | void grab(); 138 | void drop(); 139 | 140 | //Call finalize when done writing to the code page to guarantee that it can be executed 141 | //No more writing may be done to the allocated pages 142 | void finalize(); 143 | 144 | //Returns the pointer to the first currently unused chunk of the page 145 | template 146 | T getFunctionPointer() { 147 | return reinterpret_cast((byte*)page+used); 148 | } 149 | 150 | byte* getActivePage() const { 151 | return (byte*)page+used; 152 | } 153 | 154 | //Marks bytes as used; 155 | //future calls to getFunctionPointer() will not reference the location that is being marked as used 156 | void markBytesUsed(unsigned int count) { 157 | used += count; 158 | } 159 | 160 | //Marks bytes up to
as used 161 | void markUsedAddress(void* address) { 162 | unsigned newUsed = (unsigned)((byte*)address - (byte*)page); 163 | if(newUsed > used && newUsed <= size) 164 | used = newUsed; 165 | } 166 | 167 | //Returns the number of bytes not yet allocated to a function 168 | unsigned int getFreeSize() const { 169 | return size-used; 170 | } 171 | 172 | //Returns the smallest page (in bytes) that can be allocated by a code page (Sizes other than multiples of this size allocate an extra page) 173 | static unsigned int getMinimumPageSize(); 174 | 175 | private: 176 | CodePage() {} 177 | }; 178 | 179 | //Stores the code pointer and provides access to various processor-level operations 180 | // To work with the processor, create a set of 'Register' instances, each taking the RegCode of the associated register (e.g. Register eax(cpu, EAX)) 181 | //Implementation in virtual_asm_.cpp (e.g. virtual_asm_x86.cpp) 182 | struct Processor { 183 | //Pointer to the location for the next opcode 184 | byte* op; 185 | byte* pageStart; 186 | //The current mode of operation, in bits 187 | // e.g. 32 bits for x86, indicating that operations should treat addresses as if they were unsigned integers 188 | unsigned bitMode, lastBitMode; 189 | //The number of bytes currently on the stack that we are responsible for 190 | unsigned stackDepth; 191 | //Reserved jump space 192 | unsigned jumpSpace; 193 | byte* jumpPtr; 194 | 195 | //Initializes the processor to point to the active page of the code page 196 | //Optionally takes a bitMode override (defaults to the same bitMode as the exe) 197 | Processor(CodePage& codePage, unsigned defaultBitMode = sizeof(void*)*8 ); 198 | 199 | //Creates a jump to the new code page, and marks the current address as used on the old code page 200 | //Updates output pointer to the new code page's active page 201 | void migrate(CodePage& prevPage, CodePage& newPage); 202 | 203 | //Changes the current bitMode, and stores the previous bitMode 204 | void setBitMode(unsigned bits) { 205 | lastBitMode = bitMode; 206 | bitMode = bits; 207 | } 208 | 209 | //Restores the previous bitMode 210 | void resetBitMode() { 211 | bitMode = lastBitMode; 212 | } 213 | 214 | //Returns the alignment of the stack (number of bytes a push increments esp) 215 | static unsigned pushSize(); 216 | 217 | //Pushes data to the opcode output 218 | template 219 | Processor& operator<<(T b) { 220 | *(T*)op = b; op += sizeof(T); 221 | return *this; 222 | } 223 | 224 | //Pushes bytes representing a memory address to the opcode output 225 | template 226 | Processor& operator<<(MemAddress addr); 227 | 228 | //Pushes bytes representing a prefix 229 | template 230 | Processor& operator<<(AddrPrefix pr); 231 | 232 | template 233 | Processor& operator<<(RegPrefix pr); 234 | 235 | //Calls the function, passing the arguments specified by 'args' 236 | //args is a string like "rrcmrm" which specifies arguments as sourced by a Register*, MemAddres*, or a constant 237 | //EBP is invalid during the call 238 | void call_cdecl(void* func, const char* args, va_list ap); 239 | void call_cdecl(void* func, const char* args, ...); 240 | 241 | //Use call() in between these to set up a call with an arbitrary function 242 | unsigned call_cdecl_args(const char* args, ...); 243 | unsigned call_cdecl_args(const char* args, va_list ap); 244 | unsigned call_thiscall_args(Register* obj, const char* args, ...); 245 | unsigned call_thiscall_args(Register* obj, const char* args, va_list ap); 246 | 247 | //Prepares for a call to manual call to a cdecl function (Do not use with call_cdecl) 248 | // Use before pushing arguments 249 | // Invalidates EBP until call_cdecl_end() 250 | void call_cdecl_prep(unsigned argBytes); 251 | //Ends a manual call to a cdecl function (Do not use with call_cdecl) 252 | // Use after returning from the function 253 | void call_cdecl_end(unsigned argBytes, bool returnPointer = false); 254 | 255 | //Note: stdcall is like cdecl, but does not use cdecl_end 256 | 257 | //Calls the function, passing the arguments specified by 'args' 258 | //args is a string like "rrcmrm" which specifies arguments as sourced by a Register*, MemAddres*, or a constant 259 | //EBP is invalid during the call 260 | void call_stdcall(void* func, const char* args, ...); 261 | 262 | //To call a thiscall: 263 | // cpu.call_thiscall_prep(total argument size) 264 | // cpu.push(arguments) 265 | // cpu.call_thiscall_this(source of 'this' pointer) 266 | // cpu.call(function) 267 | // cpu.call_thiscall_end(total argument size) 268 | void call_thiscall_prep(unsigned argBytes); 269 | void call_thiscall_this(MemAddress address); 270 | void call_thiscall_this(Register& reg); 271 | void call_thiscall_this_mem(MemAddress address, Register& memreg); 272 | void call_thiscall_this_mem(Register& reg, Register& memreg); 273 | void call_thiscall_end(unsigned argBytes, bool returnPointer = false); 274 | 275 | //Calls a function (push code pointer, jump to function) 276 | void call(Register& reg); 277 | void call(void* func); 278 | 279 | //Pushes a constant value onto the stack (Pushes are always pushSize() large, values beyond this size are an error) 280 | void push(size_t value); 281 | //Pops times (Pops are always pushSize() large) 282 | void pop(unsigned int count); 283 | 284 | //Pushes the value of onto the stack 285 | void push(Register& reg); 286 | //Pops the alue of from the stack 287 | void pop(Register& reg); 288 | 289 | //Get a register corresponding to an argument on 64-bit calling convention 290 | unsigned maxIntArgs64(); 291 | unsigned maxFloatArgs64(); 292 | bool isIntArg64Register(unsigned char number, unsigned char arg); 293 | bool isFloatArg64Register(unsigned char number, unsigned char arg); 294 | Register intArg64(unsigned char number, unsigned char arg); 295 | Register floatArg64(unsigned char number, unsigned char arg); 296 | Register intArg64(unsigned char number, unsigned char arg, Register defaultReg); 297 | Register floatArg64(unsigned char number, unsigned char arg, Register defaultReg); 298 | Register floatReturn64(); 299 | Register intReturn64(); 300 | 301 | //Pushes the memory at
onto the stack (Pushes are always pushSize() large, pushing larger values invokes multiple pushes) 302 | void push(MemAddress address); 303 | //Pops the value on the stack to the memory at
(Pops are always pushSize() large, popping larger values invokes multiple pops) 304 | void pop(MemAddress address); 305 | 306 | //Prepares a short jump (fewer than approx. 120 bytes in either direction) 307 | // Pass the return to a matching end_short_jump 308 | void* prep_short_jump(JumpType type); 309 | //Ends a short jump 310 | void end_short_jump(void* p); 311 | 312 | //Prepares a large jump (can jump to any location) 313 | // Pass the return to a matching end_long_jump 314 | void* prep_long_jump(JumpType type); 315 | //Ends a large jump 316 | void end_long_jump(void* p); 317 | 318 | //Jumps to 319 | void jump(JumpType type, volatile byte* dest); 320 | //Jumps to the address in 321 | void jump(Register& reg); 322 | //Decrements ecx and jumps if it becomes 0; Optionally conditionally jumps based on a Zero/NotZero test 323 | void loop(volatile byte* dest, JumpType type = Jump); 324 | 325 | //Copies from *esi to *edi, and adjusts them both by the data size according to the direction flag 326 | void string_copy(unsigned size); 327 | //Sets direction flag for string copy 328 | void setDirFlag(bool forward); 329 | 330 | //Returns from a function (pop code pointer, jump there) 331 | void ret(); 332 | 333 | //Triggers a debug break 334 | void debug_interrupt(); 335 | 336 | private: 337 | Processor() {} 338 | }; 339 | 340 | //Provides access to the floating point unit's state 341 | //Implementation in virtual_asm_.cpp (e.g. virtual_asm_x86.cpp) 342 | struct FloatingPointUnit { 343 | Processor& cpu; 344 | 345 | FloatingPointUnit(Processor& CPU); 346 | 347 | //Clears the FPU's state and registers 348 | void init(); 349 | 350 | //Negates FPU_0 351 | void negate(); 352 | 353 | //Pushes 354 | void load_const_0(); 355 | void load_const_1(); 356 | 357 | //FPU_1 becomes FPU_0 (Pops the fpu stack) 358 | void pop(); 359 | 360 | //Exchanges contents of FPU_n and FPU_0 361 | void exchange(FloatReg floatReg); 362 | 363 | //Compares FPU_0 to floatReg, setting the CPU's flags according to the values' relation 364 | // Optionally pops the fpu stack 365 | void compare_toCPU(FloatReg floatReg, bool pop = true); 366 | 367 | //Pushes the specified data type stored at
onto the FPU stack (becomes FPU_0) 368 | void load_float(MemAddress address); 369 | void load_dword(MemAddress address); 370 | void load_qword(MemAddress address); 371 | void load_double(MemAddress address); 372 | 373 | //Stores the value on FPU_0 to
according to the data type 374 | // Optionally pops the fpu stack 375 | void store_float(MemAddress address, bool pop = true); 376 | void store_dword(MemAddress address, bool pop = true); 377 | void store_double(MemAddress address, bool pop = true); 378 | 379 | //Control words 380 | void store_control_word(MemAddress address); 381 | void load_control_word(MemAddress address); 382 | 383 | //Effect: FPU_0 -= 384 | void operator-=(FloatReg reg); 385 | 386 | //Effect: FPU_0 += *(float*)address 387 | void add_float(MemAddress address); 388 | //Effect: FPU_0 -= *(float*)address 389 | void sub_float(MemAddress address); 390 | //Effect: FPU_0 *= *(float*)address 391 | void mult_float(MemAddress address); 392 | //Effect: FPU_0 /= *(float*)address 393 | void div_float(MemAddress address); 394 | 395 | //Effect: FPU_0 += *(double*)address 396 | void add_double(MemAddress address); 397 | void add_double(FloatReg reg, bool pop = true); 398 | //Effect: FPU_0 -= *(double*)address 399 | // If Reversed: FPU_0 = *(double*)address - FPU_0 400 | void sub_double(MemAddress address, bool reversed = false); 401 | void sub_double(FloatReg reg, bool reversed = false, bool pop = true); 402 | //Effect: FPU_0 *= *(double*)address 403 | void mult_double(MemAddress address); 404 | void mult_double(FloatReg reg, bool pop = true); 405 | //Effect: FPU_0 /= *(double*)address 406 | // If Reversed: FPU_0 = *(double*)address / FPU_0 407 | void div_double(MemAddress address, bool reversed = false); 408 | void div_double(FloatReg reg, bool reversed = false, bool pop = true); 409 | }; 410 | 411 | //Temporary struct that represents an addition to a memory address, with optional scaling 412 | struct ScaledIndex { 413 | RegCode reg; 414 | unsigned char scaleFactor; 415 | 416 | ScaledIndex(RegCode Reg, unsigned char Scale) : reg(Reg), scaleFactor(Scale) {} 417 | }; 418 | 419 | //Temporary struct that stores data necessary for memory access 420 | // Provides operations that can be performed on a memory address 421 | //Implementation in virtual_asm_.cpp (e.g. virtual_asm_x86.cpp) 422 | struct MemAddress { 423 | Processor& cpu; 424 | void* absolute_address; 425 | int offset; 426 | unsigned bitMode; 427 | RegCode code; 428 | RegCode scaleReg; 429 | unsigned char other; 430 | unsigned char scaleFactor; 431 | bool Float; 432 | bool Signed; 433 | 434 | MemAddress(Processor& CPU, void* address); 435 | MemAddress(Processor& CPU, RegCode Code); 436 | MemAddress(Processor& CPU, RegCode Code, int Offset); 437 | MemAddress operator+(ScaledIndex scale); 438 | MemAddress operator+(int Offset); 439 | MemAddress operator-(int Offset); 440 | 441 | void operator++(); 442 | void operator--(); 443 | 444 | void operator-(); 445 | void operator~(); 446 | 447 | void operator+=(unsigned int amount); 448 | void operator-=(unsigned int amount); 449 | 450 | void operator=(unsigned int value); 451 | void operator=(void* pointer); 452 | void operator=(Register fromReg); 453 | 454 | void operator&=(unsigned int value); 455 | void operator|=(unsigned int value); 456 | 457 | //Copies memory using an intermediate register 458 | void direct_copy(MemAddress address, Register& intermediate); 459 | AddrPrefix prefix(unsigned char further = 0, bool defLong = false); 460 | }; 461 | 462 | //Converts a MemAddress from the default unsigned to match the passed type 463 | template 464 | MemAddress as(MemAddress addr) { 465 | addr.bitMode = sizeof(T) * 8; 466 | addr.Signed = (T)-1 < (T)0; 467 | return addr; 468 | } 469 | 470 | template<> 471 | MemAddress as(MemAddress addr); 472 | 473 | template<> 474 | MemAddress as(MemAddress addr); 475 | 476 | //Structure that provides operations that can be performed on a register 477 | // Also provides the means to generate MemAddresses relative to a register via dereference (e.g. *eax+8) 478 | //Implementation in virtual_asm_.cpp (e.g. virtual_asm_x86.cpp) 479 | struct Register { 480 | Processor& cpu; 481 | RegCode code; 482 | unsigned bitMode; 483 | 484 | Register(Processor& CPU, RegCode Code); 485 | Register(Processor& CPU, RegCode Code, unsigned BitModeOverride); 486 | 487 | void set_regCode(Register& other) { 488 | code = other.code; 489 | bitMode = other.bitMode; 490 | } 491 | 492 | unsigned getBitMode() const; 493 | unsigned getBitMode(const MemAddress& addr) const; 494 | 495 | MemAddress operator*() const; 496 | ScaledIndex operator*(unsigned char scale) const; 497 | 498 | //Loads the address pointed to by
into this register 499 | void copy_address(MemAddress address); 500 | 501 | void swap(MemAddress address); 502 | void swap(Register& other); 503 | 504 | void operator<<=(Register& other); 505 | void operator>>=(Register& other); 506 | void rightshift_logical(Register& other); 507 | 508 | void operator+=(unsigned int amount); 509 | void operator+=(MemAddress address); 510 | void operator+=(Register& other); 511 | 512 | void operator-=(unsigned int amount); 513 | void operator-=(Register& other); 514 | void operator-=(MemAddress address); 515 | 516 | void operator*=(MemAddress address); 517 | 518 | void operator-(); 519 | void operator~(); 520 | 521 | void operator--(); 522 | void operator++(); 523 | 524 | void operator&=(unsigned long long mask); 525 | void operator&=(MemAddress address); 526 | void operator&=(Register other); 527 | 528 | void operator^=(MemAddress address); 529 | void operator^=(Register& other); 530 | 531 | void operator|=(MemAddress address); 532 | void operator|=(unsigned long long mask); 533 | 534 | //Copies a smaller data type, retaining the sign 535 | void copy_expanding(MemAddress address); 536 | //Copies an 8 bit register, leaving 0s in higher bytes 537 | void copy_zeroing(Register& other); 538 | 539 | void operator=(unsigned long long value); 540 | void operator=(void* pointer); 541 | void operator=(Register other); 542 | void operator=(MemAddress addr); 543 | 544 | void operator==(Register other); 545 | void operator==(MemAddress addr); 546 | void operator==(unsigned int test); 547 | 548 | void setIf(JumpType condition); 549 | void* setDeferred(unsigned long long def = 0); 550 | 551 | bool xmm(); 552 | bool extended(); 553 | RegCode index(); 554 | 555 | RegPrefix prefix(unsigned short other = 0, bool defaultLong = false); 556 | RegPrefix prefix(Register& other, bool defaultLong = false); 557 | unsigned char modrm(unsigned short other); 558 | unsigned char modrm(Register& other); 559 | 560 | //Multiplies *address with value, stores the result in this register 561 | void multiply_signed(MemAddress address, int value); 562 | 563 | //Divides {eax,edx} by this register; result in eax, remainder in edx 564 | void divide(); 565 | void divide_signed(); 566 | }; 567 | 568 | //Converts a MemAddress from the default unsigned to match the passed type 569 | template 570 | Register as(Register reg) { 571 | reg.bitMode = sizeof(T) * 8; 572 | return reg; 573 | } 574 | }; 575 | -------------------------------------------------------------------------------- /virtual_asm_linux.cpp: -------------------------------------------------------------------------------- 1 | #include "virtual_asm.h" 2 | #include 3 | #include 4 | #include 5 | 6 | //OSX has MAP_ANON 7 | #ifndef MAP_ANONYMOUS 8 | #define MAP_ANONYMOUS MAP_ANON 9 | #endif 10 | 11 | namespace assembler { 12 | 13 | unsigned Processor::maxIntArgs64() { 14 | return 6; 15 | } 16 | 17 | unsigned Processor::maxFloatArgs64() { 18 | return 8; 19 | } 20 | 21 | bool Processor::isIntArg64Register(unsigned char number, unsigned char arg) { 22 | return number < 6; 23 | } 24 | 25 | bool Processor::isFloatArg64Register(unsigned char number, unsigned char arg) { 26 | return number < 8; 27 | } 28 | 29 | Register Processor::intArg64(unsigned char number, unsigned char arg) { 30 | switch(number) { 31 | case 0: 32 | return Register(*this, EDI); 33 | case 1: 34 | return Register(*this, ESI); 35 | case 2: 36 | return Register(*this, EDX); 37 | case 3: 38 | return Register(*this, ECX); 39 | case 4: 40 | return Register(*this, R8); 41 | case 5: 42 | return Register(*this, R9); 43 | default: 44 | throw "Integer64 argument index out of bounds"; 45 | } 46 | } 47 | 48 | Register Processor::floatArg64(unsigned char number, unsigned char arg) { 49 | switch(number) { 50 | case 0: 51 | return Register(*this, XMM0); 52 | case 1: 53 | return Register(*this, XMM1); 54 | case 2: 55 | return Register(*this, XMM2); 56 | case 3: 57 | return Register(*this, XMM3); 58 | case 4: 59 | return Register(*this, XMM4); 60 | case 5: 61 | return Register(*this, XMM5); 62 | case 6: 63 | return Register(*this, XMM6); 64 | case 7: 65 | return Register(*this, XMM7); 66 | default: 67 | throw "Float64 argument index out of bounds"; 68 | } 69 | } 70 | 71 | Register Processor::intArg64(unsigned char number, unsigned char arg, Register defaultReg) { 72 | if(isIntArg64Register(number, arg)) 73 | return intArg64(number, arg); 74 | return defaultReg; 75 | } 76 | 77 | Register Processor::floatArg64(unsigned char number, unsigned char arg, Register defaultReg) { 78 | if(isFloatArg64Register(number, arg)) 79 | return floatArg64(number, arg); 80 | return defaultReg; 81 | } 82 | 83 | Register Processor::intReturn64() { 84 | return Register(*this, EAX); 85 | } 86 | 87 | Register Processor::floatReturn64() { 88 | return Register(*this, XMM0); 89 | } 90 | 91 | CodePage::CodePage(unsigned int Size, void* requestedStart) : used(0), final(false), references(1) { 92 | unsigned minPageSize = getMinimumPageSize(); 93 | unsigned pages = Size / minPageSize; 94 | 95 | if(Size % minPageSize != 0) 96 | pages += 1; 97 | 98 | size_t reqptr = (size_t)requestedStart; 99 | if(reqptr % minPageSize != 0) 100 | reqptr -= (reqptr % minPageSize); 101 | 102 | page = mmap( 103 | (void*)reqptr, 104 | Size, 105 | PROT_READ | PROT_WRITE | PROT_EXEC, 106 | MAP_ANONYMOUS | MAP_PRIVATE, 107 | 0, 108 | 0); 109 | 110 | size = pages * minPageSize; 111 | } 112 | 113 | void CodePage::grab() { 114 | ++references; 115 | } 116 | 117 | void CodePage::drop() { 118 | if(--references == 0) 119 | delete this; 120 | } 121 | 122 | CodePage::~CodePage() { 123 | munmap(page, size); 124 | } 125 | 126 | void CodePage::finalize() { 127 | mprotect(page, size, PROT_READ | PROT_EXEC); 128 | final = true; 129 | } 130 | 131 | unsigned int CodePage::getMinimumPageSize() { 132 | return getpagesize(); 133 | } 134 | 135 | void CriticalSection::enter() { 136 | pthread_mutex_lock((pthread_mutex_t*)pLock); 137 | } 138 | 139 | void CriticalSection::leave() { 140 | pthread_mutex_unlock((pthread_mutex_t*)pLock); 141 | } 142 | 143 | CriticalSection::CriticalSection() { 144 | pthread_mutex_t* mutex = new pthread_mutex_t(); 145 | pthread_mutex_init(mutex, 0); 146 | 147 | pLock = mutex; 148 | } 149 | CriticalSection::~CriticalSection() { 150 | pthread_mutex_t* mutex = (pthread_mutex_t*)pLock; 151 | pthread_mutex_destroy(mutex); 152 | delete mutex; 153 | } 154 | 155 | }; 156 | -------------------------------------------------------------------------------- /virtual_asm_windows.cpp: -------------------------------------------------------------------------------- 1 | #include "virtual_asm.h" 2 | #include 3 | 4 | namespace assembler { 5 | 6 | unsigned Processor::maxIntArgs64() { 7 | return 4; 8 | } 9 | 10 | unsigned Processor::maxFloatArgs64() { 11 | return 4; 12 | } 13 | 14 | bool Processor::isIntArg64Register(unsigned char number, unsigned char arg) { 15 | return arg < 4; 16 | } 17 | 18 | bool Processor::isFloatArg64Register(unsigned char number, unsigned char arg) { 19 | return arg < 4; 20 | } 21 | 22 | Register Processor::intArg64(unsigned char number, unsigned char arg) { 23 | switch(arg) { 24 | case 0: 25 | return Register(*this, ECX); 26 | case 1: 27 | return Register(*this, EDX); 28 | case 2: 29 | return Register(*this, R8); 30 | case 3: 31 | return Register(*this, R9); 32 | default: 33 | throw "Integer64 argument index out of bounds"; 34 | } 35 | } 36 | 37 | Register Processor::floatArg64(unsigned char number, unsigned char arg) { 38 | switch(arg) { 39 | case 0: 40 | return Register(*this, XMM0); 41 | case 1: 42 | return Register(*this, XMM1); 43 | case 2: 44 | return Register(*this, XMM2); 45 | case 3: 46 | return Register(*this, XMM3); 47 | default: 48 | throw "Float64 argument index out of bounds"; 49 | } 50 | } 51 | 52 | Register Processor::intArg64(unsigned char number, unsigned char arg, Register defaultReg) { 53 | if(isIntArg64Register(number, arg)) 54 | return intArg64(number, arg); 55 | return defaultReg; 56 | } 57 | 58 | Register Processor::floatArg64(unsigned char number, unsigned char arg, Register defaultReg) { 59 | if(isFloatArg64Register(number, arg)) 60 | return floatArg64(number, arg); 61 | return defaultReg; 62 | } 63 | 64 | Register Processor::intReturn64() { 65 | return Register(*this, EAX); 66 | } 67 | 68 | Register Processor::floatReturn64() { 69 | return Register(*this, XMM0); 70 | } 71 | 72 | CodePage::CodePage(unsigned int Size, void* requestedStart) : used(0), final(false), references(1) { 73 | SYSTEM_INFO info; 74 | GetSystemInfo(&info); 75 | 76 | unsigned minPageSize = info.dwPageSize; 77 | size_t pageStep = (size_t)info.dwAllocationGranularity * 2; 78 | if((size_t)Size > pageStep) 79 | pageStep = (size_t)Size; 80 | 81 | unsigned pages = Size / minPageSize; 82 | if(Size % minPageSize != 0) 83 | pages += 1; 84 | 85 | size = (pages * minPageSize) - 2; 86 | 87 | //Search for progressively more distant possible page locations, then just get any available one 88 | for(int i = 1; i < 256; ++i) { 89 | void* request = (char*)requestedStart + i*pageStep; 90 | page = VirtualAlloc(request, size, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE); 91 | if(page != 0) 92 | return; 93 | } 94 | 95 | page = VirtualAlloc(0, size, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE); 96 | } 97 | 98 | void CodePage::grab() { 99 | ++references; 100 | } 101 | 102 | void CodePage::drop() { 103 | if(--references == 0) 104 | delete this; 105 | } 106 | 107 | CodePage::~CodePage() { 108 | VirtualFree(page,0,MEM_RELEASE); 109 | } 110 | 111 | void CodePage::finalize() { 112 | FlushInstructionCache(GetCurrentProcess(),page,size); 113 | DWORD oldProtect = PAGE_EXECUTE_READWRITE; 114 | VirtualProtect(page,size,PAGE_EXECUTE_READ,&oldProtect); 115 | final = true; 116 | } 117 | 118 | unsigned int CodePage::getMinimumPageSize() { 119 | SYSTEM_INFO info; 120 | GetSystemInfo(&info); 121 | return info.dwPageSize; 122 | } 123 | 124 | 125 | void CriticalSection::enter() { 126 | EnterCriticalSection((CRITICAL_SECTION*)pLock); 127 | } 128 | 129 | void CriticalSection::leave() { 130 | LeaveCriticalSection((CRITICAL_SECTION*)pLock); 131 | } 132 | 133 | CriticalSection::CriticalSection() { 134 | auto* section = new CRITICAL_SECTION; 135 | InitializeCriticalSection(section); 136 | pLock = section; 137 | } 138 | CriticalSection::~CriticalSection() { 139 | DeleteCriticalSection((CRITICAL_SECTION*)pLock); 140 | delete (CRITICAL_SECTION*)pLock; 141 | } 142 | 143 | }; -------------------------------------------------------------------------------- /virtual_asm_x64.cpp: -------------------------------------------------------------------------------- 1 | #include "virtual_asm.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | //See http://ref.x86asm.net/coder32.html for a list of x86 opcode bytes 10 | 11 | namespace assembler { 12 | 13 | enum OpExtension : byte { 14 | EX_0 = 0, 15 | EX_1 = 1, 16 | EX_2 = 2, 17 | EX_3 = 3, 18 | EX_4 = 4, 19 | EX_5 = 5, 20 | EX_6 = 6, 21 | EX_7 = 7, 22 | }; 23 | 24 | enum ModBits : byte { 25 | ADR = 0, 26 | ADR8 = 1, 27 | ADR32 = 2, 28 | REG = 3 29 | }; 30 | 31 | enum IndexScale : byte { 32 | Scale1 = 0, 33 | Scale2 = 1, 34 | Scale4 = 2, 35 | Scale8 = 3 36 | }; 37 | 38 | unsigned char mod_rm(unsigned char Reg, unsigned char Mod, unsigned char RM) { 39 | return (Mod<<6) | (Reg<<3) | RM; 40 | } 41 | 42 | unsigned char sib(unsigned char ScaledIndex, unsigned char Mode, unsigned char BaseReg) { 43 | return (Mode<<6) | (ScaledIndex<<3) | BaseReg; 44 | } 45 | 46 | struct Argument { 47 | Register* reg; 48 | MemAddress* mem; 49 | uint64_t constant; 50 | bool is32; 51 | Argument(Register* r) : reg(r), mem(0) {} 52 | Argument(MemAddress* m) : reg(0), mem(m) {} 53 | Argument(unsigned Constant32) : reg(0), mem(0), constant(Constant32), is32(true) {} 54 | Argument(uint64_t Constant) : reg(0), mem(0), constant(Constant), is32(false) {} 55 | }; 56 | 57 | void moveToUpperDWORD(MemAddress& address) { 58 | if(address.absolute_address == 0) 59 | address.offset += 4; 60 | else 61 | address.absolute_address = (byte*)address.absolute_address + 4; 62 | } 63 | 64 | AddrPrefix MemAddress::prefix(unsigned char further, bool defLong) { 65 | return AddrPrefix(*this, defLong, further); 66 | } 67 | 68 | template<> 69 | MemAddress as(MemAddress addr) { 70 | addr.bitMode = sizeof(float) * 8; 71 | addr.Signed = true; 72 | addr.Float = true; 73 | return addr; 74 | } 75 | 76 | template<> 77 | MemAddress as(MemAddress addr) { 78 | addr.bitMode = sizeof(double) * 8; 79 | addr.Signed = true; 80 | addr.Float = true; 81 | return addr; 82 | } 83 | 84 | unsigned Processor::pushSize() { 85 | return sizeof(void*); 86 | } 87 | 88 | void Processor::call_cdecl_prep(unsigned argBytes) { 89 | unsigned stackOffset = (stackDepth + argBytes) % 16; 90 | Register esp(*this, ESP, sizeof(void*) * 8); 91 | if(stackOffset != 0) 92 | esp -= 16 - stackOffset; 93 | } 94 | 95 | void Processor::call_cdecl_end(unsigned argBytes, bool returnPointer) { 96 | Register esp(*this, ESP, sizeof(void*) * 8); 97 | unsigned stackOffset = (stackDepth + argBytes) % 16; 98 | if(stackOffset != 0) 99 | argBytes += (16 - stackOffset); 100 | #ifndef _MSC_VER 101 | if(returnPointer) 102 | argBytes -= 4; 103 | #endif 104 | if(argBytes != 0) 105 | esp += argBytes; 106 | } 107 | 108 | unsigned Processor::call_cdecl_args(const char* args, va_list ap) { 109 | return call_thiscall_args(0, args, ap); 110 | } 111 | 112 | unsigned Processor::call_thiscall_args(Register* obj, const char* args, va_list ap) { 113 | std::stack arg_stack; 114 | std::unordered_set used_regs; 115 | Register esp(*this, ESP, sizeof(void*) * 8); 116 | 117 | unsigned argCount = 0, floatCount = 0, intCount = 0, regCount = 0, stackBytes = 0; 118 | 119 | //Set the object as first argument 120 | if(obj) { 121 | if(!isIntArg64Register(intCount, argCount)) 122 | stackBytes += pushSize(); 123 | ++argCount; 124 | ++intCount; 125 | arg_stack.push(obj); 126 | } 127 | 128 | //Read the arguments in... 129 | while(args && *args != '\0') { 130 | if(*args == 'r') { 131 | Register* reg = va_arg(ap,Register*); 132 | if(reg->xmm()) { 133 | if(!isFloatArg64Register(floatCount, argCount)) 134 | stackBytes += pushSize(); 135 | ++floatCount; 136 | } 137 | else { 138 | if(!isIntArg64Register(intCount, argCount)) 139 | stackBytes += pushSize(); 140 | ++intCount; 141 | } 142 | ++regCount; 143 | arg_stack.push(reg); 144 | } 145 | else if(*args == 'm') { 146 | MemAddress* adr = va_arg(ap,MemAddress*); 147 | if(adr->Float) { 148 | if(!isFloatArg64Register(floatCount, argCount)) 149 | stackBytes += pushSize(); 150 | ++floatCount; 151 | } 152 | else { 153 | if(!isIntArg64Register(intCount, argCount)) 154 | stackBytes += pushSize(); 155 | ++intCount; 156 | } 157 | arg_stack.push(adr); 158 | } 159 | else if(*args == 'p') { 160 | if(!isIntArg64Register(intCount, argCount)) 161 | stackBytes += pushSize(); 162 | arg_stack.push(va_arg(ap,uint64_t)); 163 | ++intCount; 164 | } 165 | else if(*args == 'c') { 166 | if(!isIntArg64Register(intCount, argCount)) 167 | stackBytes += pushSize(); 168 | arg_stack.push(va_arg(ap,unsigned)); 169 | ++intCount; 170 | } 171 | else 172 | throw 0; 173 | ++argCount; 174 | ++args; 175 | } 176 | 177 | #ifdef _MSC_VER 178 | if(stackBytes < 32) 179 | stackBytes = 32; 180 | #endif 181 | 182 | call_cdecl_prep(stackBytes); 183 | 184 | unsigned intA = intCount - 1, floatA = floatCount - 1, a = argCount - 1; 185 | 186 | //Then push them in reverse order 187 | while(!arg_stack.empty()) { 188 | auto& arg = arg_stack.top(); 189 | 190 | if(arg.reg) { 191 | Register reg = *arg.reg; 192 | 193 | if(reg.code == ESP || reg.code == R15) 194 | throw "Cannot use this register for cdecl call wrapper."; 195 | 196 | if(reg.xmm()) { 197 | if(isFloatArg64Register(floatA, a)) { 198 | Register other = floatArg64(floatA, a); 199 | other.bitMode = reg.bitMode; 200 | 201 | if(other.code != reg.code) { 202 | if(used_regs.find(reg.code) != used_regs.end()) 203 | throw "Invalid out-of-order use of argument register."; 204 | other = reg; 205 | } 206 | 207 | used_regs.insert(other.code); 208 | } 209 | else { 210 | if(used_regs.find(reg.code) != used_regs.end()) 211 | throw "Invalid out-of-order use of argument register."; 212 | esp -= pushSize(); 213 | MemAddress adr = *esp; 214 | adr.bitMode = reg.bitMode; 215 | 216 | adr = reg; 217 | } 218 | --floatA; 219 | } 220 | else { 221 | if(isIntArg64Register(intA, a)) { 222 | Register other = intArg64(intA, a); 223 | other.bitMode = reg.bitMode; 224 | 225 | if(other.code != reg.code) { 226 | if(used_regs.find(reg.code) != used_regs.end()) 227 | throw "Invalid out-of-order use of argument register."; 228 | other = reg; 229 | } 230 | 231 | used_regs.insert(other.code); 232 | } 233 | else { 234 | if(used_regs.find(reg.code) != used_regs.end()) 235 | throw "Invalid out-of-order use of argument register."; 236 | push(reg); 237 | } 238 | --intA; 239 | } 240 | } 241 | else if(arg.mem) { 242 | MemAddress addr = *arg.mem; 243 | 244 | if(argCount > 1) { 245 | for(unsigned i = 0; i < maxIntArgs64(); ++i) { 246 | if(addr.code == intArg64(i, i).code) 247 | throw "Cannot use this register for cdecl call wrapper address."; 248 | if(addr.other == intArg64(i, i).code) 249 | throw "Cannot use this register for cdecl call wrapper address."; 250 | if(addr.scaleFactor != 0 && addr.scaleReg == intArg64(i, i).code) 251 | throw "Cannot use this register for cdecl call wrapper address."; 252 | } 253 | } 254 | if(addr.code == R15 || addr.other == R15 || (addr.scaleFactor != 0 && addr.scaleReg == R15)) 255 | throw "Cannot use this register for cdecl call wrapper address."; 256 | if(addr.other == ESP) 257 | throw "Cannot use this register for cdecl call wrapper address."; 258 | if(addr.code == ESP) { 259 | addr.code = R15; 260 | addr.offset += pushSize(); 261 | } 262 | 263 | if(addr.Float) { 264 | if(isFloatArg64Register(floatA, a)) { 265 | Register reg = floatArg64(floatA, a); 266 | reg.bitMode = addr.bitMode; 267 | 268 | reg = addr; 269 | } 270 | else { 271 | push(addr); 272 | } 273 | --floatA; 274 | } 275 | else { 276 | if(isIntArg64Register(intA, a)) { 277 | Register reg = intArg64(intA, a); 278 | reg.bitMode = addr.bitMode; 279 | 280 | reg = addr; 281 | } 282 | else { 283 | push(addr); 284 | } 285 | --intA; 286 | } 287 | } 288 | else { 289 | if(isIntArg64Register(intA, a)) { 290 | Register reg = intArg64(intA, a); 291 | if(arg.is32) 292 | reg.bitMode = 32; 293 | else 294 | reg.bitMode = 64; 295 | reg = arg.constant; 296 | } 297 | else { 298 | push(arg.constant); 299 | } 300 | --intA; 301 | } 302 | 303 | 304 | arg_stack.pop(); 305 | --a; 306 | } 307 | 308 | #ifdef _MSC_VER 309 | esp -= 32; 310 | #endif 311 | 312 | return stackBytes; 313 | } 314 | 315 | void Processor::call_cdecl(void* func, const char* args, va_list ap) { 316 | unsigned stackBytes = call_cdecl_args(args, ap); 317 | call(func); 318 | call_cdecl_end(stackBytes); 319 | } 320 | 321 | unsigned Processor::call_cdecl_args(const char* args, ...) { 322 | va_list ap; 323 | va_start(ap, args); 324 | unsigned r = call_cdecl_args(args, ap); 325 | va_end(ap); 326 | return r; 327 | } 328 | 329 | void Processor::call_cdecl(void* func, const char* args, ...) { 330 | va_list ap; 331 | va_start(ap, args); 332 | call_cdecl(func, args, ap); 333 | va_end(ap); 334 | } 335 | 336 | unsigned Processor::call_thiscall_args(Register* obj, const char* args, ...) { 337 | va_list ap; 338 | va_start(ap, args); 339 | unsigned r = call_thiscall_args(obj, args, ap); 340 | va_end(ap); 341 | return r; 342 | } 343 | 344 | void Processor::call_stdcall(void* func, const char* args, ...) { 345 | va_list ap; 346 | va_start(ap, args); 347 | call_cdecl(func, args, ap); 348 | va_end(ap); 349 | } 350 | 351 | Processor::Processor(CodePage& codePage, unsigned defaultBitMode ) { 352 | op = codePage.getActivePage(); 353 | pageStart = op; 354 | bitMode = defaultBitMode; 355 | lastBitMode = bitMode; 356 | stackDepth = pushSize(); 357 | jumpSpace = 0; 358 | } 359 | 360 | void Processor::migrate(CodePage& prevPage, CodePage& newPage) { 361 | jump(Jump,newPage.getActivePage()); 362 | jumpPtr = op; 363 | op += jumpSpace; 364 | prevPage.markUsedAddress((void*)op); 365 | op = newPage.getActivePage(); 366 | pageStart = op; 367 | jumpSpace = 0; 368 | } 369 | 370 | template<> 371 | Processor& Processor::operator<<(MemAddress addr) { 372 | if(addr.absolute_address != 0) { 373 | if((size_t)addr.absolute_address <= INT_MAX) { 374 | //Normal 32 bit address needs a none sib byte 375 | return *this << mod_rm(addr.other % 8, ADR, SIB) << sib(0x4, 0, ADDR) << (int)(size_t)addr.absolute_address; 376 | } 377 | else { 378 | //Take 64 bit absolute address from R11 379 | return *this << mod_rm(addr.other % 8, ADR, R11 % 8); 380 | } 381 | } 382 | 383 | if(addr.scaleFactor != 0) { 384 | IndexScale scale; 385 | switch(addr.scaleFactor) { 386 | case 1: 387 | scale = Scale1; break; 388 | case 2: 389 | scale = Scale2; break; 390 | case 4: 391 | scale = Scale4; break; 392 | case 8: 393 | scale = Scale8; break; 394 | default: throw 0; 395 | } 396 | 397 | //Can't scale with an offset from ESP 398 | if(addr.scaleReg % 8 == ESP) 399 | throw 0; 400 | 401 | //EBP/R13 doesn't have an ADR mode, so use ADR8 and append a 0 402 | if(addr.offset == 0 && addr.code % 8 != EBP) 403 | return *this << mod_rm(addr.other % 8, ADR, SIB) << sib(addr.scaleReg % 8, scale, addr.code % 8); 404 | else if(addr.offset >= CHAR_MIN && addr.offset <= CHAR_MAX) 405 | return *this << mod_rm(addr.other % 8, ADR8, SIB) << sib(addr.scaleReg % 8, scale, addr.code % 8) << (char)addr.offset; 406 | else 407 | return *this << mod_rm(addr.other % 8, ADR32, SIB) << sib(addr.scaleReg % 8, scale, addr.code % 8) << addr.offset; 408 | } 409 | 410 | if(addr.offset == 0 && addr.code % 8 != EBP) { //[EBP] means absolute address, so we use [EBP+0] instead 411 | *this << mod_rm(addr.other % 8, ADR, addr.code % 8); 412 | if(addr.code % 8 == ESP) 413 | *this << '\x24'; //SIB byte indicating [ESP] 414 | } 415 | else if(addr.offset >= CHAR_MIN && addr.offset <= CHAR_MAX) { 416 | *this << mod_rm(addr.other % 8, ADR8, addr.code % 8); 417 | if(addr.code % 8 == ESP) 418 | *this << '\x24'; //SIB byte indicating [ESP] 419 | *this << (char)addr.offset; 420 | } 421 | else { 422 | *this << mod_rm(addr.other % 8, ADR32, addr.code % 8); 423 | if(addr.code % 8 == ESP) 424 | *this << '\x24'; //SIB byte indicating [ESP] 425 | *this << addr.offset; 426 | } 427 | return *this; 428 | } 429 | 430 | template<> 431 | Processor& Processor::operator<<(AddrPrefix pr) { 432 | MemAddress& adr = pr.adr; 433 | 434 | //64 bit absolute addresses need to mangle a register in order to work 435 | if((size_t)adr.absolute_address > (size_t)INT_MAX) { 436 | *this << '\x49' << '\xBB' << (uint64_t)adr.absolute_address; 437 | adr.code = R11; 438 | } 439 | 440 | //Further prefixes that need to be before the REX byte 441 | if(pr.further != 0) 442 | *this << pr.further; 443 | 444 | //64 bit prefix 445 | unsigned char ch = '\x40'; 446 | if(!pr.defLong) { 447 | if(adr.bitMode == 64) 448 | ch |= '\x08'; 449 | } 450 | if((adr.code % 16) > 7) 451 | ch |= '\x01'; 452 | if((adr.other % 16) > 7) 453 | ch |= '\x04'; 454 | if(adr.scaleReg > 7) 455 | ch |= '\x02'; 456 | if(ch != '\x40') 457 | *this << ch; 458 | return *this; 459 | } 460 | 461 | template<> 462 | Processor& Processor::operator<<(RegPrefix pr) { 463 | Register& reg = pr.reg; 464 | unsigned short other = pr.other; 465 | 466 | unsigned char ch = '\x40'; 467 | if(!pr.defLong) { 468 | if(reg.getBitMode() == 64) 469 | ch |= '\x08'; 470 | } 471 | if((reg.code % 16) > 7) 472 | ch |= '\x01'; 473 | if((other % 16) > 7) 474 | ch |= '\x04'; 475 | 476 | if(ch != '\x40') 477 | *this << ch; 478 | return *this; 479 | } 480 | 481 | void Processor::push(Register& reg) { 482 | *this << reg.prefix(EX_0, true) << byte(0x50u+(reg.code % 8)); 483 | } 484 | 485 | void Processor::pop(Register& reg) { 486 | *this << reg.prefix(EX_0, true) << byte(0x58u+(reg.code % 8)); 487 | } 488 | 489 | void Processor::push(MemAddress address) { 490 | address.other = EX_6; 491 | *this << address.prefix() << '\xFF' << address; 492 | } 493 | 494 | void Processor::pop(MemAddress address) { 495 | address.other = EX_0; 496 | *this << address.prefix() << '\x8F' << address; 497 | } 498 | 499 | void Processor::push(size_t value) { 500 | if(value <= CHAR_MAX) 501 | *this << '\x6A' << (byte)value; 502 | else 503 | *this << '\x48' << '\x68' << (long long)value; 504 | } 505 | 506 | void Processor::pop(unsigned int count) { 507 | Register esp(*this, ESP); 508 | esp += count * pushSize(); 509 | } 510 | 511 | void Processor::call(Register& reg) { 512 | *this << reg.prefix() << '\xFF' << reg.modrm(EX_2); 513 | } 514 | 515 | void Processor::call(void* func) { 516 | int64_t offset = ((byte*)func - op) - 5; 517 | if(offset < (int64_t)INT_MIN || offset > (int64_t)INT_MAX) { 518 | uint64_t abs = (uint64_t)func; 519 | if(abs > (uint64_t)UINT_MAX) 520 | *this << '\x49' << '\xBB' << abs; 521 | else //0-extend small actual addresses 522 | *this << '\x41' << '\xBB' << (unsigned)abs; 523 | *this << '\x49' << '\xFF' << mod_rm(EX_2,REG,R11 % 8); 524 | } 525 | else { 526 | *this << '\xE8' << (int)offset; 527 | } 528 | } 529 | 530 | unsigned char shortJumpCodes[JumpTypeCount] = { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0xEB}; 531 | unsigned char longJumpCodes[JumpTypeCount] = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0xE9 }; 532 | 533 | void* Processor::prep_short_jump(JumpType type) { 534 | *this << shortJumpCodes[type]; 535 | void* ret = (void*)op; 536 | *this << (char)0; 537 | return ret; 538 | } 539 | 540 | void Processor::end_short_jump(void* p) { 541 | volatile byte* jumpFrom = (volatile byte*)p; 542 | int64_t offset = ((size_t)op - (size_t)jumpFrom) - 1; 543 | if(offset < CHAR_MIN || offset > CHAR_MAX) 544 | throw "Short jump too long."; 545 | *jumpFrom = (char)offset; 546 | } 547 | 548 | void* Processor::prep_long_jump(JumpType type) { 549 | if(type != Jump) 550 | *this << '\x0F'; 551 | *this << longJumpCodes[type]; 552 | void* ret = (void*)op; 553 | *this << (int)0; 554 | jumpSpace += 16; 555 | return ret; 556 | } 557 | 558 | void Processor::end_long_jump(void* p) { 559 | volatile byte* jumpFrom = (volatile byte*)p; 560 | bool isSamePage = (size_t)jumpFrom >= (size_t)pageStart && (size_t)jumpFrom < (size_t)op; 561 | int64_t offset = ((size_t)op - (size_t)jumpFrom) - 4; 562 | if(offset < (int64_t)INT_MIN || offset > (int64_t)INT_MAX) { 563 | if(isSamePage) 564 | throw "Inside-page long jump too long. This should never ever happen, somebody screwed the pooch."; 565 | Register reg(*this, R11, sizeof(void*)); 566 | auto* prevOp = op; 567 | op = jumpPtr; 568 | 569 | reg = (void*)prevOp; 570 | *this << reg.prefix(EX_4) << '\xFF' << reg.modrm(EX_4); 571 | 572 | offset = ((size_t)jumpPtr - (size_t)jumpFrom) - 4; 573 | if(offset < (int64_t)INT_MIN || offset > (int64_t)INT_MAX) 574 | throw "Multi-page drifting! Can't recover from this."; 575 | *(volatile int*)jumpFrom = (int)offset; 576 | 577 | jumpPtr = op; 578 | op = prevOp; 579 | return; 580 | } 581 | *(volatile int*)jumpFrom = (int)offset; 582 | if(isSamePage) 583 | jumpSpace -= 16; 584 | } 585 | 586 | void Processor::jump(JumpType type, volatile byte* dest) { 587 | int64_t offset = ((size_t)dest - (size_t)op) - 2; 588 | if(offset >= CHAR_MIN && offset <= CHAR_MAX) 589 | *this << shortJumpCodes[type] << (char)offset; 590 | else if (offset > INT_MAX || offset < INT_MIN) { 591 | Register reg(*this, R11, sizeof(void*)); 592 | reg = (void*)dest; 593 | jump(reg); 594 | } 595 | else if(type == Jump) 596 | *this << longJumpCodes[Jump] << (int)(offset-3); //Long jump is 3 bytes larger, jump is from the end of the full opcode 597 | else 598 | *this << '\x0F' << longJumpCodes[type] << (int)(offset-4); //Conditional long jump is 4 bytes larger, jump is from the end of the full opcode 599 | } 600 | 601 | void Processor::jump(Register& reg) { 602 | *this << reg.prefix(EX_4) << '\xFF' << reg.modrm(EX_4); 603 | } 604 | 605 | void Processor::loop(volatile byte* dest, JumpType type) { 606 | int64_t off = dest - op - 2; 607 | if(off < CHAR_MIN || off > CHAR_MAX) 608 | throw "Loop offset too far."; 609 | 610 | if(type == Jump) 611 | *this << '\xE2' << (char)off; 612 | else if(type == Zero) 613 | *this << '\xE1' << (char)off; 614 | else if(type == NotZero) 615 | *this << '\xE0' << (char)off; 616 | else 617 | throw "Unsupported loop type."; 618 | } 619 | 620 | void Processor::string_copy(unsigned size) { 621 | if(size == 1) 622 | *this << '\xA4'; 623 | else if(size == 2) 624 | *this << '\x66' << '\xA5'; 625 | else if(size == 4) 626 | *this << '\xA5'; 627 | else if(size == 8) 628 | *this << '\x48' << '\xA5'; 629 | else 630 | throw "Invalid string copy step size."; 631 | } 632 | 633 | void Processor::setDirFlag(bool forward) { 634 | if(forward) 635 | *this << '\xFC'; 636 | else 637 | *this << '\xFD'; 638 | } 639 | 640 | void Processor::ret() { 641 | *this << '\xC3'; 642 | } 643 | 644 | void Processor::debug_interrupt() { 645 | *this << '\xCC'; 646 | } 647 | 648 | MemAddress::MemAddress(Processor& CPU, void* address) 649 | : cpu(CPU), code(ESP), absolute_address(address), other(NONE), 650 | offset(0), bitMode(cpu.bitMode), Float(false), Signed(false), scaleFactor(0), scaleReg(NONE) {} 651 | 652 | MemAddress::MemAddress(Processor& CPU, RegCode Code) 653 | : cpu(CPU), code(Code), absolute_address(0), other(NONE), 654 | offset(0), bitMode(cpu.bitMode), Float(false), Signed(false), scaleFactor(0), scaleReg(NONE) {} 655 | 656 | MemAddress::MemAddress(Processor& CPU, RegCode Code, int Offset) 657 | : cpu(CPU), code(Code), absolute_address(0), other(NONE), 658 | offset(Offset), bitMode(cpu.bitMode), Float(false), Signed(false), scaleFactor(0), scaleReg(NONE) {} 659 | 660 | MemAddress MemAddress::operator+(ScaledIndex scale) { 661 | scaleReg = scale.reg; 662 | scaleFactor = scale.scaleFactor; 663 | return *this; 664 | } 665 | 666 | MemAddress MemAddress::operator+(int Offset) { 667 | offset += Offset; 668 | return *this; 669 | } 670 | 671 | MemAddress MemAddress::operator-(int Offset) { 672 | offset -= Offset; 673 | return *this; 674 | } 675 | 676 | void MemAddress::operator++() { 677 | switch(bitMode) { 678 | case 8: 679 | cpu << prefix() << '\xFE' << *this; break; 680 | case 16: 681 | cpu << prefix('\x66') << '\xFF' << *this; break; 682 | default: 683 | cpu << prefix() << '\xFF' << *this; break; 684 | } 685 | } 686 | 687 | void MemAddress::operator--() { 688 | other = EX_1; 689 | switch(bitMode) { 690 | case 8: 691 | cpu << prefix() << '\xFE' << *this; break; 692 | case 16: 693 | cpu << prefix('\x66') << '\xFF' << *this; break; 694 | default: 695 | cpu << prefix() << '\xFF' << *this; break; 696 | } 697 | } 698 | 699 | void MemAddress::operator-() { 700 | other = EX_3; 701 | switch(bitMode) { 702 | case 8: 703 | cpu << prefix() << '\xF6' << *this; break; 704 | case 16: 705 | cpu << prefix('\x66') << '\xF7' << *this; break; 706 | default: 707 | cpu << prefix() << '\xF7' << *this; break; 708 | } 709 | } 710 | 711 | void MemAddress::operator~() { 712 | other = EX_2; 713 | switch(bitMode) { 714 | case 8: 715 | cpu << prefix() << '\xF6' << *this; break; 716 | case 16: 717 | cpu << prefix('\x66') << '\xF7' << *this; break; 718 | default: 719 | cpu << prefix() << '\xF7' << *this; break; 720 | } 721 | } 722 | 723 | void MemAddress::operator+=(unsigned int amount) { 724 | if(amount == 0) return; 725 | 726 | if(code == EAX) 727 | cpu << '\x05' << amount; 728 | else if(amount <= CHAR_MAX) 729 | cpu << prefix() << '\x83' << *this << (byte)amount; 730 | else 731 | cpu << prefix() << '\x81' << *this << amount; 732 | } 733 | 734 | void MemAddress::operator-=(unsigned int amount) { 735 | if(amount == 0) return; 736 | 737 | other = (RegCode)EX_5; 738 | if(code == EAX) 739 | cpu << '\x2D' << amount; 740 | else if(amount <= CHAR_MAX) 741 | cpu << prefix() << '\x83' << *this << (byte)amount; 742 | else 743 | cpu << prefix() << '\x81' << *this << amount; 744 | } 745 | 746 | void MemAddress::operator=(unsigned int value) { 747 | switch(bitMode) { 748 | case 8: 749 | cpu << prefix() << '\xC6' << *this << (byte)value; break; 750 | case 16: 751 | cpu << prefix('\x66') << '\xC7' << *this << (unsigned short)value; break; 752 | case 32: 753 | default: 754 | cpu << prefix() << '\xC7' << *this << value; break; 755 | } 756 | } 757 | 758 | void MemAddress::operator&=(unsigned int value) { 759 | other = EX_4; 760 | cpu << prefix() << '\x81' << *this << value; 761 | } 762 | 763 | void MemAddress::operator|=(unsigned int value) { 764 | other = EX_7; 765 | switch(bitMode) { 766 | case 8: 767 | cpu << prefix() << '\x80' << *this << (byte)value; break; 768 | case 16: 769 | cpu << prefix('\x66') << '\x81' << *this << (unsigned short)value; break; 770 | case 32: 771 | case 64: 772 | cpu << prefix() << '\x81' << *this << value; break; 773 | } 774 | } 775 | 776 | void MemAddress::operator=(void* value) { 777 | bitMode = 64; 778 | if((size_t)value < (size_t)INT_MAX) { 779 | cpu << prefix() << '\xC7' << *this << (unsigned)(size_t)value; 780 | } 781 | else { 782 | if((size_t)absolute_address > UINT_MAX - sizeof(void*) * 8) { 783 | bitMode = 32; 784 | unsigned* values = (unsigned*)&value; 785 | 786 | cpu << prefix() << '\xC7' << *this << values[0]; 787 | moveToUpperDWORD(*this); 788 | cpu << prefix() << '\xC7' << *this << values[1]; 789 | } 790 | else { 791 | other = R11; 792 | cpu << '\x49' << '\xBB' << (uint64_t)value; 793 | cpu << prefix() << '\x89' << *this; 794 | } 795 | } 796 | } 797 | 798 | void MemAddress::operator=(Register fromReg) { 799 | other = fromReg.code; 800 | if(fromReg.xmm()) { 801 | switch(bitMode) { 802 | case 32: 803 | cpu << prefix('\xF3') << '\x0F' << '\x11' << *this; 804 | break; 805 | case 64: 806 | cpu << prefix('\xF2', true) << '\x0F' << '\x11' << *this; 807 | break; 808 | default: 809 | throw "Unsupported bitmode for xmm register"; 810 | } 811 | } 812 | else { 813 | switch(bitMode) { 814 | case 8: 815 | cpu << prefix() << '\x88' << *this; break; 816 | case 16: 817 | cpu << prefix('\x66') << '\x89' << *this; break; 818 | default: 819 | cpu << prefix() << '\x89' << *this; break; 820 | } 821 | } 822 | } 823 | 824 | void MemAddress::direct_copy(MemAddress address, Register& intermediate) { 825 | if(bitMode != address.bitMode) 826 | throw 0; 827 | other = intermediate.code; address.other = other; 828 | switch(bitMode) { 829 | case 8: 830 | case 16: 831 | case 32: 832 | address.bitMode = 32; 833 | 834 | intermediate = address; 835 | *this = intermediate; 836 | break; 837 | case 64: 838 | address.bitMode = 64; 839 | 840 | intermediate = address; 841 | *this = intermediate; 842 | break; 843 | } 844 | } 845 | 846 | Register::Register(Processor& CPU, RegCode Code) : cpu(CPU), code(Code), bitMode(0) {} 847 | 848 | Register::Register(Processor& CPU, RegCode Code, unsigned BitModeOverride) 849 | : cpu(CPU), code(Code), bitMode(BitModeOverride) { 850 | } 851 | 852 | bool Register::xmm() { 853 | return code >= 16; 854 | } 855 | 856 | bool Register::extended() { 857 | return (code % 16) >= 8; 858 | } 859 | 860 | RegCode Register::index() { 861 | return (RegCode)(code % 8); 862 | } 863 | 864 | RegPrefix Register::prefix(unsigned short other, bool defLong) { 865 | return RegPrefix(*this, other, defLong); 866 | } 867 | 868 | RegPrefix Register::prefix(Register& other, bool defLong) { 869 | return RegPrefix(*this, other.code, defLong); 870 | } 871 | 872 | unsigned char Register::modrm(unsigned short other) { 873 | return mod_rm(other % 8, REG, code % 8); 874 | } 875 | 876 | unsigned char Register::modrm(Register& other) { 877 | return mod_rm(other.code % 8, REG, code % 8); 878 | } 879 | 880 | unsigned Register::getBitMode() const { 881 | if(bitMode) 882 | return bitMode; 883 | else 884 | return cpu.bitMode; 885 | } 886 | 887 | unsigned Register::getBitMode(const MemAddress& addr) const { 888 | if(bitMode == 0) 889 | return addr.bitMode; 890 | else 891 | return bitMode; 892 | } 893 | 894 | MemAddress Register::operator*() const { 895 | return MemAddress(cpu,code); 896 | } 897 | 898 | ScaledIndex Register::operator*(unsigned char scale) const { 899 | return ScaledIndex(code, scale); 900 | } 901 | 902 | void Register::swap(MemAddress address) { 903 | address.other = code; 904 | switch(getBitMode(address)) { 905 | case 8: 906 | cpu << address.prefix() << '\x86' << address; break; 907 | case 16: 908 | cpu << address.prefix('\x66') << '\x87' << address; break; 909 | case 32: 910 | case 64: 911 | cpu << address.prefix() << '\x87' << address; break; 912 | } 913 | } 914 | 915 | void Register::swap(Register& other) { 916 | if(code == other.code) 917 | return; 918 | if(code == EAX) 919 | cpu << other.prefix() << byte(0x90+(other.code % 8)); 920 | else if(other.code == EAX) 921 | cpu << prefix() << byte(0x90+(code % 8)); 922 | else 923 | cpu << other.prefix(code) << '\x87' << other.modrm(code); 924 | } 925 | 926 | void Register::copy_address(MemAddress address) { 927 | address.bitMode = sizeof(void*) * 8; 928 | address.other = code; 929 | cpu << address.prefix() << '\x8D' << address; 930 | } 931 | 932 | void Register::operator<<=(Register& other) { 933 | if(other.code != ECX) 934 | throw "Can only rotate by ECX"; 935 | cpu << prefix() << '\xD3' << modrm(EX_4); 936 | } 937 | 938 | void Register::operator>>=(Register& other) { 939 | if(other.code != ECX) 940 | throw "Can only rotate by ECX"; 941 | cpu << prefix() << '\xD3' << modrm(EX_7); 942 | } 943 | 944 | void Register::rightshift_logical(Register& other) { 945 | if(other.code != ECX) 946 | throw "Can only rotate by ECX"; 947 | cpu << prefix() << '\xD3' << modrm(EX_5); 948 | } 949 | 950 | void Register::operator+=(unsigned int amount) { 951 | if(amount == 0) return; 952 | 953 | if(code == EAX) { 954 | cpu << prefix() << '\x05' << amount; 955 | } 956 | else if(amount <= CHAR_MAX) { 957 | cpu << prefix() <<'\x83' << modrm(EX_0) << (byte)amount; 958 | } 959 | else { 960 | cpu << prefix() << '\x81' << modrm(EX_0) << amount; 961 | } 962 | } 963 | 964 | void Register::operator+=(MemAddress address) { 965 | address.other = code; 966 | cpu << address.prefix() << '\x03' << address; 967 | } 968 | 969 | void Register::operator+=(Register& other) { 970 | cpu << other.prefix(*this) << '\x03' << other.modrm(code); 971 | } 972 | 973 | void Register::operator-=(unsigned int amount) { 974 | if(amount == 0) return; 975 | 976 | if(code == EAX) { 977 | cpu << '\x2D' << amount; 978 | } 979 | else if(amount <= CHAR_MAX) { 980 | cpu << prefix() <<'\x83' << modrm(EX_5) << (byte)amount; 981 | } 982 | else { 983 | cpu << prefix() << '\x81' << modrm(EX_5) << amount; 984 | } 985 | } 986 | 987 | void Register::operator-=(Register& other) { 988 | cpu << other.prefix(*this) << '\x2B' << other.modrm(code); 989 | } 990 | 991 | void Register::operator-=(MemAddress address) { 992 | address.other = code; 993 | cpu << address.prefix() << '\x2B' << address; 994 | } 995 | 996 | void Register::operator*=(MemAddress address) { 997 | address.other = code; 998 | cpu << address.prefix() << '\x0F' << '\xAF' << address; 999 | } 1000 | 1001 | void Register::multiply_signed(MemAddress address, int value) { 1002 | address.other = code; 1003 | if(cpu.bitMode == 32 || cpu.bitMode == 64) { 1004 | if(value >= CHAR_MIN && value <= CHAR_MAX) 1005 | cpu << address.prefix() << '\x6B' << address << (char)value; 1006 | else 1007 | cpu << address.prefix() << '\x69' << address << value; 1008 | } 1009 | else if(cpu.bitMode == 16) { 1010 | if(value >= CHAR_MIN && value <= CHAR_MAX) 1011 | cpu << address.prefix('\x66') << '\x6B' << address << (char)value; 1012 | else 1013 | cpu << address.prefix('\x66') << '\x69' << address << (short)value; 1014 | } 1015 | } 1016 | 1017 | void Register::operator-() { 1018 | cpu << prefix(EX_3) << '\xF7' << modrm(EX_3); 1019 | } 1020 | 1021 | void Register::operator--() { 1022 | switch(getBitMode()) { 1023 | case 8: 1024 | cpu << prefix(EX_1) << '\xFE' << modrm(EX_1); break; 1025 | case 16: 1026 | cpu << '\x66' << prefix(EX_1) << byte('\x48'+(code % 8)); break; 1027 | default: 1028 | cpu << prefix(EX_1) << '\xFF' << modrm(EX_1); break; 1029 | } 1030 | } 1031 | 1032 | void Register::operator++() { 1033 | switch(getBitMode()) { 1034 | case 8: 1035 | cpu << prefix() << '\xFE' << modrm(EX_0); break; 1036 | case 16: 1037 | cpu << '\x66' << prefix() << byte('\x40'+(code % 8)); break; 1038 | default: 1039 | cpu << prefix() << '\xFF' << modrm(EX_0); break; 1040 | } 1041 | } 1042 | 1043 | void Register::operator~() { 1044 | if(getBitMode() == 8) 1045 | cpu << prefix(EX_2) << '\xF6' << modrm(EX_2); 1046 | else 1047 | cpu << prefix(EX_2) << '\xF7' << modrm(EX_2); 1048 | } 1049 | 1050 | void Register::operator&=(MemAddress address) { 1051 | address.other = code; 1052 | cpu << address.prefix() << '\x23' << address; 1053 | } 1054 | 1055 | void Register::operator&=(unsigned long long mask) { 1056 | switch(getBitMode()) { 1057 | case 8: 1058 | cpu << prefix() << '\x80' << modrm(EX_4) << (byte)mask; break; 1059 | case 16: 1060 | cpu << prefix('\x66') << '\x81' << modrm(EX_4) << (unsigned short)mask; break; 1061 | case 32: 1062 | case 64: 1063 | if(code == EAX) 1064 | cpu << '\x25' << (unsigned)mask; 1065 | else 1066 | cpu << prefix() << '\x81' << modrm(EX_4) << (unsigned)mask; 1067 | } 1068 | } 1069 | 1070 | void Register::operator&=(Register other) { 1071 | switch(getBitMode()) { 1072 | case 8: 1073 | cpu << prefix(other) << '\x20' << modrm(other.code); break; 1074 | case 16: 1075 | cpu << '\x66' << prefix(other) << '\x21' << modrm(other.code); break; 1076 | case 32: 1077 | case 64: 1078 | cpu << prefix(other) << '\x21' << modrm(other.code); break; 1079 | } 1080 | } 1081 | 1082 | void Register::operator^=(MemAddress address) { 1083 | address.other = code; 1084 | cpu << address.prefix() << '\x33' << address; 1085 | } 1086 | 1087 | void Register::operator^=(Register& other) { 1088 | if(xmm() || other.xmm()) 1089 | throw 0; 1090 | cpu << prefix(other) << '\x31' << modrm(other); 1091 | } 1092 | 1093 | void Register::operator|=(MemAddress address) { 1094 | address.other = code; 1095 | cpu << address.prefix() << '\x0B' << address; 1096 | } 1097 | 1098 | void Register::operator|=(unsigned long long mask) { 1099 | switch(getBitMode()) { 1100 | case 8: 1101 | cpu << prefix() << '\x80' << modrm(EX_1) << (byte)mask; break; 1102 | case 16: 1103 | cpu << '\x66' << prefix() << '\x81' << modrm(EX_1) << (unsigned short)mask; break; 1104 | case 32: 1105 | case 64: 1106 | if(code == EAX) 1107 | cpu << '\x0D' << (unsigned)mask; 1108 | else 1109 | cpu << prefix() << '\x81' << modrm(EX_1) << (unsigned)mask; 1110 | } 1111 | } 1112 | 1113 | void Register::operator=(void* pointer) { 1114 | if(pointer != (void*)0) { 1115 | bitMode = sizeof(void*) * 8; 1116 | cpu << prefix() << (byte)('\xB8'+(code % 8)) << pointer; 1117 | } 1118 | else { 1119 | //Special case setting to a null pointer with implied sign extend 1120 | bitMode = 32; 1121 | *this = (unsigned long long)0; 1122 | } 1123 | } 1124 | 1125 | void Register::operator=(unsigned long long value) { 1126 | switch(getBitMode()) { 1127 | case 8: 1128 | cpu << prefix() << (byte)('\xB0'+(code % 8)) << (byte)value; break; 1129 | case 16: 1130 | cpu << '\x66' << prefix() << (byte)('\xB8'+(code % 8)) << (unsigned short)value; break; 1131 | case 32: 1132 | cpu << prefix() << (byte)('\xB8'+(code % 8)) << (unsigned int)value; break; 1133 | case 64: 1134 | cpu << prefix() << (byte)('\xB8'+(code % 8)) << value; break; 1135 | } 1136 | } 1137 | 1138 | void* Register::setDeferred(unsigned long long value) { 1139 | void* ptr = 0; 1140 | switch(getBitMode()) { 1141 | case 8: 1142 | cpu << prefix() << (byte)('\xB0'+(code % 8)); 1143 | ptr = (void*)cpu.op; 1144 | cpu << (byte)value; break; 1145 | case 16: 1146 | cpu << '\x66' << prefix() << (byte)('\xB8'+(code % 8)); 1147 | ptr = (void*)cpu.op; 1148 | cpu << (unsigned short)value; break; 1149 | case 32: 1150 | cpu << prefix() << (byte)('\xB8'+(code % 8)); 1151 | ptr = (void*)cpu.op; 1152 | cpu << (unsigned int)value; break; 1153 | case 64: 1154 | cpu << prefix() << (byte)('\xB8'+(code % 8)); 1155 | ptr = (void*)cpu.op; 1156 | cpu << value; break; 1157 | } 1158 | return ptr; 1159 | } 1160 | 1161 | void Register::operator=(Register other) { 1162 | if(xmm() != other.xmm()) 1163 | throw 0; 1164 | if(code == other.code) 1165 | return; 1166 | 1167 | if(xmm()) { 1168 | if(bitMode == 0 && other.getBitMode() != getBitMode()) 1169 | bitMode = other.getBitMode(); 1170 | switch(getBitMode()) { 1171 | case 32: 1172 | cpu << '\xF3' << prefix(other) << '\x0F' << '\x10' << modrm(other); 1173 | break; 1174 | case 64: 1175 | cpu << '\xF2' << prefix(other, true) << '\x0F' << '\x10' << modrm(other); 1176 | break; 1177 | } 1178 | } 1179 | else { 1180 | cpu << prefix(other) << '\x89' << modrm(other); 1181 | } 1182 | } 1183 | 1184 | void Register::copy_expanding(MemAddress address) { 1185 | address.other = code; 1186 | switch(getBitMode(address)) { 1187 | case 8: 1188 | cpu << address.prefix() << '\x0F' << '\xBE' << address; break; 1189 | case 16: 1190 | cpu << address.prefix() << '\x0F' << '\xBF' << address; break; 1191 | case 32: 1192 | cpu << address.prefix() << '\x63' << address; break; 1193 | case 64: 1194 | *this = address; break; 1195 | } 1196 | } 1197 | 1198 | void Register::copy_zeroing(Register& other) { 1199 | switch(getBitMode()) { 1200 | case 8: 1201 | case 16: 1202 | throw 0; 1203 | case 32: 1204 | case 64: 1205 | cpu << other.prefix(*this) << '\x0F' << '\xB6' << other.modrm(code); break; 1206 | } 1207 | } 1208 | 1209 | void Register::operator=(MemAddress addr) { 1210 | addr.other = code; 1211 | if(xmm()) { 1212 | if(bitMode == 0 && addr.bitMode != getBitMode()) 1213 | bitMode = addr.bitMode; 1214 | switch(addr.bitMode) { 1215 | case 32: 1216 | cpu << addr.prefix('\xF3') << '\x0F' << '\x10' << addr; 1217 | break; 1218 | case 64: 1219 | cpu << addr.prefix('\xF2', true) << '\x0F' << '\x10' << addr; 1220 | break; 1221 | } 1222 | } 1223 | else { 1224 | switch(getBitMode(addr)) { 1225 | case 8: 1226 | cpu << addr.prefix() << '\x8A' << addr; break; 1227 | case 16: 1228 | cpu << addr.prefix('\x66') << '\x8B' << addr; break; 1229 | default: 1230 | cpu << addr.prefix() << '\x8B' << addr; break; 1231 | } 1232 | } 1233 | } 1234 | 1235 | void Register::operator==(Register other) { 1236 | switch(getBitMode()) { 1237 | case 8: 1238 | cpu << other.prefix(*this) << '\x3A' << other.modrm(code); break; 1239 | case 16: 1240 | cpu << '\x66' << other.prefix(*this) << '\x3B' << other.modrm(code); break; 1241 | case 32: 1242 | case 64: 1243 | cpu << other.prefix(*this) << '\x3B' << other.modrm(code); break; 1244 | } 1245 | } 1246 | 1247 | void Register::operator==(MemAddress addr) { 1248 | addr.other = code; 1249 | switch(getBitMode(addr)) { 1250 | case 8: 1251 | cpu << addr.prefix() << '\x3A' << addr; break; 1252 | case 16: 1253 | cpu << addr.prefix('\x66') << '\x3B' << addr; break; 1254 | case 32: 1255 | case 64: 1256 | cpu << addr.prefix() << '\x3B' << addr; break; 1257 | } 1258 | } 1259 | 1260 | void Register::operator==(unsigned int test) { 1261 | switch(getBitMode()) { 1262 | case 8: 1263 | cpu << prefix(EX_7) << '\x80' << modrm(EX_7) << (byte)test; break; 1264 | case 16: 1265 | cpu << '\x66' << prefix(EX_7) << '\x80' << modrm(EX_7) << (unsigned short)test; break; 1266 | case 32: 1267 | case 64: 1268 | cpu << prefix(EX_7) << '\x81' << modrm(EX_7) << test; break; 1269 | } 1270 | } 1271 | 1272 | unsigned char setConditions[JumpTypeCount-1] = {0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F}; 1273 | 1274 | void Register::setIf(JumpType condition) { 1275 | if(condition >= Jump) 1276 | throw 0; 1277 | cpu << prefix() << '\x0F' << setConditions[condition] << modrm(EX_0); 1278 | } 1279 | 1280 | void Register::divide() { 1281 | cpu << prefix() << '\xF7' << modrm(EX_6); 1282 | } 1283 | 1284 | void Register::divide_signed() { 1285 | cpu << prefix() << '\xF7' << modrm(EX_7); 1286 | } 1287 | 1288 | FloatingPointUnit::FloatingPointUnit(Processor& CPU) : cpu(CPU) {} 1289 | 1290 | void FloatingPointUnit::pop() { 1291 | //FSTP ST0 1292 | cpu << '\xDD' << '\xD8'; 1293 | } 1294 | 1295 | void FloatingPointUnit::exchange(FloatReg reg) { 1296 | cpu << '\xD9' << mod_rm(EX_1,REG,reg); 1297 | } 1298 | 1299 | void FloatingPointUnit::init() { 1300 | cpu << '\xDB' << '\xE3'; 1301 | } 1302 | 1303 | void FloatingPointUnit::negate() { 1304 | cpu << '\xD9' << '\xE0'; 1305 | } 1306 | 1307 | void FloatingPointUnit::load_const_0() { 1308 | cpu << '\xD9' << '\xEE'; 1309 | } 1310 | 1311 | void FloatingPointUnit::load_const_1() { 1312 | cpu << '\xD9' << '\xE8'; 1313 | } 1314 | 1315 | void FloatingPointUnit::operator-=(FloatReg reg) { 1316 | cpu << '\xDC' << mod_rm(EX_4,REG,reg); 1317 | } 1318 | 1319 | void FloatingPointUnit::load_double(MemAddress address) { 1320 | address.other = EX_0; 1321 | cpu << address.prefix() << '\xDD' << address; 1322 | } 1323 | 1324 | void FloatingPointUnit::add_double(MemAddress address) { 1325 | address.other = EX_0; 1326 | cpu << address.prefix() << '\xDC' << address; 1327 | } 1328 | 1329 | void FloatingPointUnit::mult_double(MemAddress address) { 1330 | address.other = EX_1; 1331 | cpu << address.prefix() <<'\xDC' << address; 1332 | } 1333 | 1334 | void FloatingPointUnit::div_double(MemAddress address, bool reversed) { 1335 | address.other = reversed ? EX_7 : EX_6; 1336 | cpu << address.prefix() <<'\xDC' << address; 1337 | } 1338 | 1339 | void FloatingPointUnit::sub_double(MemAddress address, bool reversed) { 1340 | address.other = reversed ? EX_5 : EX_4; 1341 | cpu << address.prefix() <<'\xDC' << address; 1342 | } 1343 | 1344 | void FloatingPointUnit::add_float(MemAddress address) { 1345 | address.other = EX_0; 1346 | cpu << address.prefix() <<'\xD8' << address; 1347 | } 1348 | 1349 | void FloatingPointUnit::sub_float(MemAddress address) { 1350 | address.other = EX_4; 1351 | cpu << address.prefix() <<'\xD8' << address; 1352 | } 1353 | 1354 | void FloatingPointUnit::mult_float(MemAddress address) { 1355 | address.other = EX_1; 1356 | cpu << address.prefix() <<'\xD8' << address; 1357 | } 1358 | 1359 | void FloatingPointUnit::div_float(MemAddress address) { 1360 | address.other = EX_6; 1361 | cpu << address.prefix() <<'\xD8' << address; 1362 | } 1363 | 1364 | void FloatingPointUnit::store_double(MemAddress address, bool pop) { 1365 | address.other = pop ? EX_3 : EX_2; 1366 | cpu << address.prefix() <<'\xDD' << address; 1367 | } 1368 | 1369 | void FloatingPointUnit::load_float(MemAddress address) { 1370 | address.other = EX_0; 1371 | cpu << address.prefix() <<'\xD9' << address; 1372 | } 1373 | 1374 | void FloatingPointUnit::store_float(MemAddress address, bool pop) { 1375 | address.other = pop ? EX_3 : EX_2; 1376 | cpu << address.prefix() <<'\xD9' << address; 1377 | } 1378 | 1379 | void FloatingPointUnit::load_dword(MemAddress address) { 1380 | address.other = EX_0; 1381 | cpu << address.prefix() <<'\xDB' << address; 1382 | } 1383 | 1384 | void FloatingPointUnit::store_dword(MemAddress address, bool pop) { 1385 | address.other = pop ? EX_3 : EX_2; 1386 | cpu << address.prefix() <<'\xDB' << address; 1387 | } 1388 | 1389 | void FloatingPointUnit::load_qword(MemAddress address) { 1390 | address.other = EX_5; 1391 | cpu << address.prefix() <<'\xDF' << address; 1392 | } 1393 | 1394 | void FloatingPointUnit::compare_toCPU(FloatReg floatReg, bool pop) { 1395 | if(pop) 1396 | cpu << '\xDF' << mod_rm(EX_5,REG,floatReg); 1397 | else 1398 | cpu << '\xDB' << mod_rm(EX_5,REG,floatReg); 1399 | } 1400 | 1401 | void FloatingPointUnit::store_control_word(MemAddress address) { 1402 | address.other = EX_7; 1403 | cpu << address.prefix() <<'\xD9' << address; 1404 | } 1405 | 1406 | void FloatingPointUnit::load_control_word(MemAddress address) { 1407 | address.other = EX_5; 1408 | cpu << address.prefix() <<'\xD9' << address; 1409 | } 1410 | 1411 | }; 1412 | -------------------------------------------------------------------------------- /virtual_asm_x86.cpp: -------------------------------------------------------------------------------- 1 | #include "virtual_asm.h" 2 | #include 3 | #include 4 | #include 5 | 6 | //See http://ref.x86asm.net/coder32.html for a list of x86 opcode bytes 7 | 8 | namespace assembler { 9 | 10 | enum OpExtension : byte { 11 | EX_0 = 0, 12 | EX_1 = 1, 13 | EX_2 = 2, 14 | EX_3 = 3, 15 | EX_4 = 4, 16 | EX_5 = 5, 17 | EX_6 = 6, 18 | EX_7 = 7, 19 | }; 20 | 21 | enum ModBits : byte { 22 | ADR = 0, 23 | ADR8 = 1, 24 | ADR32 = 2, 25 | REG = 3 26 | }; 27 | 28 | enum IndexScale : byte { 29 | Scale1 = 0, 30 | Scale2 = 1, 31 | Scale4 = 2, 32 | Scale8 = 3 33 | }; 34 | 35 | unsigned char mod_rm(unsigned char Reg, unsigned char Mod, unsigned char RM) { 36 | return (Mod<<6) | (Reg<<3) | RM; 37 | } 38 | 39 | unsigned char sib(unsigned char ScaledIndex, unsigned char Mode, unsigned char BaseReg) { 40 | return (Mode<<6) | (ScaledIndex<<3) | BaseReg; 41 | } 42 | 43 | void moveToUpperDWORD(MemAddress& address) { 44 | if(address.absolute_address == 0) 45 | address.offset += 4; 46 | else 47 | address.absolute_address = (byte*)address.absolute_address + 4; 48 | } 49 | 50 | template<> 51 | MemAddress as(MemAddress addr) { 52 | addr.bitMode = sizeof(float) * 8; 53 | addr.Signed = true; 54 | addr.Float = true; 55 | return addr; 56 | } 57 | 58 | template<> 59 | MemAddress as(MemAddress addr) { 60 | addr.bitMode = sizeof(double) * 8; 61 | addr.Signed = true; 62 | addr.Float = true; 63 | return addr; 64 | } 65 | 66 | struct Argument { 67 | Register* reg; 68 | MemAddress* mem; 69 | unsigned int constant; 70 | Argument(Register* r) : reg(r), mem(0) {} 71 | Argument(MemAddress* m) : reg(0), mem(m) {} 72 | Argument(unsigned int Constant) : reg(0), mem(0), constant(Constant) {} 73 | }; 74 | 75 | unsigned Processor::pushSize() { 76 | return sizeof(void*); 77 | } 78 | 79 | void Processor::call_thiscall_prep(unsigned argBytes) { 80 | #ifndef _MSC_VER 81 | //THISCALL on GCC passes the this pointer on the stack, and is mostly identical to cdecl 82 | call_cdecl_prep(argBytes + 4); 83 | #endif 84 | } 85 | 86 | void Processor::call_thiscall_this(MemAddress address) { 87 | #ifdef _MSC_VER 88 | Register(*this,ECX) = as(address); 89 | #else 90 | push(as(address)); 91 | #endif 92 | } 93 | 94 | void Processor::call_thiscall_this(Register& reg) { 95 | #ifdef _MSC_VER 96 | Register(*this,ECX) = reg; 97 | #else 98 | push(reg); 99 | #endif 100 | } 101 | 102 | void Processor::call_thiscall_this_mem(MemAddress address, Register& memreg) { 103 | call_thiscall_this(address); 104 | push(memreg); 105 | } 106 | 107 | void Processor::call_thiscall_this_mem(Register& reg, Register& memreg) { 108 | call_thiscall_this(reg); 109 | push(memreg); 110 | } 111 | 112 | void Processor::call_thiscall_end(unsigned argBytes, bool returnPointer) { 113 | #ifndef _MSC_VER 114 | //THISCALL callers on GCC pops arguments and pointers 115 | call_cdecl_end(argBytes + 4, returnPointer); 116 | #endif 117 | } 118 | 119 | void Processor::call_cdecl_prep(unsigned argBytes) { 120 | #ifndef _MSC_VER 121 | //Align to 16 byte boundary if not on MSVC 122 | unsigned stackOffset = (stackDepth + argBytes) % 16; 123 | 124 | Register esp(*this, ESP); 125 | if(stackOffset != 0) 126 | esp -= 16 - stackOffset; 127 | #endif 128 | } 129 | 130 | void Processor::call_cdecl_end(unsigned argBytes, bool returnPointer) { 131 | Register esp(*this, ESP); 132 | #ifdef _MSC_VER 133 | esp += argBytes; 134 | #else 135 | unsigned stackOffset = (stackDepth + argBytes) % 16; 136 | if(returnPointer) 137 | argBytes -= 4; 138 | if(stackOffset != 0) 139 | argBytes += (16 - stackOffset); 140 | if(argBytes != 0) 141 | esp += argBytes; 142 | #endif 143 | } 144 | 145 | unsigned Processor::call_cdecl_args(const char* args, va_list ap) { 146 | return call_thiscall_args(0, args, ap); 147 | } 148 | 149 | unsigned Processor::call_cdecl_args(const char* args, ...) { 150 | va_list ap; 151 | va_start(ap, args); 152 | unsigned r = call_cdecl_args(args, ap); 153 | va_end(ap); 154 | return r; 155 | } 156 | 157 | unsigned Processor::call_thiscall_args(Register* obj, const char* args, va_list ap) { 158 | std::stack arg_stack; 159 | 160 | unsigned argCount = 0; 161 | #ifdef _MSC_VER 162 | //TODO 163 | if(obj) 164 | throw "Implement this."; 165 | #else 166 | if(obj) { 167 | arg_stack.push(obj); 168 | ++argCount; 169 | } 170 | #endif 171 | //Read the arguments in... 172 | while(args, *args != '\0') { 173 | ++argCount; 174 | if(*args == 'r') 175 | arg_stack.push(va_arg(ap,Register*)); 176 | else if(*args == 'm') 177 | arg_stack.push(va_arg(ap,MemAddress*)); 178 | else if(*args == 'c' || *args == 'p') 179 | arg_stack.push(va_arg(ap,unsigned int)); 180 | else 181 | throw 0; 182 | ++args; 183 | } 184 | 185 | call_cdecl_prep(argCount * 4); 186 | 187 | //Then push them in reverse order 188 | while(!arg_stack.empty()) { 189 | auto& arg = arg_stack.top(); 190 | if(arg.reg) 191 | push(*arg.reg); 192 | else if(arg.mem) 193 | push(*arg.mem); 194 | else 195 | push(arg.constant); 196 | arg_stack.pop(); 197 | } 198 | return argCount * 4; 199 | } 200 | 201 | void Processor::call_cdecl(void* func, const char* args, va_list ap) { 202 | unsigned stackBytes = call_cdecl_args(args, ap); 203 | call(func); 204 | call_cdecl_end(stackBytes); 205 | } 206 | 207 | void Processor::call_cdecl(void* func, const char* args, ...) { 208 | va_list ap; 209 | va_start(ap, args); 210 | call_cdecl(func, args, ap); 211 | va_end(ap); 212 | } 213 | 214 | //STDCALL is similar to CDECL, but we don't need the call preperation or end 215 | void Processor::call_stdcall(void* func, const char* args, ...) { 216 | std::stack arg_stack; 217 | 218 | unsigned argCount = 0; 219 | if(args && *args != '\0') { 220 | //Read the arguments in... 221 | va_list list; va_start(list,args); 222 | while(*args != '\0') { 223 | ++argCount; 224 | if(*args == 'r') 225 | arg_stack.push(va_arg(list,Register*)); 226 | else if(*args == 'm') 227 | arg_stack.push(va_arg(list,MemAddress*)); 228 | else if(*args == 'c' || *args == 'p') 229 | arg_stack.push(va_arg(list,unsigned int)); 230 | else 231 | throw 0; 232 | ++args; 233 | } 234 | va_end(list); 235 | } 236 | 237 | #ifndef _MSC_VER 238 | //Still need to make sure the stack is aligned in GCC 239 | Register esp(*this, ESP); 240 | unsigned argBytes = argCount * sizeof(void*); 241 | unsigned stackOffset = (stackDepth + argBytes) % 16; 242 | if(stackOffset != 0) 243 | esp -= 16 - stackOffset; 244 | #endif 245 | 246 | //Then push them in reverse order 247 | while(!arg_stack.empty()) { 248 | auto& arg = arg_stack.top(); 249 | if(arg.reg) 250 | push(*arg.reg); 251 | else if(arg.mem) 252 | push(*arg.mem); 253 | else 254 | push(arg.constant); 255 | arg_stack.pop(); 256 | } 257 | 258 | call(func); 259 | 260 | #ifndef _MSC_VER 261 | if(stackOffset != 0) 262 | esp += 16 - stackOffset; 263 | #endif 264 | } 265 | 266 | Processor::Processor(CodePage& codePage, unsigned defaultBitMode ) { 267 | op = codePage.getActivePage(); 268 | pageStart = op; 269 | bitMode = defaultBitMode; 270 | lastBitMode = bitMode; 271 | stackDepth = 4; 272 | jumpSpace = 0; 273 | } 274 | 275 | void Processor::migrate(CodePage& prevPage, CodePage& newPage) { 276 | jump(Jump,newPage.getActivePage()); 277 | prevPage.markUsedAddress((void*)op); 278 | op = newPage.getActivePage(); 279 | } 280 | 281 | IndexScale factorToScale(unsigned char scale) { 282 | switch(scale) { 283 | case 1: 284 | return Scale1; break; 285 | case 2: 286 | return Scale2; break; 287 | case 4: 288 | return Scale4; break; 289 | case 8: 290 | return Scale8; break; 291 | default: throw 0; 292 | } 293 | } 294 | 295 | template<> 296 | Processor& Processor::operator<<(MemAddress addr) { 297 | if(addr.absolute_address != 0) { 298 | if(addr.scaleFactor == 0) 299 | return *this << mod_rm(addr.other, ADR, ADDR) << addr.absolute_address; 300 | else { 301 | if(addr.scaleReg == ESP) 302 | throw 0; 303 | IndexScale scale = factorToScale(addr.scaleFactor); 304 | return *this << mod_rm(addr.other, ADR, SIB) << sib(addr.scaleReg, scale, EBP) << addr.absolute_address; 305 | } 306 | } 307 | 308 | if(addr.scaleFactor != 0) { 309 | IndexScale scale = factorToScale(addr.scaleFactor); 310 | 311 | //EBP can't accept a scaled index, and ESP doesn't perform scaling 312 | if(addr.scaleReg == ESP) 313 | throw 0; 314 | 315 | if(addr.offset == 0 && addr.code != EBP) 316 | return *this << mod_rm(addr.other, ADR, SIB) << sib(addr.scaleReg, scale, addr.code); 317 | else if(addr.offset >= CHAR_MIN && addr.offset <= CHAR_MAX) 318 | return *this << mod_rm(addr.other, ADR8, SIB) << sib(addr.scaleReg, scale, addr.code) << (char)addr.offset; 319 | else 320 | return *this << mod_rm(addr.other, ADR32, SIB) << sib(addr.scaleReg, scale, addr.code) << addr.offset; 321 | } 322 | 323 | if(addr.offset == 0 && addr.code != EBP) { //[EBP] means absolute address, so we use [EBP+0] instead 324 | *this << mod_rm(addr.other, ADR, addr.code); 325 | if(addr.code == ESP) 326 | *this << '\x24'; //SIB byte indicating [ESP] 327 | } 328 | else if(addr.offset >= CHAR_MIN && addr.offset <= CHAR_MAX) { 329 | *this << mod_rm(addr.other, ADR8, addr.code); 330 | if(addr.code == ESP) 331 | *this << '\x24'; //SIB byte indicating [ESP] 332 | *this << (char)addr.offset; 333 | } 334 | else { 335 | *this << mod_rm(addr.other, ADR32, addr.code); 336 | if(addr.code == ESP) 337 | *this << '\x24'; //SIB byte indicating [ESP] 338 | *this << addr.offset; 339 | } 340 | return *this; 341 | } 342 | 343 | void Processor::push(Register& reg) { 344 | *this << byte(0x50u+reg.code); 345 | } 346 | 347 | void Processor::pop(Register& reg) { 348 | *this << byte(0x58u+reg.code); 349 | } 350 | 351 | void Processor::push(MemAddress address) { 352 | address.other = EX_6; 353 | switch(address.bitMode) { 354 | case 8: 355 | case 16: 356 | case 32: 357 | *this << '\xFF' << address; break; 358 | case 64: 359 | MemAddress upper(address); moveToUpperDWORD(upper); 360 | *this << '\xFF' << upper; 361 | *this << '\xFF' << address; break; 362 | } 363 | } 364 | 365 | void Processor::pop(MemAddress address) { 366 | address.other = EX_0; 367 | switch(address.bitMode) { 368 | case 8: 369 | case 16: 370 | case 32: 371 | *this << '\x8F' << address; break; 372 | case 64: 373 | *this << '\x8F' << address; 374 | moveToUpperDWORD(address); 375 | *this << '\x8F' << address; 376 | break; 377 | } 378 | } 379 | 380 | void Processor::push(size_t value) { 381 | if(value <= CHAR_MAX) 382 | *this << '\x6A' << (byte)value; 383 | else 384 | *this << '\x68' << (unsigned int)value; 385 | } 386 | 387 | void Processor::pop(unsigned int count) { 388 | Register esp(*this, ESP); 389 | esp += count * pushSize(); 390 | } 391 | 392 | void Processor::call(Register& reg) { 393 | *this << '\xFF' << mod_rm(EX_2,REG,reg.code); 394 | } 395 | 396 | void Processor::call(void* func) { 397 | int offset = ((byte*)func - op) - 5; 398 | *this << '\xE8' << offset; 399 | } 400 | 401 | unsigned char shortJumpCodes[JumpTypeCount] = { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0xEB}; 402 | unsigned char longJumpCodes[JumpTypeCount] = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0xE9 }; 403 | 404 | void* Processor::prep_short_jump(JumpType type) { 405 | *this << shortJumpCodes[type]; 406 | void* ret = (void*)op; 407 | *this << (char)0; 408 | return ret; 409 | } 410 | 411 | void Processor::end_short_jump(void* p) { 412 | volatile byte* jumpFrom = (volatile byte*)p; 413 | int offset = (op - jumpFrom) - 1; 414 | if(offset < CHAR_MIN || offset > CHAR_MAX) 415 | throw 0; 416 | *jumpFrom = (char)offset; 417 | } 418 | 419 | void* Processor::prep_long_jump(JumpType type) { 420 | if(type != Jump) 421 | *this << '\x0F'; 422 | *this << longJumpCodes[type]; 423 | void* ret = (void*)op; 424 | *this << (int)0; 425 | return ret; 426 | } 427 | 428 | void Processor::end_long_jump(void* p) { 429 | volatile byte* jumpFrom = (volatile byte*)p; 430 | *(volatile int*)jumpFrom = (op - jumpFrom) - 4; 431 | } 432 | 433 | void Processor::jump(JumpType type, volatile byte* dest) { 434 | int offset = (dest - op) - 2; 435 | if(offset >= CHAR_MIN && offset <= CHAR_MAX) 436 | *this << shortJumpCodes[type] << (char)offset; 437 | else if(type == Jump) 438 | *this << longJumpCodes[Jump] << offset-3; //Long jump is 3 bytes larger, jump is from the end of the full opcode 439 | else 440 | *this << '\x0F' << longJumpCodes[type] << offset-4; //Conditional long jump is 4 bytes larger, jump is from the end of the full opcode 441 | } 442 | 443 | void Processor::jump(Register& reg) { 444 | *this << '\xFF' << mod_rm(EX_4,REG,reg.code); 445 | } 446 | 447 | void Processor::loop(volatile byte* dest, JumpType type) { 448 | int off = dest - op - 2; 449 | if(off < CHAR_MIN || off > CHAR_MAX) 450 | throw "Loop offset too far."; 451 | 452 | if(type == Jump) 453 | *this << '\xE2' << (char)off; 454 | else if(type == Zero) 455 | *this << '\xE1' << (char)off; 456 | else if(type == NotZero) 457 | *this << '\xE0' << (char)off; 458 | else 459 | throw "Unsupported loop type."; 460 | } 461 | 462 | void Processor::string_copy(unsigned size) { 463 | if(size == 1) 464 | *this << '\xA4'; 465 | else if(size == 2) 466 | *this << '\x66' << '\xA5'; 467 | else if(size == 4) 468 | *this << '\xA5'; 469 | else if(size == 8) 470 | *this << '\xA5' << '\xA5'; //Just copy twice for 8 bytes (for 64 bit compatibility) 471 | else 472 | throw "Invalid string copy step size."; 473 | } 474 | 475 | void Processor::setDirFlag(bool forward) { 476 | if(forward) 477 | *this << '\xFC'; 478 | else 479 | *this << '\xFD'; 480 | } 481 | 482 | void Processor::ret() { 483 | *this << '\xC3'; 484 | } 485 | 486 | void Processor::debug_interrupt() { 487 | *this << '\xCC'; 488 | } 489 | 490 | MemAddress::MemAddress(Processor& CPU, void* address) 491 | : cpu(CPU), code(ESP), absolute_address(address), other(NONE), 492 | offset(0), bitMode(cpu.bitMode), Signed(false), scaleFactor(0) {} 493 | 494 | MemAddress::MemAddress(Processor& CPU, RegCode Code) 495 | : cpu(CPU), code(Code), absolute_address(0), other(NONE), 496 | offset(0), bitMode(cpu.bitMode), Signed(false), scaleFactor(0) {} 497 | 498 | MemAddress::MemAddress(Processor& CPU, RegCode Code, int Offset) 499 | : cpu(CPU), code(Code), absolute_address(0), other(NONE), 500 | offset(Offset), bitMode(cpu.bitMode), Signed(false), scaleFactor(0) {} 501 | 502 | 503 | MemAddress MemAddress::operator+(ScaledIndex scale) { 504 | scaleReg = scale.reg; 505 | scaleFactor = scale.scaleFactor; 506 | return *this; 507 | } 508 | 509 | MemAddress MemAddress::operator+(int Offset) { 510 | offset += Offset; 511 | return *this; 512 | } 513 | 514 | MemAddress MemAddress::operator-(int Offset) { 515 | offset -= Offset; 516 | return *this; 517 | } 518 | 519 | void MemAddress::operator++() { 520 | switch(bitMode) { 521 | case 8: 522 | cpu << '\xFE' << *this; break; 523 | case 16: 524 | cpu << '\x66' << '\xFF' << *this; break; 525 | case 32: 526 | cpu << '\xFF' << *this; break; 527 | case 64: 528 | cpu << '\xFF' << *this; 529 | void* p = cpu.prep_short_jump(NotOverflow); 530 | moveToUpperDWORD(*this); 531 | cpu << '\xFF' << *this; 532 | cpu.end_short_jump(p); 533 | } 534 | } 535 | 536 | void MemAddress::operator--() { 537 | other = EX_1; 538 | switch(bitMode) { 539 | case 8: 540 | cpu << '\xFE' << *this; break; 541 | case 16: 542 | cpu << '\x66' << '\xFF' << *this; break; 543 | case 32: 544 | cpu << '\xFF' << *this; break; 545 | case 64: 546 | cpu << '\xFF' << *this; 547 | void* p = cpu.prep_short_jump(NotOverflow); 548 | moveToUpperDWORD(*this); 549 | cpu << '\xFF' << *this; 550 | cpu.end_short_jump(p); 551 | } 552 | } 553 | 554 | void MemAddress::operator-() { 555 | other = EX_3; 556 | switch(bitMode) { 557 | case 8: 558 | cpu << '\xF6' << *this; break; 559 | case 16: 560 | cpu << '\x66' << '\xF7' << *this; break; 561 | case 32: 562 | cpu << '\xF7' << *this; break; 563 | case 64: 564 | ~MemAddress(*this); 565 | ++MemAddress(*this); break; 566 | } 567 | } 568 | 569 | void MemAddress::operator~() { 570 | other = EX_2; 571 | switch(bitMode) { 572 | case 8: 573 | cpu << '\xF6' << *this; break; 574 | case 16: 575 | cpu << '\x66' << '\xF7' << *this; break; 576 | case 32: 577 | cpu << '\xF7' << *this; break; 578 | case 64: 579 | cpu << '\xF7' << *this; 580 | moveToUpperDWORD(*this); 581 | cpu << '\xF7' << *this; break; 582 | } 583 | } 584 | 585 | void MemAddress::operator+=(unsigned int amount) { 586 | if(amount == 0) return; 587 | 588 | if(code == EAX) 589 | cpu << '\x05' << amount; 590 | else if(amount <= CHAR_MAX) 591 | cpu << '\x83' << *this << (byte)amount; 592 | else 593 | cpu << '\x81' << *this << amount; 594 | } 595 | 596 | void MemAddress::operator-=(unsigned int amount) { 597 | if(amount == 0) return; 598 | 599 | other = (RegCode)EX_5; 600 | if(code == EAX) 601 | cpu << '\x2D' << amount; 602 | else if(amount <= CHAR_MAX) 603 | cpu << '\x83' << *this << (byte)amount; 604 | else 605 | cpu << '\x81' << *this << amount; 606 | } 607 | 608 | void MemAddress::operator=(unsigned int value) { 609 | switch(bitMode) { 610 | case 8: 611 | cpu << '\xC6' << *this << (byte)value; break; 612 | case 16: 613 | cpu << '\x66' << '\xC7' << *this << (unsigned short)value; break; 614 | case 32: 615 | cpu << '\xC7' << *this << value; break; 616 | } 617 | } 618 | 619 | void MemAddress::operator&=(unsigned int value) { 620 | other = EX_4; 621 | cpu << '\x81' << *this << value; 622 | } 623 | 624 | void MemAddress::operator|=(unsigned int value) { 625 | other = EX_7; 626 | switch(bitMode) { 627 | case 8: 628 | cpu << '\x80' << *this << (byte)value; break; 629 | case 16: 630 | cpu << '\x66' << '\x81' << *this << (unsigned short)value; break; 631 | case 32: 632 | cpu << '\x81' << *this << value; break; 633 | } 634 | } 635 | 636 | void MemAddress::operator=(void* value) { 637 | cpu << '\xC7' << *this << value; 638 | } 639 | 640 | void MemAddress::operator=(Register fromReg) { 641 | other = fromReg.code; 642 | switch(bitMode) { 643 | case 8: 644 | cpu << '\x88' << *this; break; 645 | case 16: 646 | cpu << '\x66' << '\x89' << *this; break; 647 | case 32: 648 | cpu << '\x89' << *this; break; 649 | case 64: 650 | throw 0; 651 | } 652 | } 653 | 654 | void MemAddress::direct_copy(MemAddress address, Register& intermediate) { 655 | if(bitMode != address.bitMode) 656 | throw 0; 657 | other = intermediate.code; address.other = other; 658 | switch(bitMode) { 659 | case 8: 660 | case 16: 661 | case 32: 662 | intermediate = address; 663 | *this = intermediate; 664 | break; 665 | case 64: 666 | bitMode = 32; address.bitMode = 32; 667 | 668 | intermediate = address; 669 | *this = intermediate; 670 | moveToUpperDWORD(*this); moveToUpperDWORD(address); 671 | intermediate = address; 672 | *this = intermediate; 673 | break; 674 | } 675 | } 676 | 677 | Register::Register(Processor& CPU, RegCode Code) : cpu(CPU), code(Code), bitMode(0) {} 678 | 679 | Register::Register(Processor& CPU, RegCode Code, unsigned BitModeOverride) 680 | : cpu(CPU), code(Code), bitMode(BitModeOverride) { 681 | } 682 | 683 | unsigned Register::getBitMode() const { 684 | if(bitMode) 685 | return bitMode; 686 | else 687 | return cpu.bitMode; 688 | } 689 | 690 | unsigned Register::getBitMode(const MemAddress& addr) const { 691 | if(bitMode == 0) 692 | return addr.bitMode; 693 | else if(bitMode <= addr.bitMode) 694 | return bitMode; 695 | else 696 | throw 0; 697 | } 698 | 699 | MemAddress Register::operator*() const { 700 | return MemAddress(cpu,code); 701 | } 702 | 703 | ScaledIndex Register::operator*(unsigned char scale) const { 704 | return ScaledIndex(code, scale); 705 | } 706 | 707 | void Register::swap(MemAddress address) { 708 | address.other = code; 709 | switch(getBitMode(address)) { 710 | case 8: 711 | cpu << '\x86' << address; break; 712 | case 16: 713 | cpu << '\x66' << '\x87' << address; break; 714 | case 32: 715 | cpu << '\x87' << address; break; 716 | case 64: 717 | throw 0; 718 | } 719 | } 720 | 721 | void Register::swap(Register& other) { 722 | if(code == other.code) 723 | return; 724 | if(code == EAX) 725 | cpu << byte(0x90+other.code); 726 | else if(other.code == EAX) 727 | cpu << byte(0x90+code); 728 | else 729 | cpu << '\x87' << mod_rm(code,REG,other.code); 730 | } 731 | 732 | void Register::copy_address(MemAddress address) { 733 | address.other = code; 734 | cpu << '\x8D' << address; 735 | } 736 | 737 | void Register::operator<<=(Register& other) { 738 | if(other.code != ECX) 739 | throw 0; 740 | cpu << '\xD3' << mod_rm(EX_4,REG,code); 741 | } 742 | 743 | void Register::operator>>=(Register& other) { 744 | if(other.code != ECX) 745 | throw 0; 746 | cpu << '\xD3' << mod_rm(EX_7,REG,code); 747 | } 748 | 749 | void Register::rightshift_logical(Register& other) { 750 | if(other.code != ECX) 751 | throw 0; 752 | cpu << '\xD3' << mod_rm(EX_5,REG,code); 753 | } 754 | 755 | void Register::operator+=(unsigned int amount) { 756 | if(amount == 0) return; 757 | if(amount == 1) { 758 | ++*this; 759 | return; 760 | } 761 | 762 | if(code == EAX) 763 | cpu << '\x05' << amount; 764 | else if(amount <= CHAR_MAX) 765 | cpu << '\x83' << mod_rm(EX_0,REG,code) << (byte)amount; 766 | else 767 | cpu << '\x81' << mod_rm(EX_0,REG,code) << amount; 768 | } 769 | 770 | void Register::operator+=(MemAddress address) { 771 | address.other = code; 772 | cpu << '\x03' << address; 773 | } 774 | 775 | void Register::operator+=(Register& other) { 776 | cpu << '\x03' << mod_rm(code,REG,other.code); 777 | } 778 | 779 | void Register::operator-=(unsigned int amount) { 780 | if(amount == 0) return; 781 | if(amount == 1) { 782 | --*this; 783 | return; 784 | } 785 | 786 | if(code == EAX) 787 | cpu << '\x2D' << amount; 788 | else if(amount <= CHAR_MAX) 789 | cpu << '\x83' << mod_rm(EX_5,REG,code) << (byte)amount; 790 | else 791 | cpu << '\x81' << mod_rm(EX_5,REG,code) << amount; 792 | } 793 | 794 | void Register::operator-=(Register& other) { 795 | cpu << '\x2B' << mod_rm(code,REG,other.code); 796 | } 797 | 798 | void Register::operator-=(MemAddress address) { 799 | address.other = code; 800 | cpu << '\x2B' << address; 801 | } 802 | 803 | void Register::operator*=(MemAddress address) { 804 | address.other = code; 805 | cpu << '\x0F' << '\xAF' << address; 806 | } 807 | 808 | void Register::multiply_signed(MemAddress address, int value) { 809 | address.other = code; 810 | if(cpu.bitMode == 32) { 811 | if(value >= CHAR_MIN && value <= CHAR_MAX) 812 | cpu << '\x6B' << address << (char)value; 813 | else 814 | cpu << '\x69' << address << value; 815 | } 816 | else if(cpu.bitMode == 16) { 817 | if(value >= CHAR_MIN && value <= CHAR_MAX) 818 | cpu << '\x66' << '\x6B' << address << (char)value; 819 | else 820 | cpu << '\x66' << '\x69' << address << (short)value; 821 | } 822 | } 823 | 824 | void Register::operator-() { 825 | cpu << '\xF7' << mod_rm(EX_3,REG,code); 826 | } 827 | 828 | void Register::operator--() { 829 | switch(getBitMode()) { 830 | case 8: 831 | cpu << '\xFE' << mod_rm(EX_1,REG,code); break; 832 | case 16: 833 | cpu << '\x66' << byte('\x48'+code); break; 834 | case 32: 835 | cpu << byte('\x48'+code); break; 836 | case 64: 837 | throw 0; 838 | } 839 | } 840 | 841 | void Register::operator++() { 842 | switch(getBitMode()) { 843 | case 8: 844 | cpu << '\xFE' << mod_rm(EX_0,REG,code); break; 845 | case 16: 846 | cpu << '\x66' << byte('\x40'+code); break; 847 | case 32: 848 | cpu << byte('\x40'+code); break; 849 | case 64: 850 | throw 0; 851 | } 852 | } 853 | 854 | void Register::operator~() { 855 | if(getBitMode() == 8) { 856 | cpu << '\xF6' << mod_rm(EX_2,REG,code); 857 | } 858 | else { 859 | cpu << '\xF7' << mod_rm(EX_2,REG,code); 860 | } 861 | } 862 | 863 | void Register::operator&=(MemAddress address) { 864 | address.other = code; 865 | cpu << '\x23' << address; 866 | } 867 | 868 | void Register::operator&=(unsigned long long mask) { 869 | switch(getBitMode()) { 870 | case 8: 871 | cpu << '\x80' << mod_rm(EX_4,REG,code) << (byte)mask; break; 872 | case 16: 873 | cpu << '\x66' << '\x81' << mod_rm(EX_4,REG,code) << (unsigned short)mask; break; 874 | case 32: 875 | case 64: 876 | if(code == EAX) 877 | cpu << '\x25' << (unsigned)mask; 878 | else 879 | cpu << '\x81' << mod_rm(EX_4,REG,code) << (unsigned)mask; 880 | } 881 | } 882 | 883 | void Register::operator&=(Register other) { 884 | switch(getBitMode()) { 885 | case 8: 886 | cpu << '\x20' << mod_rm(other.code,REG,code); break; 887 | case 16: 888 | cpu << '\x66' << '\x21' << mod_rm(other.code,REG,code); break; 889 | case 32: 890 | case 64: 891 | cpu << '\x21' << mod_rm(other.code,REG,code); break; 892 | } 893 | } 894 | 895 | void Register::operator^=(MemAddress address) { 896 | address.other = code; 897 | cpu << '\x33' << address; 898 | } 899 | 900 | void Register::operator^=(Register& other) { 901 | cpu << '\x31' << mod_rm(other.code,REG,code); 902 | } 903 | 904 | void Register::operator|=(MemAddress address) { 905 | address.other = code; 906 | cpu << '\x0B' << address; 907 | } 908 | 909 | void Register::operator|=(unsigned long long mask) { 910 | switch(getBitMode()) { 911 | case 8: 912 | cpu << '\x80' << mod_rm(EX_1,REG,code) << (byte)mask; break; 913 | case 16: 914 | cpu << '\x66' << '\x81' << mod_rm(EX_1,REG,code) << (unsigned short)mask; break; 915 | case 32: 916 | case 64: 917 | if(code == EAX) 918 | cpu << '\x0D' << (unsigned)mask; 919 | else 920 | cpu << '\x81' << mod_rm(EX_1,REG,code) << (unsigned)mask; 921 | } 922 | } 923 | 924 | void Register::operator=(void* pointer) { 925 | cpu << (byte)('\xB8'+code) << pointer; 926 | } 927 | 928 | void Register::operator=(unsigned long long value) { 929 | switch(getBitMode()) { 930 | case 8: 931 | cpu << (byte)('\xB0'+code) << (byte)value; break; 932 | case 16: 933 | cpu << '\x66' << (byte)('\xB8'+code) << (unsigned short)value; break; 934 | case 32: 935 | cpu << (byte)('\xB8'+code) << (unsigned int)value; break; 936 | case 64: 937 | throw 0; 938 | } 939 | } 940 | 941 | void* Register::setDeferred(unsigned long long value) { 942 | void* ptr = 0; 943 | switch(getBitMode()) { 944 | case 8: 945 | cpu << (byte)('\xB0'+code); 946 | ptr = (void*)cpu.op; 947 | cpu << (byte)value; break; 948 | case 16: 949 | cpu << '\x66' << (byte)('\xB8'+code); 950 | ptr = (void*)cpu.op; 951 | cpu << (unsigned short)value; break; 952 | case 32: 953 | cpu << (byte)('\xB8'+code); 954 | ptr = (void*)cpu.op; 955 | cpu << (unsigned int)value; break; 956 | case 64: 957 | throw 0; 958 | } 959 | return ptr; 960 | } 961 | 962 | void Register::operator=(Register other) { 963 | if(code != other.code) 964 | cpu << '\x89' << mod_rm(other.code,REG,code); 965 | } 966 | 967 | void Register::copy_expanding(MemAddress address) { 968 | address.other = code; 969 | switch(getBitMode(address)) { 970 | case 8: 971 | cpu << '\x0F' << '\xBE' << address; break; 972 | case 16: 973 | cpu << '\x0F' << '\xBF' << address; break; 974 | case 32: 975 | *this = address; break; 976 | case 64: 977 | throw 0; 978 | } 979 | } 980 | 981 | void Register::copy_zeroing(Register& other) { 982 | switch(getBitMode()) { 983 | case 8: 984 | case 16: 985 | throw 0; 986 | case 32: 987 | cpu << '\x0F' << '\xB6' << mod_rm(code,REG,other.code); break; 988 | case 64: 989 | throw 0; 990 | } 991 | } 992 | 993 | void Register::operator=(MemAddress addr) { 994 | addr.other = code; 995 | switch(getBitMode(addr)) { 996 | case 8: 997 | cpu << '\x8A' << addr; break; 998 | case 16: 999 | cpu << '\x66' << '\x8B' << addr; break; 1000 | case 32: 1001 | cpu << '\x8B' << addr; break; 1002 | case 64: 1003 | throw 0; 1004 | } 1005 | } 1006 | 1007 | void Register::operator==(Register other) { 1008 | switch(getBitMode()) { 1009 | case 8: 1010 | cpu << '\x3A' << mod_rm(code,REG,other.code); break; 1011 | case 16: 1012 | cpu << '\x66' << '\x3B' << mod_rm(code,REG,other.code); break; 1013 | case 32: 1014 | cpu << '\x3B' << mod_rm(code,REG,other.code); break; 1015 | case 64: 1016 | throw 0; 1017 | } 1018 | } 1019 | 1020 | void Register::operator==(MemAddress addr) { 1021 | addr.other = code; 1022 | switch(getBitMode(addr)) { 1023 | case 8: 1024 | cpu << '\x3A' << addr; break; 1025 | case 16: 1026 | cpu << '\x66' << '\x3B' << addr; break; 1027 | case 32: 1028 | cpu << '\x3B' << addr; break; 1029 | case 64: 1030 | throw 0; 1031 | } 1032 | } 1033 | 1034 | void Register::operator==(unsigned int test) { 1035 | switch(getBitMode()) { 1036 | case 8: 1037 | cpu << '\x80' << mod_rm(EX_7,REG,code) << (byte)test; break; 1038 | case 16: 1039 | cpu << '\x66' << '\x80' << mod_rm(EX_7,REG,code) << (unsigned short)test; break; 1040 | case 32: 1041 | cpu << '\x81' << mod_rm(EX_7,REG,code) << test; break; 1042 | case 64: 1043 | throw 0; 1044 | } 1045 | } 1046 | 1047 | unsigned char setConditions[JumpTypeCount-1] = {0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F}; 1048 | 1049 | void Register::setIf(JumpType condition) { 1050 | if(condition >= Jump) 1051 | throw 0; 1052 | cpu << '\x0F' << setConditions[condition] << mod_rm(EX_0,REG,code); 1053 | } 1054 | 1055 | void Register::divide() { 1056 | cpu << '\xF7' << mod_rm(EX_6,REG,code); 1057 | } 1058 | 1059 | void Register::divide_signed() { 1060 | cpu << '\xF7' << mod_rm(EX_7,REG,code); 1061 | } 1062 | 1063 | FloatingPointUnit::FloatingPointUnit(Processor& CPU) : cpu(CPU) {} 1064 | 1065 | void FloatingPointUnit::pop() { 1066 | //FSTP ST0 1067 | cpu << '\xDD' << '\xD8'; 1068 | } 1069 | 1070 | void FloatingPointUnit::init() { 1071 | cpu << '\xDB' << '\xE3'; 1072 | } 1073 | 1074 | void FloatingPointUnit::negate() { 1075 | cpu << '\xD9' << '\xE0'; 1076 | } 1077 | 1078 | void FloatingPointUnit::exchange(FloatReg reg) { 1079 | cpu << '\xD9' << mod_rm(EX_1,REG,reg); 1080 | } 1081 | 1082 | void FloatingPointUnit::load_const_0() { 1083 | cpu << '\xD9' << '\xEE'; 1084 | } 1085 | 1086 | void FloatingPointUnit::load_const_1() { 1087 | cpu << '\xD9' << '\xE8'; 1088 | } 1089 | 1090 | void FloatingPointUnit::operator-=(FloatReg reg) { 1091 | cpu << '\xDC' << mod_rm(EX_4,REG,reg); 1092 | } 1093 | 1094 | void FloatingPointUnit::load_double(MemAddress address) { 1095 | address.other = EX_0; 1096 | cpu << '\xDD' << address; 1097 | } 1098 | 1099 | void FloatingPointUnit::add_double(MemAddress address) { 1100 | address.other = EX_0; 1101 | cpu << '\xDC' << address; 1102 | } 1103 | 1104 | void FloatingPointUnit::add_double(FloatReg reg, bool pop) { 1105 | if(pop) 1106 | cpu << '\xDE' << mod_rm(EX_0,REG,reg); 1107 | else 1108 | cpu << '\xDC' << mod_rm(EX_0,REG,reg); 1109 | } 1110 | 1111 | void FloatingPointUnit::sub_double(MemAddress address, bool reversed) { 1112 | address.other = reversed ? EX_5 : EX_4; 1113 | cpu << '\xDC' << address; 1114 | } 1115 | 1116 | void FloatingPointUnit::sub_double(FloatReg reg, bool reversed, bool pop) { 1117 | if(pop) 1118 | cpu << '\xDE' << mod_rm(reversed ? EX_5 : EX_4, REG, reg); 1119 | else 1120 | cpu << '\xDC' << mod_rm(reversed ? EX_5 : EX_4, REG, reg); 1121 | } 1122 | 1123 | void FloatingPointUnit::mult_double(MemAddress address) { 1124 | address.other = EX_1; 1125 | cpu << '\xDC' << address; 1126 | } 1127 | 1128 | void FloatingPointUnit::mult_double(FloatReg reg, bool pop) { 1129 | if(pop) 1130 | cpu << '\xDE' << mod_rm(EX_1,REG,reg); 1131 | else 1132 | cpu << '\xDC' << mod_rm(EX_1,REG,reg); 1133 | } 1134 | 1135 | void FloatingPointUnit::div_double(MemAddress address, bool reversed) { 1136 | address.other = reversed ? EX_7 : EX_6; 1137 | cpu << '\xDC' << address; 1138 | } 1139 | 1140 | void FloatingPointUnit::div_double(FloatReg reg, bool reversed, bool pop) { 1141 | if(pop) 1142 | cpu << '\xDE' << mod_rm(reversed ? EX_7 : EX_6, REG, reg); 1143 | else 1144 | cpu << '\xDC' << mod_rm(reversed ? EX_7 : EX_6, REG, reg); 1145 | } 1146 | 1147 | void FloatingPointUnit::add_float(MemAddress address) { 1148 | address.other = EX_0; 1149 | cpu << '\xD8' << address; 1150 | } 1151 | 1152 | void FloatingPointUnit::sub_float(MemAddress address) { 1153 | address.other = EX_4; 1154 | cpu << '\xD8' << address; 1155 | } 1156 | 1157 | void FloatingPointUnit::mult_float(MemAddress address) { 1158 | address.other = EX_1; 1159 | cpu << '\xD8' << address; 1160 | } 1161 | 1162 | void FloatingPointUnit::div_float(MemAddress address) { 1163 | address.other = EX_6; 1164 | cpu << '\xD8' << address; 1165 | } 1166 | 1167 | void FloatingPointUnit::store_double(MemAddress address, bool pop) { 1168 | address.other = pop ? EX_3 : EX_2; 1169 | cpu << '\xDD' << address; 1170 | } 1171 | 1172 | void FloatingPointUnit::load_float(MemAddress address) { 1173 | address.other = EX_0; 1174 | cpu << '\xD9' << address; 1175 | } 1176 | 1177 | void FloatingPointUnit::store_float(MemAddress address, bool pop) { 1178 | address.other = pop ? EX_3 : EX_2; 1179 | cpu << '\xD9' << address; 1180 | } 1181 | 1182 | void FloatingPointUnit::load_dword(MemAddress address) { 1183 | address.other = EX_0; 1184 | cpu << '\xDB' << address; 1185 | } 1186 | 1187 | void FloatingPointUnit::store_dword(MemAddress address, bool pop) { 1188 | address.other = pop ? EX_3 : EX_2; 1189 | cpu << '\xDB' << address; 1190 | } 1191 | 1192 | void FloatingPointUnit::load_qword(MemAddress address) { 1193 | address.other = EX_5; 1194 | cpu << '\xDF' << address; 1195 | } 1196 | 1197 | void FloatingPointUnit::compare_toCPU(FloatReg floatReg, bool pop) { 1198 | if(pop) 1199 | cpu << '\xDF' << mod_rm(EX_5,REG,floatReg); 1200 | else 1201 | cpu << '\xDB' << mod_rm(EX_5,REG,floatReg); 1202 | } 1203 | 1204 | void FloatingPointUnit::store_control_word(MemAddress address) { 1205 | address.other = EX_7; 1206 | cpu << '\xD9' << address; 1207 | } 1208 | 1209 | void FloatingPointUnit::load_control_word(MemAddress address) { 1210 | address.other = EX_5; 1211 | cpu << '\xD9' << address; 1212 | } 1213 | 1214 | }; 1215 | --------------------------------------------------------------------------------