1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-22 14:24:33 +01:00

Update hooks to return CPU flags

This commit is contained in:
Marijn van der Werf
2016-11-13 18:32:32 +01:00
parent 4077e607b0
commit 15a6575346
3 changed files with 219 additions and 228 deletions

View File

@@ -27,9 +27,12 @@
#include "hook.h"
#include "platform/platform.h"
void* g_hooktableaddress = 0;
int g_hooktableoffset = 0;
int g_maxhooks = 1000;
void* _hookTableAddress = 0;
int _hookTableOffset = 0;
int _maxHooks = 1000;
#define HOOK_BYTE_COUNT (140)
registers gHookRegisters = {0};
// This macro writes a little-endian 4-byte long value into *data
// It is used to avoid type punning.
@@ -39,165 +42,115 @@ int g_maxhooks = 1000;
*(data + 2) = ((addr) & 0x00ff0000) >> 16; \
*(data + 3) = ((addr) & 0xff000000) >> 24;
static void hookfunc(int address, int newaddress, int stacksize, int registerargs[], int registersreturned, int eaxDestinationRegister)
static void hookfunc(uintptr_t address, uintptr_t hookAddress, int stacksize)
{
int i = 0;
char data[100];
uint8 data[HOOK_BYTE_COUNT] = {0};
registersreturned |= eaxDestinationRegister;
uintptr_t registerAddress = (uintptr_t) &gHookRegisters;
int registerssaved = 7;
int n = registersreturned;
for (; n; registerssaved--) {
n &= n - 1;
}
int numrargs = 0;
for (int j = 0; ; j++) {
if (registerargs[j] != END) {
numrargs++;
} else {
break;
}
}
data[i++] = 0x89; // mov [gHookRegisters], eax
data[i++] = (0b000 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress);
i += 4;
int rargssize = numrargs * 4;
data[i++] = 0x89; // mov [gHookRegisters + 4], ebx
data[i++] = (0b011 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 4);
i += 4;
if (!(registersreturned & EAX)) {
data[i++] = 0x50; // push eax
}
if (!(registersreturned & EBX)) {
data[i++] = 0x53; // push ebx
}
if (!(registersreturned & ECX)) {
data[i++] = 0x51; // push ecx
}
if (!(registersreturned & EDX)) {
data[i++] = 0x52; // push edx
}
if (!(registersreturned & EBP)) {
data[i++] = 0x55; // push ebp
}
if (!(registersreturned & ESI)) {
data[i++] = 0x56; // push esi
}
if (!(registersreturned & EDI)) {
data[i++] = 0x57; // push edi
}
data[i++] = 0x89; // mov [gHookRegisters + 8], ecx
data[i++] = (0b001 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 8);
i += 4;
data[i++] = 0x50; //push eax
data[i++] = 0x89; //mov eax, esp
data[i++] = 0xE0;
data[i++] = 0x83; //sub eax, (0xC + numargs*4) & 0xF
data[i++] = 0xE8;
data[i++] = (0xC + numrargs * 4) & 0xF;
data[i++] = 0x83; //and eax, 0xC
data[i++] = 0xE0;
data[i++] = 0x0C;
data[i++] = 0xA3; //mov [0x9ABDA8], eax
data[i++] = 0xA8;
data[i++] = 0xBD;
data[i++] = 0x9A;
data[i++] = 0x00;
data[i++] = 0x58; //pop eax
data[i++] = 0x2B; //sub esp, [0x9ABDA8]
data[i++] = 0x25;
data[i++] = 0xA8;
data[i++] = 0xBD;
data[i++] = 0x9A;
data[i++] = 0x00;
data[i++] = 0x89; // mov [gHookRegisters + 12], edx
data[i++] = (0b010 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 12);
i += 4;
data[i++] = 0x89; // mov [gHookRegisters + 16], esi
data[i++] = (0b110 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 16);
i += 4;
data[i++] = 0x89; // mov [gHookRegisters + 20], edi
data[i++] = (0b111 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 20);
i += 4;
data[i++] = 0x89; // mov [gHookRegisters + 24], ebp
data[i++] = (0b101 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 24);
i += 4;
// work out distance to nearest 0xC
// (esp - numargs * 4) & 0xC
// move to align - 4
// save that amount
if (numrargs > 0) {
// push the registers to be on the stack to access as arguments
for (signed int j = numrargs - 1; j >= 0; j--) {
switch (registerargs[j]) {
case EAX: data[i++] = 0x50; break;
case EBX: data[i++] = 0x53; break;
case ECX: data[i++] = 0x51; break;
case EDX: data[i++] = 0x52; break;
case ESI: data[i++] = 0x56; break;
case EDI: data[i++] = 0x57; break;
case EBP: data[i++] = 0x55; break;
}
}
}
// push the registers to be on the stack to access as arguments
data[i++] = 0x68; // push gHookRegisters
write_address_strictalias(&data[i], registerAddress);
i += 4;
data[i++] = 0xE8; // call
write_address_strictalias(&data[i], newaddress - address - i - 4);
write_address_strictalias(&data[i], hookAddress - address - i - 4);
i += 4;
// returnlocation:
switch (eaxDestinationRegister) {
case EBX:
// mov ebx, eax
data[i++] = 0x8B;
data[i++] = 0xD8;
break;
case ECX:
// mov ecx, eax
data[i++] = 0x8B;
data[i++] = 0xC8;
break;
case EDX:
// mov ecx, eax
data[i++] = 0x8B;
data[i++] = 0xD0;
break;
case ESI:
// mov ecx, eax
data[i++] = 0x8B;
data[i++] = 0xF0;
break;
case EDI:
// mov ecx, eax
data[i++] = 0x8B;
data[i++] = 0xF8;
break;
case EBP:
// mov ecx, eax
data[i++] = 0x8B;
data[i++] = 0xE8;
break;
}
data[i++] = 0x83; // add esp, 4
data[i++] = 0xC4;
data[i++] = 0x04;
data[i++] = 0x83; // sub esp, x
data[i++] = 0xEC;
data[i++] = (signed char)(stacksize * -4) - rargssize;
data[i++] = 0x03; //add esp, [0x9ABDA8]
data[i++] = 0x25;
data[i++] = 0xA8;
data[i++] = 0xBD;
data[i++] = 0x9A;
data[i++] = 0x25; // and eax,0xff
data[i++] = 0xff;
data[i++] = 0x00;
data[i++] = 0x00;
data[i++] = 0x00;
data[i++] = 0xc1; // shl eax, 8
data[i++] = 0xe0;
data[i++] = 0x08;
data[i++] = 0x9e; // sahf
data[i++] = 0x9c; // pushf
if (!(registersreturned & EDI)) {
data[i++] = 0x5F; // pop edi
}
if (!(registersreturned & ESI)) {
data[i++] = 0x5E; // pop esi
}
if (!(registersreturned & EBP)) {
data[i++] = 0x5D; // pop ebp
}
if (!(registersreturned & EDX)) {
data[i++] = 0x5A; // pop edx
}
if (!(registersreturned & ECX)) {
data[i++] = 0x59; // pop ecx
}
if (!(registersreturned & EBX)) {
data[i++] = 0x5B; // pop ebx
}
if (!(registersreturned & EAX)) {
data[i++] = 0x58; // pop eax
}
data[i++] = 0x8B; // mov eax, [gHookRegisters]
data[i++] = (0b000 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress);
i += 4;
data[i++] = 0x8B; // mov ebx, [gHookRegisters + 4]
data[i++] = (0b011 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 4);
i += 4;
data[i++] = 0x8B; // mov ecx, [gHookRegisters + 8]
data[i++] = (0b001 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 8);
i += 4;
data[i++] = 0x8B; // mov edx, [gHookRegisters + 12]
data[i++] = (0b010 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 12);
i += 4;
data[i++] = 0x8B; // mov esi, [gHookRegisters + 16]
data[i++] = (0b110 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 16);
i += 4;
data[i++] = 0x8B; // mov edi, [gHookRegisters + 20]
data[i++] = (0b111 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 20);
i += 4;
data[i++] = 0x8B; // mov ebp, [gHookRegisters + 24]
data[i++] = (0b101 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 24);
i += 4;
data[i++] = 0x9d; // popf
data[i++] = 0xC3; // retn
@@ -209,26 +162,26 @@ static void hookfunc(int address, int newaddress, int stacksize, int registerarg
#endif // __WINDOWS__
}
void addhook(int address, int newaddress, int stacksize, int registerargs[], int registersreturned, int eaxDestinationRegister)
void addhook(uintptr_t address, hook_function *function)
{
if (!g_hooktableaddress) {
size_t size = g_maxhooks * 100;
if (!_hookTableAddress) {
size_t size = _maxHooks * HOOK_BYTE_COUNT;
#ifdef __WINDOWS__
g_hooktableaddress = VirtualAllocEx(GetCurrentProcess(), NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
_hookTableAddress = VirtualAllocEx(GetCurrentProcess(), NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
#else
g_hooktableaddress = mmap(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (g_hooktableaddress == MAP_FAILED)
_hookTableAddress = mmap(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (_hookTableAddress == MAP_FAILED)
{
perror("mmap");
exit(1);
}
#endif // __WINDOWS__
}
if (g_hooktableoffset > g_maxhooks) {
if (_hookTableOffset > _maxHooks) {
return;
}
unsigned int hookaddress = (unsigned int)g_hooktableaddress + (g_hooktableoffset * 100);
char data[9];
unsigned int hookaddress = (unsigned int)_hookTableAddress + (_hookTableOffset * HOOK_BYTE_COUNT);
uint8 data[9];
int i = 0;
data[i++] = 0xE9; // jmp
@@ -254,8 +207,8 @@ void addhook(int address, int newaddress, int stacksize, int registerargs[], int
perror("mprotect");
}
#endif // __WINDOWS__
hookfunc(hookaddress, newaddress, stacksize, registerargs, registersreturned, eaxDestinationRegister);
g_hooktableoffset++;
hookfunc(hookaddress, (uintptr_t)function, 0);
_hookTableOffset++;
}
#endif

View File

@@ -19,18 +19,19 @@
#ifndef NO_RCT2
enum REGISTER_ARGS {
EAX = 1 << 0,
EBX = 1 << 1,
ECX = 1 << 2,
EDX = 1 << 3,
ESI = 1 << 4,
EDI = 1 << 5,
EBP = 1 << 6,
END = 0
enum {
X86_FLAG_CARRY = 1 << 0,
X86_FLAG_PARITY = 1 << 2,
X86_FLAG_ADJUST = 1 << 4,
X86_FLAG_ZERO = 1 << 6,
X86_FLAG_SIGN = 1 << 7,
};
void addhook(int address, int newaddress, int stacksize, int registerargs[], int registersreturned, int eaxDestinationRegister);
typedef uint8 (hook_function)(registers *regs);
void addhook(uintptr_t address, hook_function *function);
#endif

View File

@@ -29,47 +29,46 @@ static uint8 _callCount = 0;
static function_call _calls[256] = {0};
namespace PaintIntercept {
static uint32 InterceptWoodenASupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp);
static uint32 InterceptWoodenBSupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp);
static uint32 InterceptMetalASupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp);
static uint32 InterceptMetalBSupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp);
static uint32 InterceptPaint6C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp);
static uint32 InterceptPaint7C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp);
static uint32 InterceptPaint8C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp);
static uint32 InterceptPaint9C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp);
static uint32 InterceptPaintFull(uint8 function, uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp);
static uint8 InterceptWoodenASupports(registers *regs);
static uint8 InterceptWoodenBSupports(registers *regs);
static uint8 InterceptMetalASupports(registers *regs);
static uint8 InterceptMetalBSupports(registers *regs);
static uint8 InterceptPaint6C(registers *regs);
static uint8 InterceptPaint7C(registers *regs);
static uint8 InterceptPaint8C(registers *regs);
static uint8 InterceptPaint9C(registers *regs);
static uint8 InterceptPaintFull(uint8 function, registers *regs);
bool PaintMetalSupports(uint8 function, int supportType, uint8 segment, int special, int height, uint32 imageColourFlags);
bool PaintWoodenSupports(uint8 function, int supportType, int special, int height, uint32 imageColourFlags, bool *underground);
static void CheckSegmentSupportHeight();
void InitHooks() {
int supportsRegisterArgs[] = {EAX, EBX, EDX, EDI, EBP, END};
addhook(0x006629BC, (int) InterceptWoodenASupports, 0, supportsRegisterArgs, 0, EAX);
addhook(0x00662D5C, (int) InterceptWoodenBSupports, 0, supportsRegisterArgs, 0, EAX);
addhook(0x006629BC, InterceptWoodenASupports);
addhook(0x00662D5C, InterceptWoodenBSupports);
addhook(0x00663105, (int) InterceptMetalASupports, 0, supportsRegisterArgs, 0, EAX);
addhook(0x00663584, (int) InterceptMetalBSupports, 0, supportsRegisterArgs, 0, EAX);
addhook(0x00663105, InterceptMetalASupports);
addhook(0x00663584, InterceptMetalBSupports);
int paintRegisterArgs[] = {EAX, EBX, ECX, EDX, ESI, EDI, EBP, END};
addhook(0x006861AC, (int) InterceptPaint6C, 0, paintRegisterArgs, 0, EBP);
addhook(0x00686337, (int) InterceptPaint6C, 0, paintRegisterArgs, 0, EBP);
addhook(0x006864D0, (int) InterceptPaint6C, 0, paintRegisterArgs, 0, EBP);
addhook(0x0068666B, (int) InterceptPaint6C, 0, paintRegisterArgs, 0, EBP);
addhook(0x006861AC, InterceptPaint6C);
addhook(0x00686337, InterceptPaint6C);
addhook(0x006864D0, InterceptPaint6C);
addhook(0x0068666B, InterceptPaint6C);
addhook(0x00686806, (int) InterceptPaint7C, 0, paintRegisterArgs, 0, EBP);
addhook(0x006869B2, (int) InterceptPaint7C, 0, paintRegisterArgs, 0, EBP);
addhook(0x00686B6F, (int) InterceptPaint7C, 0, paintRegisterArgs, 0, EBP);
addhook(0x00686D31, (int) InterceptPaint7C, 0, paintRegisterArgs, 0, EBP);
addhook(0x00686806, InterceptPaint7C);
addhook(0x006869B2, InterceptPaint7C);
addhook(0x00686B6F, InterceptPaint7C);
addhook(0x00686D31, InterceptPaint7C);
addhook(0x00686EF0, (int) InterceptPaint8C, 0, paintRegisterArgs, 0, EBP);
addhook(0x00687056, (int) InterceptPaint8C, 0, paintRegisterArgs, 0, EBP);
addhook(0x006871C8, (int) InterceptPaint8C, 0, paintRegisterArgs, 0, EBP);
addhook(0x0068733C, (int) InterceptPaint8C, 0, paintRegisterArgs, 0, EBP);
addhook(0x00686EF0, InterceptPaint8C);
addhook(0x00687056, InterceptPaint8C);
addhook(0x006871C8, InterceptPaint8C);
addhook(0x0068733C, InterceptPaint8C);
addhook(0x006874B0, (int) InterceptPaint9C, 0, paintRegisterArgs, 0, EBP);
addhook(0x00687618, (int) InterceptPaint9C, 0, paintRegisterArgs, 0, EBP);
addhook(0x0068778C, (int) InterceptPaint9C, 0, paintRegisterArgs, 0, EBP);
addhook(0x00687902, (int) InterceptPaint9C, 0, paintRegisterArgs, 0, EBP);
addhook(0x006874B0, InterceptPaint9C);
addhook(0x00687618, InterceptPaint9C);
addhook(0x0068778C, InterceptPaint9C);
addhook(0x00687902, InterceptPaint9C);
}
bool PaintWoodenSupports(uint8 function, int supportType, int special, int height, uint32 imageColourFlags, bool *underground) {
@@ -110,7 +109,7 @@ namespace PaintIntercept {
sint16 zOffset,
uint32 rotation
) {
function_call call = {0};
function_call call = _calls[_callCount];
call.function = PAINT_98196C;
call.paint.image_id = imageID;
call.paint.offset = {xOffset, yOffset};
@@ -133,7 +132,7 @@ namespace PaintIntercept {
sint16 boundBoxOffsetX, sint16 boundBoxOffsetY, sint16 boundBoxOffsetZ,
uint32 rotation
) {
function_call call = {0};
function_call call = _calls[_callCount];
call.function = function;
call.paint.image_id = imageID;
call.paint.offset = {xOffset, yOffset};
@@ -162,16 +161,18 @@ namespace PaintIntercept {
_woodenSupports = enabled;
}
static uint32 InterceptMetalASupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp) {
bool output = PaintMetalSupports(SUPPORTS_METAL_A, edi, ebx, (sint16) (eax & 0xFFFF), (edx & 0xFFFF), ebp);
static uint8 InterceptMetalASupports(registers *regs)
{
bool output = PaintMetalSupports(SUPPORTS_METAL_A, regs->edi, regs->ebx, (sint16) regs->ax, regs->dx, regs->ebp);
return output ? 1 : 0;
return output ? X86_FLAG_CARRY : 0;
}
static uint32 InterceptMetalBSupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp) {
bool output = PaintMetalSupports(SUPPORTS_METAL_B, edi, ebx, (sint16) (eax & 0xFFFF), (edx & 0xFFFF), ebp);
static uint8 InterceptMetalBSupports(registers *regs)
{
bool output = PaintMetalSupports(SUPPORTS_METAL_B, regs->edi, regs->ebx, (sint16) regs->ax, regs->dx, regs->ebp);
return output ? 1 : 0;
return output ? X86_FLAG_CARRY : 0;
}
static void CheckSegmentSupportHeight() {
@@ -192,47 +193,75 @@ namespace PaintIntercept {
_callCount++;
}
static uint32 InterceptWoodenASupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp) {
bool output = PaintWoodenSupports(SUPPORTS_WOOD_A, edi, eax & 0xFFFF, edx & 0xFFFF, ebp, nullptr);
static uint8 InterceptWoodenASupports(registers *regs)
{
bool cf = false;
regs->al = PaintWoodenSupports(SUPPORTS_WOOD_A, regs->edi, regs->ax, regs->dx, regs->ebp, &cf);
return output ? 1 : 0;
if (cf)
{
return X86_FLAG_CARRY;
}
return 0;
}
static uint32 InterceptWoodenBSupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp) {
bool output = PaintWoodenSupports(SUPPORTS_WOOD_B, edi, eax & 0xFFFF, edx & 0xFFFF, ebp, nullptr);
static uint8 InterceptWoodenBSupports(registers *regs)
{
bool cf = false;
regs->al = PaintWoodenSupports(SUPPORTS_WOOD_B, regs->edi, regs->ax, regs->dx, regs->ebp, &cf);
return output ? 1 : 0;
if (cf)
{
return X86_FLAG_CARRY;
}
return 0;
}
static uint32 InterceptPaint6C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp) {
if ((ebp & 0x03) != get_current_rotation()) {
static uint8 InterceptPaint6C(registers *regs)
{
if ((regs->ebp & 0x03) != get_current_rotation())
{
// Log error
log_error("Ebp is different from current rotation");
}
return (uintptr_t) Paint6C(
ebx,
(sint8) (eax & 0xFF), (sint8) (ecx & 0xFF),
(sint16) (edi & 0xFFFF), (sint16) (esi & 0xFFFF), (sint8) ((eax >> 8) & 0xFF),
edx & 0xFFFF,
ebp & 0x03
paint_struct *out = Paint6C(
regs->ebx,
(sint8) regs->al, (sint8) regs->cl,
(sint16) regs->di, (sint16) regs->si, (sint8) regs->ah,
regs->dx,
regs->ebp & 0x03
);
if (out == nullptr)
{
return X86_FLAG_CARRY;
}
regs->ebp = (int) out;
regs->al = 1;
return 0;
}
static uint32 InterceptPaint7C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp) {
return InterceptPaintFull(PAINT_98197C, eax, ebx, ecx, edx, esi, edi, ebp);
static uint8 InterceptPaint7C(registers *regs)
{
return InterceptPaintFull(PAINT_98197C, regs);
}
static uint32 InterceptPaint8C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp) {
return InterceptPaintFull(PAINT_98198C, eax, ebx, ecx, edx, esi, edi, ebp);
static uint8 InterceptPaint8C(registers *regs)
{
return InterceptPaintFull(PAINT_98198C, regs);
}
static uint32 InterceptPaint9C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp) {
return InterceptPaintFull(PAINT_98199C, eax, ebx, ecx, edx, esi, edi, ebp);
static uint8 InterceptPaint9C(registers *regs)
{
return InterceptPaintFull(PAINT_98199C, regs);
}
static uint32 InterceptPaintFull(uint8 function, uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp) {
if ((ebp & 0x03) != get_current_rotation()) {
static uint8 InterceptPaintFull(uint8 function, registers *regs) {
if ((regs->ebp & 0x03) != get_current_rotation()) {
// Log error
log_error("Ebp is different from current rotation");
}
@@ -243,15 +272,23 @@ namespace PaintIntercept {
RCT2_GLOBAL(RCT2_ADDRESS_PAINT_BOUNDBOX_OFFSET_Z, sint16)
};
return (uintptr_t) PaintFull(
paint_struct *out = PaintFull(
function,
ebx,
(sint8) (eax & 0xFF), (sint8) (ecx & 0xFF),
(sint16) (edi & 0xFFFF), (sint16) (esi & 0xFFFF), (sint8) ((eax >> 8) & 0xFF),
edx & 0xFFFF,
regs->ebx,
(sint8) regs->al, (sint8) regs->cl,
(sint16) regs->di, (sint16) regs->si, (sint8) regs->ah,
regs->dx,
boundOffset.x, boundOffset.y, boundOffset.z,
ebp & 0x03
regs->ebp & 0x03
);
if (out == nullptr)
{
return X86_FLAG_CARRY;
}
regs->ebp = (int) out;
return 0;
}
};