diff options
Diffstat (limited to 'src/emu/x64run.c')
| -rw-r--r-- | src/emu/x64run.c | 468 |
1 files changed, 370 insertions, 98 deletions
diff --git a/src/emu/x64run.c b/src/emu/x64run.c index f064dfd1..6465ab5e 100644 --- a/src/emu/x64run.c +++ b/src/emu/x64run.c @@ -49,9 +49,10 @@ int Run(x64emu_t *emu, int step) int step = 0; #endif uintptr_t addr = R_RIP; - rex_t rex; + rex_t rex = {0}; int rep; // 0 none, 1=F2 prefix, 2=F3 prefix int unimp = 0; + int is32bits = (emu->segs[_CS]==0x23); if(emu->quit) return 0; @@ -62,7 +63,7 @@ int Run(x64emu_t *emu, int step) return 0; } //ref opcode: http://ref.x64asm.net/geek32.html#xA1 - printf_log(LOG_DEBUG, "Run X86 (%p), RIP=%p, Stack=%p\n", emu, (void*)addr, (void*)R_RSP); + printf_log(LOG_DEBUG, "Run X86 (%p), RIP=%p, Stack=%p is32bits=%d\n", emu, (void*)addr, (void*)R_RSP, is32bits); x64emurun: #ifndef TEST_INTERPRETER @@ -86,13 +87,15 @@ x64emurun: rep = opcode-0xF1; opcode = F8; } - while((opcode==0x3E)) //Branch Taken Hint ignored + while((opcode==0x3E) || (opcode==0x26)) //Branch Taken Hint ignored opcode = F8; rex.rex = 0; - while(opcode>=0x40 && opcode<=0x4f) { - rex.rex = opcode; - opcode = F8; - } + rex.is32bits = is32bits; + if(!is32bits) + while(opcode>=0x40 && opcode<=0x4f) { + rex.rex = opcode; + opcode = F8; + } switch(opcode) { @@ -142,6 +145,21 @@ x64emurun: break; GO(0x00, add) /* ADD 0x00 -> 0x05 */ + case 0x06: /* PUSH ES */ + if(!rex.is32bits) { + unimp = 1; + goto fini; + } + Push32(emu, emu->segs[_ES]); // even if a segment is a 16bits, a 32bits push/pop is done + break; + case 0x07: /* POP ES */ + if(!rex.is32bits) { + unimp = 1; + goto fini; + } + emu->segs[_ES] = Pop32(emu); // no check, no use.... + emu->segs_serial[_ES] = 0; + break; GO(0x08, or) /* OR 0x08 -> 0x0D */ case 0x0F: /* More instructions */ switch(rep) { @@ -193,7 +211,24 @@ x64emurun: GO(0x30, xor) /* XOR 0x30 -> 0x35 */ #undef GO + case 0x1E: /* PUSH DS */ + if(!rex.is32bits) { + unimp = 1; + goto fini; + } + Push32(emu, emu->segs[_DS]); // even if a segment is a 16bits, a 32bits push/pop is done + break; + case 0x1F: /* POP DS */ + if(!rex.is32bits) { + unimp = 1; + goto fini; + } + emu->segs[_DS] = Pop32(emu); // no check, no use.... + emu->segs_serial[_DS] = 0; + break; + case 0x2E: /* segments are ignored */ + case 0x26: case 0x36: /* SS: (ignored) */ break; @@ -236,13 +271,39 @@ x64emurun: else cmp32(emu, R_EAX, F32); break; - + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: /* INC Reg (32bits only)*/ + tmp8u = opcode&7; + emu->regs[tmp8u].dword[0] = inc32(emu, emu->regs[tmp8u].dword[0]); + break; + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: /* DEC Reg (32bits only)*/ + tmp8u = opcode&7; + emu->regs[tmp8u].dword[0] = dec32(emu, emu->regs[tmp8u].dword[0]); + break; case 0x54: /* PUSH ESP */ if(rex.b) - Push(emu, R_R12); + Push64(emu, R_R12); else { - tmp64u = R_RSP; - Push(emu, tmp64u); + if(rex.is32bits) { + tmp32u = R_ESP; + Push32(emu, tmp32u); + } else { + tmp64u = R_RSP; + Push64(emu, tmp64u); + } } break; case 0x50: @@ -253,7 +314,10 @@ x64emurun: case 0x56: case 0x57: /* PUSH Reg */ tmp8u = (opcode&7)+(rex.b<<3); - Push(emu, emu->regs[tmp8u].q[0]); + if(rex.is32bits) + Push32(emu, emu->regs[tmp8u].dword[0]); + else + Push64(emu, emu->regs[tmp8u].q[0]); break; case 0x58: case 0x59: @@ -264,20 +328,57 @@ x64emurun: case 0x5E: case 0x5F: /* POP Reg */ tmp8u = (opcode&7)+(rex.b<<3); - emu->regs[tmp8u].q[0] = Pop(emu); + emu->regs[tmp8u].q[0] = is32bits?Pop32(emu):Pop64(emu); + break; + case 0x60: /* PUSHAD */ + if(rex.is32bits) { + tmp32u = R_ESP; + Push32(emu, R_EAX); + Push32(emu, R_ECX); + Push32(emu, R_EDX); + Push32(emu, R_EBX); + Push32(emu, tmp32u); + Push32(emu, R_EBP); + Push32(emu, R_ESI); + Push32(emu, R_EDI); + } else { + unimp = 1; + goto fini; + } + break; + case 0x61: /* POPAD */ + if(rex.is32bits) { + R_EDI = Pop32(emu); + R_ESI = Pop32(emu); + R_EBP = Pop32(emu); + R_ESP+=4; // POP ESP + R_EBX = Pop32(emu); + R_EDX = Pop32(emu); + R_ECX = Pop32(emu); + R_EAX = Pop32(emu); + } else { + unimp = 1; + goto fini; + } break; case 0x63: /* MOVSXD Gd,Ed */ nextop = F8; GETED(0); GETGD; - if(rex.w) - GD->sq[0] = ED->sdword[0]; - else - if(MODREG) - GD->q[0] = ED->dword[0]; // not really a sign extension + if(rex.is32bits) { + // ARPL here + // faking to always happy... + SET_FLAG(F_ZF); + } else { + if(rex.w) + GD->sq[0] = ED->sdword[0]; else - GD->sdword[0] = ED->sdword[0]; // meh? + if(MODREG) + GD->q[0] = ED->dword[0]; // not really a sign extension + else + GD->sdword[0] = ED->sdword[0]; // meh? + } break; case 0x64: /* FS: prefix */ #ifdef TEST_INTERPRETER @@ -292,6 +393,7 @@ x64emurun: R_RIP = addr; goto fini; } + is32bits = (emu->segs[_CS]==0x23); #endif break; case 0x65: /* GS: prefix */ @@ -307,6 +409,7 @@ x64emurun: R_RIP = addr; goto fini; } + is32bits = (emu->segs[_CS]==0x23); #endif break; case 0x66: /* 16bits prefix */ @@ -340,7 +443,10 @@ x64emurun: #endif break; case 0x68: /* Push Id */ - Push(emu, F32S64); + if(rex.is32bits) + Push32(emu, F32); + else + Push64(emu, F32S64); break; case 0x69: /* IMUL Gd,Ed,Id */ nextop = F8; @@ -353,8 +459,13 @@ x64emurun: GD->q[0] = imul32(emu, ED->dword[0], tmp64u); break; case 0x6A: /* Push Ib */ - tmp64s = F8S; - Push(emu, (uint64_t)tmp64s); + if(rex.is32bits) { + tmp32s = F8S; + Push32(emu, (uint32_t)tmp32s); + } else { + tmp64s = F8S; + Push64(emu, (uint64_t)tmp64s); + } break; case 0x6B: /* IMUL Gd,Ed,Ib */ nextop = F8; @@ -367,14 +478,78 @@ x64emurun: GD->q[0] = imul32(emu, ED->dword[0], (uint32_t)tmp64s); break; case 0x6C: /* INSB DX */ + if(rex.is32bits) { + tmp32u = rep?R_ECX:1; + while(tmp32u--) { + *(int8_t*)(R_EDI+GetESBaseEmu(emu)) = 0; // faking port read, using explicit ES segment + if(ACCESS_FLAG(F_DF)) + R_EDI-=1; + else + R_EDI+=1; + } + if(rep) + R_ECX = 0; + } else { + // this is a privilege opcode in 64bits, but not in 32bits... + #ifndef TEST_INTERPRETOR + emit_signal(emu, SIGSEGV, (void*)R_RIP, 0); + STEP; + #endif + } + break; case 0x6D: /* INSL DX */ + if(rex.is32bits) { + tmp32u = rep?R_ECX:1; + while(tmp32u--) { + *(int32_t*)(R_EDI+GetESBaseEmu(emu)) = 0; // faking port read, using explicit ES segment + if(ACCESS_FLAG(F_DF)) + R_EDI-=4; + else + R_EDI+=4; + } + if(rep) + R_ECX = 0; + } else { + // this is a privilege opcode in 64bits, but not in 32bits... + #ifndef TEST_INTERPRETOR + emit_signal(emu, SIGSEGV, (void*)R_RIP, 0); + STEP; + #endif + } + break; case 0x6E: /* OUTSB DX */ + if(rex.is32bits) { + // faking port write, using explicit ES segment + if(ACCESS_FLAG(F_DF)) + R_ESI-=rep?R_ECX:1; + else + R_ESI+=1?R_ECX:1; + if(rep) + R_ECX = 0; + } else { + // this is a privilege opcode in 64bits, but not in 32bits... + #ifndef TEST_INTERPRETOR + emit_signal(emu, SIGSEGV, (void*)R_RIP, 0); + STEP; + #endif + } + break; case 0x6F: /* OUTSL DX */ - // this is a privilege opcode... - #ifndef TEST_INTERPRETOR - emit_signal(emu, SIGSEGV, (void*)R_RIP, 0); - STEP; - #endif + if(rex.is32bits) { + // faking port write, using explicit ES segment + if(ACCESS_FLAG(F_DF)) + R_ESI-=(rep?R_ECX:1)*4; + else + R_ESI+=(rep?R_ECX:1)*4; + if(rep) + R_ECX = 0; + } else { + // this is a privilege opcode in 64bits, but not in 32bits... + #ifndef TEST_INTERPRETOR + emit_signal(emu, SIGSEGV, (void*)R_RIP, 0); + STEP; + #endif + } break; GOCOND(0x70 @@ -383,6 +558,12 @@ x64emurun: ,,STEP2 ) /* Jxx Ib */ + case 0x82: + if(!rex.is32bits) { + unimp = 1; + goto fini; + } + // fallthru case 0x80: /* GRP Eb,Ib */ nextop = F8; GETEB(1); @@ -581,17 +762,30 @@ x64emurun: else GD->q[0] = tmp64u&0xffffffff; break; - + case 0x8E: /* MOV Seg, Ew */ + nextop = F8; + GETED(0); + emu->segs[((nextop&0x38)>>3)] = ED->word[0]; + emu->segs_serial[((nextop&0x38)>>3)] = 0; + break; case 0x8F: /* POP Ed */ nextop = F8; if(MODREG) { - emu->regs[(nextop&7)+(rex.b<<3)].q[0] = Pop(emu); + emu->regs[(nextop&7)+(rex.b<<3)].q[0] = rex.is32bits?Pop32(emu):Pop64(emu); } else { - tmp64u = Pop(emu); // this order allows handling POP [ESP] and variant - GETED(0); - R_ESP -= sizeof(void*); // to prevent issue with SEGFAULT - ED->q[0] = tmp64u; - R_ESP += sizeof(void*); + if(rex.is32bits) { + tmp32u = Pop32(emu); // this order allows handling POP [ESP] and variant + GETED(0); + R_ESP -= 4; // to prevent issue with SEGFAULT + ED->dword[0] = tmp32u; + R_ESP += 4; + } else { + tmp64u = Pop64(emu); // this order allows handling POP [ESP] and variant + GETED(0); + R_RSP -= sizeof(void*); // to prevent issue with SEGFAULT + ED->q[0] = tmp64u; + R_RSP += sizeof(void*); + } } break; case 0x90: /* NOP or XCHG R8, RAX*/ @@ -635,11 +829,23 @@ x64emurun: break; case 0x9C: /* PUSHF */ CHECK_FLAGS(emu); - Push(emu, emu->eflags.x64); + if(rex.is32bits) + Push32(emu, emu->eflags.x64); + else + Push64(emu, emu->eflags.x64); break; case 0x9D: /* POPF */ - emu->eflags.x64 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1 + emu->eflags.x64 = (((rex.is32bits?Pop32(emu):Pop64(emu)) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1 RESET_FLAGS(emu); + #ifndef TEST_INTERPRETER + if(ACCESS_FLAG(F_TF)) { + R_RIP = addr; + emit_signal(emu, SIGTRAP, (void*)addr, 1); + if(emu->quit) goto fini; + CLEAR_FLAG(F_TF); + STEP; + } + #endif break; case 0x9E: /* SAHF */ CHECK_FLAGS(emu); @@ -656,22 +862,36 @@ x64emurun: R_AH = (uint8_t)emu->eflags.x64; break; case 0xA0: /* MOV AL,Ob */ - R_AL = *(uint8_t*)F64; + if(rex.is32bits) + R_AL = *(uint8_t*)(uintptr_t)F32; + else + R_AL = *(uint8_t*)F64; break; case 0xA1: /* MOV EAX,Od */ - if(rex.w) - R_RAX = *(uint64_t*)F64; - else - R_RAX = *(uint32_t*)F64; + if(rex.is32bits) + R_EAX = *(int32_t*)(uintptr_t)F32; + else { + if(rex.w) + R_RAX = *(uint64_t*)F64; + else + R_RAX = *(uint32_t*)F64; + } break; case 0xA2: /* MOV Ob,AL */ - *(uint8_t*)F64 = R_AL; + if(rex.is32bits) + *(uint8_t*)(uintptr_t)F32 = R_AL; + else + *(uint8_t*)F64 = R_AL; break; case 0xA3: /* MOV Od,EAX */ - if(rex.w) - *(uint64_t*)F64 = R_RAX; - else - *(uint32_t*)F64 = R_EAX; + if(rex.is32bits) + *(uint32_t*)(uintptr_t)F32 = R_EAX; + else { + if(rex.w) + *(uint64_t*)F64 = R_RAX; + else + *(uint32_t*)F64 = R_EAX; + } break; case 0xA4: /* MOVSB */ tmp8s = ACCESS_FLAG(F_DF)?-1:+1; @@ -746,7 +966,6 @@ x64emurun: R_RCX = tmp64u; break; default: - tmp8s = ACCESS_FLAG(F_DF)?-1:+1; tmp8u = *(uint8_t*)R_RDI; tmp8u2 = *(uint8_t*)R_RSI; R_RDI += tmp8s; @@ -816,14 +1035,12 @@ x64emurun: break; default: if(rex.w) { - tmp8s = ACCESS_FLAG(F_DF)?-8:+8; tmp64u = *(uint64_t*)R_RDI; tmp64u2 = *(uint64_t*)R_RSI; R_RDI += tmp8s; R_RSI += tmp8s; cmp64(emu, tmp64u2, tmp64u); } else { - tmp8s = ACCESS_FLAG(F_DF)?-4:+4; tmp32u = *(uint32_t*)R_RDI; tmp32u2 = *(uint32_t*)R_RSI; R_RDI += tmp8s; @@ -1090,12 +1307,12 @@ x64emurun: break; case 0xC2: /* RETN Iw */ tmp16u = F16; - addr = Pop(emu); + addr = rex.is32bits?Pop32(emu):Pop64(emu); R_RSP += tmp16u; STEP2 break; case 0xC3: /* RET */ - addr = Pop(emu); + addr = rex.is32bits?Pop32(emu):Pop64(emu); STEP2 break; @@ -1118,21 +1335,34 @@ x64emurun: case 0xC8: /* ENTER Iw,Ib */ tmp16u = F16; tmp8u = (F8) & 0x1f; - tmp64u = R_RBP; - Push(emu, R_RBP); - R_RBP = R_RSP; - if (tmp8u) { - for (tmp8u2 = 1; tmp8u2 < tmp8u; tmp8u2++) { - tmp64u -= sizeof(void*); - Push(emu, *((uintptr_t*)tmp64u)); + if(rex.is32bits) { + tmp64u = R_EBP; + Push32(emu, R_EBP); + R_EBP = R_ESP; + if (tmp8u) { + for (tmp8u2 = 1; tmp8u2 < tmp8u; tmp8u2++) { + tmp64u -= 4; + Push32(emu, *((uint32_t*)tmp64u)); + } + Push32(emu, R_EBP); + } + } else { + tmp64u = R_RBP; + Push64(emu, R_RBP); + R_RBP = R_RSP; + if (tmp8u) { + for (tmp8u2 = 1; tmp8u2 < tmp8u; tmp8u2++) { + tmp64u -= sizeof(void*); + Push64(emu, *((uintptr_t*)tmp64u)); + } + Push64(emu, R_RBP); } - Push(emu, R_RBP); } R_RSP -= tmp16u; break; case 0xC9: /* LEAVE */ R_RSP = R_RBP; - R_RBP = Pop(emu); + R_RBP = rex.is32bits?Pop32(emu):Pop64(emu); break; case 0xCC: /* INT 3 */ @@ -1143,26 +1373,44 @@ x64emurun: #endif break; case 0xCD: /* INT n */ + tmp8u = F8; // this is a privilege opcode... - #ifndef TEST_INTERPRETER - emit_signal(emu, SIGSEGV, (void*)R_RIP, 0); - STEP; - #endif + if(box64_wine && tmp8u==0x2D) { + // lets ignore the INT 2D + printf_log(LOG_DEBUG, "INT 2D called\n"); + } else if(box64_wine && tmp8u==0x29) { + // INT 29 is __fastfail + printf_log(LOG_DEBUG, "INT 29 called => __fastfail(0x%x)\n", R_ECX); + emu->quit = 1; + R_RIP = addr; + goto fini; + } else if (tmp8u==0x80) { + // 32bits syscall + #ifndef TEST_INTERPRETER + x86Syscall(emu); + STEP; + #endif + } else { + #ifndef TEST_INTERPRETER + emit_signal(emu, SIGSEGV, (void*)R_RIP, 0); + STEP; + #endif + } break; - case 0xCF: /* IRET */ - addr = Pop(emu); - emu->segs[_CS] = Pop(emu)&0xffff; + addr = rex.is32bits?Pop32(emu):Pop64(emu); + emu->segs[_CS] = (rex.is32bits?Pop32(emu):Pop64(emu))&0xffff; emu->segs_serial[_CS] = 0; - emu->eflags.x64 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1 - tmp64u = Pop(emu); //RSP - emu->segs[_SS] = Pop(emu)&0xffff; + emu->eflags.x64 = (((rex.is32bits?Pop32(emu):Pop64(emu)) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1 + tmp64u = rex.is32bits?Pop32(emu):Pop64(emu); //RSP + emu->segs[_SS] = (rex.is32bits?Pop32(emu):Pop64(emu))&0xffff; emu->segs_serial[_SS] = 0; - R_RSP= tmp64u; + R_RSP = tmp64u; RESET_FLAGS(emu); R_RIP = addr; - goto fini; // exit, to recompute CS if needed + STEP; + is32bits = (emu->segs[_CS]==0x23); break; case 0xD0: /* GRP2 Eb,1 */ case 0xD2: /* GRP2 Eb,CL */ @@ -1386,13 +1634,17 @@ x64emurun: break; case 0xE8: /* CALL Id */ tmp32s = F32S; // call is relative - Push(emu, addr); + if(rex.is32bits) + Push32(emu, addr); + else + Push64(emu, addr); addr += tmp32s; STEP2 break; case 0xE9: /* JMP Id */ tmp32s = F32S; // jmp is relative addr += tmp32s; + addr = (uintptr_t)getAlternate((void*)addr); STEP2 break; @@ -1549,12 +1801,12 @@ x64emurun: SET_FLAG(F_CF); break; case 0xFA: /* CLI */ - // this is a privilege opcode... + // this is a privilege opcode emit_signal(emu, SIGSEGV, (void*)R_RIP, 0); STEP; break; case 0xFB: /* STI */ - // this is a privilege opcode... + // this is a privilege opcode emit_signal(emu, SIGSEGV, (void*)R_RIP, 0); STEP; break; @@ -1606,8 +1858,13 @@ x64emurun: break; case 2: /* CALL NEAR Ed */ GETE8(0); - tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]); - Push(emu, addr); + if(rex.is32bits) { + tmp64u = (uintptr_t)ED->dword[0]; + Push32(emu, addr); + } else { + tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]); + Push64(emu, addr); + } addr = tmp64u; STEP2 break; @@ -1619,16 +1876,27 @@ x64emurun: emu->error |= ERR_ILLEGAL; goto fini; } else { - Push(emu, R_CS); - Push(emu, addr); - R_RIP = addr = (uintptr_t)getAlternate((void*)ED->q[0]); // check CS? - R_CS = (ED+1)->word[0]; - goto fini; // exit loop to recompute new CS... + if(rex.is32bits || !rex.w) { + Push32(emu, R_CS); + Push32(emu, addr); + addr = (uintptr_t)getAlternate((void*)(uintptr_t)ED->dword[0]); + R_CS = ED->word[2]; + } else { + Push64(emu, R_CS); + Push64(emu, addr); + addr = (uintptr_t)getAlternate((void*)ED->q[0]); + R_CS = (ED+1)->word[0]; + } + STEP2; + is32bits = (emu->segs[_CS]==0x23); } break; case 4: /* JMP NEAR Ed */ GETE8(0); - addr = (uintptr_t)getAlternate((void*)ED->q[0]); + if(rex.is32bits) + addr = (uintptr_t)ED->dword[0]; + else + addr = (uintptr_t)getAlternate((void*)ED->q[0]); STEP2 break; case 5: /* JMP FAR Ed */ @@ -1639,23 +1907,26 @@ x64emurun: emu->error |= ERR_ILLEGAL; goto fini; } else { - R_RIP = (uintptr_t)getAlternate((void*)ED->q[0]); //check CS? - R_CS = (ED+1)->word[0]; - goto fini; // exit loop to recompute CS... + if(rex.is32bits || !rex.w) { + addr = (uintptr_t)getAlternate((void*)(uintptr_t)ED->dword[0]); + R_CS = ED->word[2]; + } else { + addr = (uintptr_t)getAlternate((void*)ED->q[0]); + R_CS = (ED+1)->word[0]; + } + STEP2; + is32bits = (emu->segs[_CS]==0x23); } break; case 6: /* Push Ed */ - GETE8(0); - tmp64u = ED->q[0]; // rex.w ignored - #ifdef TEST_INTERPRETER - R_RSP -=8; - if(test->memsize!=8) - *(uint64_t*)test->mem = *(uint64_t*)test->memaddr; - test->memsize = 8; - test->memaddr = R_RSP; - #else - Push(emu, tmp64u); // avoid potential issue with push [esp+...] - #endif + _GETED(0); + if(rex.is32bits) { + tmp32u = ED->dword[0]; + Push32(emu, tmp32u); // avoid potential issue with push [esp+...] + } else { + tmp64u = ED->q[0]; // rex.w ignored + Push64(emu, tmp64u); // avoid potential issue with push [esp+...] + } break; default: printf_log(LOG_NONE, "Illegal Opcode %p: %02X %02X %02X %02X %02X %02X\n",(void*)R_RIP, opcode, nextop, PK(2), PK(3), PK(4), PK(5)); @@ -1673,11 +1944,12 @@ x64emurun: fini: +if(emu->segs[_CS]!=0x33 && emu->segs[_CS]!=0x23) printf_log(LOG_NONE, "Warning, CS is not default value: 0x%x\n", emu->segs[_CS]); #ifndef TEST_INTERPRETER printf_log(LOG_DEBUG, "End of X86 run (%p), RIP=%p, Stack=%p, unimp=%d, emu->fork=%d, emu->uc_link=%p, emu->quit=%d\n", emu, (void*)R_RIP, (void*)R_RSP, unimp, emu->fork, emu->uc_link, emu->quit); if(unimp) { emu->quit = 1; - UnimpOpcode(emu); + UnimpOpcode(emu, is32bits); } // fork handling if(emu->fork) { |