dvander@157: #include dvander@157: #include dvander@157: #include dvander@157: #include "jit_x86.h" dvander@157: #include "opcode_helpers.h" dvander@157: #include "x86_macros.h" dvander@157: dvander@157: #define NUM_INFO_PARAMS 5 dvander@157: dvander@157: jitoffs_t Write_Execute_Function(JitWriter *jit) dvander@157: { dvander@157: /** dvander@157: * The variables we're passed in: dvander@157: * sp_context_t *ctx, uint32_t code_idx, cell_t *result dvander@157: */ dvander@157: dvander@157: /** dvander@157: * !NOTE! dvander@157: * Currently, we do not accept ctx->frm as the new frame pointer. dvander@157: * Instead, we copy the frame from the stack pointer. dvander@157: * This is because we do not support resuming or sleeping! dvander@157: */ dvander@157: dvander@157: //push ebp dvander@157: //mov ebp, esp dvander@157: IA32_Push_Reg(jit, REG_EBP); dvander@157: IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG); dvander@157: dvander@157: //push esi dvander@157: //push edi dvander@157: //push ebx dvander@157: IA32_Push_Reg(jit, REG_ESI); dvander@157: IA32_Push_Reg(jit, REG_EDI); dvander@157: IA32_Push_Reg(jit, REG_EBX); dvander@157: dvander@157: //sub esp, 4*n - reserve info array dvander@157: //mov esi, esp - save info pointer dvander@157: IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG); dvander@157: IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG); dvander@157: dvander@157: /* Initial memory setup */ dvander@157: //mov eax, [ebp+16] - get result pointer dvander@157: //mov [esi+8], eax - store into info pointer dvander@157: //mov eax, [ebp+8] - get context dvander@157: //mov [esi+12], eax - store context into info pointer dvander@157: //mov ecx, [eax+] - get heap pointer dvander@157: //mov [esi+4], ecx - store heap into info pointer dvander@157: //mov ebp, [eax+] - get data pointer dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_RETVAL); dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_CONTEXT); dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp)); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAP); dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, memory)); dvander@157: dvander@157: /* Frame setup */ dvander@157: //mov edi, [eax+] - get stack pointer dvander@157: //add edi, ebp - relocate to data section dvander@157: //mov ebx, edi - copy sp to frm dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp)); dvander@157: IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); dvander@157: IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG); dvander@157: dvander@157: /* Info memory setup */ dvander@157: //mov ecx, [eax+] - copy memsize to temp var dvander@157: //add ecx, ebp - relocate dvander@157: //mov [esi+x], ecx - store relocated dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory)); dvander@157: IA32_Add_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP); dvander@157: dvander@157: /* Remaining needed vars */ dvander@157: //mov ecx, [esp+(4*(NUM_INFO_PARAMS+3))+12] - get code index (normally esp+12, but we have another array on the stack) dvander@157: //add ecx, [eax+] - add code base to index dvander@157: IA32_Mov_Reg_Esp_Disp8(jit, REG_ECX, 12+(4*(NUM_INFO_PARAMS+3))); dvander@157: IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, codebase)); dvander@157: dvander@157: /* by now, everything is set up, so we can call into the plugin */ dvander@157: //call ecx dvander@157: IA32_Call_Reg(jit, REG_ECX); dvander@157: dvander@157: /* if the code flow gets to here, there was a normal return */ dvander@157: //mov ecx, [esi+8] - get retval pointer dvander@157: //mov [ecx], eax - store retval from PRI dvander@157: //mov eax, SP_ERROR_NONE - set no error dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_RETVAL); dvander@157: IA32_Mov_Rm_Reg(jit, REG_ECX, AMX_REG_PRI, MOD_MEM_REG); dvander@157: IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERROR_NONE); dvander@157: dvander@157: /* save where error checking/halting functions should go to */ dvander@157: jitoffs_t offs_return = jit->get_outputpos(); dvander@157: //mov esp, esi - restore stack pointer dvander@157: IA32_Mov_Reg_Rm(jit, REG_ESP, REG_ESI, MOD_REG); dvander@157: dvander@157: /* _FOR NOW_ ... dvander@157: * We are going to restore SP, HP, and FRM for now. This is for dvander@157: * debugging only, to check for alignment errors. As such: dvander@157: * :TODO: probably remove this. dvander@157: */ dvander@157: //mov ecx, [esi+context] dvander@157: //sub edi, ebp dvander@157: //mov edx, [esi+heap] dvander@157: //mov [ecx+sp], edi dvander@157: //mov [ecx+hp], edx dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_ESI, AMX_INFO_CONTEXT); dvander@157: IA32_Sub_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG); dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_ESI, AMX_INFO_HEAP); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDI, offsetof(sp_context_t, sp)); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDX, offsetof(sp_context_t, hp)); dvander@157: dvander@157: //add esp, 4*NUM_INFO_PARAMS dvander@157: //pop ebx dvander@157: //pop edi dvander@157: //pop esi dvander@157: //pop ebp dvander@157: //ret dvander@157: IA32_Add_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG); dvander@157: IA32_Pop_Reg(jit, REG_EBX); dvander@157: IA32_Pop_Reg(jit, REG_EDI); dvander@157: IA32_Pop_Reg(jit, REG_ESI); dvander@157: IA32_Pop_Reg(jit, REG_EBP); dvander@157: IA32_Return(jit); dvander@157: dvander@157: return offs_return; dvander@157: } dvander@157: dvander@157: void Write_BreakDebug(JitWriter *jit) dvander@157: { dvander@241: //push edi dvander@241: //mov edi, ecx dvander@157: //mov ecx, [esi+ctx] dvander@157: //cmp [ecx+dbreak], 0 dvander@157: //jnz :nocall dvander@241: IA32_Push_Reg(jit, REG_EDI); dvander@241: IA32_Mov_Reg_Rm(jit, REG_EDI, REG_ECX, MOD_REG); dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); dvander@157: IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, dbreak), 0); dvander@241: jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_Z, 0); dvander@157: dvander@241: /* NOTE, Hack! PUSHAD pushes EDI last which still has the CIP */ dvander@157: //pushad dvander@157: //push [esi+frm] faluco@238: //push ctx dvander@157: //mov ecx, [ecx+dbreak] dvander@157: //call ecx dvander@157: //add esp, 8 dvander@157: //popad dvander@241: IA32_Pushad(jit); dvander@157: IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0 dvander@237: IA32_Push_Reg(jit, AMX_REG_TMP); dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak)); dvander@157: IA32_Call_Reg(jit, AMX_REG_TMP); dvander@157: IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG); dvander@157: IA32_Popad(jit); dvander@157: dvander@157: //:nocall dvander@241: //pop edi dvander@241: //ret dvander@241: IA32_Pop_Reg(jit, REG_EDI); dvander@157: IA32_Send_Jump8_Here(jit, jmp); dvander@157: IA32_Return(jit); dvander@157: } dvander@157: dvander@157: void Write_GetError(JitWriter *jit) dvander@157: { dvander@157: CompData *data = (CompData *)jit->data; dvander@157: dvander@157: //mov eax, [esi+info.context] dvander@157: //mov eax, [eax+ctx.error] dvander@157: //jmp [jit_return] dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); dvander@237: IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EAX, offsetof(sp_context_t, n_err)); dvander@157: IA32_Jump_Imm32_Abs(jit, data->jit_return); dvander@157: } dvander@157: dvander@157: void Write_SetError(JitWriter *jit, int error) dvander@157: { dvander@157: CompData *data = (CompData *)jit->data; dvander@157: dvander@157: //mov eax, dvander@157: //jmp [jit_return] dvander@157: IA32_Mov_Reg_Imm32(jit, REG_EAX, error); dvander@157: IA32_Jump_Imm32_Abs(jit, data->jit_return); dvander@157: } dvander@157: dvander@157: void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg) dvander@157: { dvander@157: //test reg, reg dvander@157: //jz :error dvander@157: IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG); dvander@157: IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, ((CompData *)jit->data)->jit_error_divzero); dvander@157: } dvander@157: dvander@157: void Write_CheckHeap_Min(JitWriter *jit) dvander@157: { dvander@157: /* Check if the stack went beyond the heap low. dvander@157: * This usually means there was a compiler error. dvander@157: * NOTE: Special optimization here. dvander@157: * The heap low is always known ahead of time! :) dvander@157: */ dvander@157: CompData *data = (CompData *)jit->data; dvander@157: //cmp [esi+info.heap], dvander@157: //jb :error dvander@157: IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, data->plugin->data_size); dvander@157: IA32_Jump_Cond_Imm32_Abs(jit, CC_B, data->jit_error_heapmin); dvander@157: } dvander@157: dvander@157: void Write_CheckHeap_Low(JitWriter *jit) dvander@157: { dvander@157: /* Check if the heap is trying to grow beyond the stack. dvander@157: */ dvander@157: //mov ecx, [esi+info.heap] dvander@157: //lea ecx, [ebp+ecx+STACK_MARGIN] dvander@157: //cmp ecx, edi dvander@157: //ja :error ; I think this is right dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); dvander@157: IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN); dvander@157: IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG); dvander@157: IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_heaplow); dvander@157: } dvander@157: dvander@157: void Write_CheckStack_Min(JitWriter *jit) dvander@157: { dvander@157: /* Check if the stack went beyond the stack top dvander@157: * This usually means there was a compiler error. dvander@157: */ dvander@157: //cmp edi, [esi+info.stacktop] dvander@157: //jae :error dvander@157: IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP); dvander@157: IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_stackmin); dvander@157: } dvander@157: dvander@157: void Write_CheckStack_Low(JitWriter *jit) dvander@157: { dvander@157: /* Check if the stack went beyond the heap boundary. dvander@157: * Unfortunately this one isn't as quick as the other check. dvander@157: * The stack margin check is important for sysreq.n having space. dvander@157: */ dvander@157: //mov ecx, [esi+info.heap] dvander@157: //lea ecx, [ebp+ecx+STACK_MARGIN] dvander@157: //cmp edi, ecx dvander@157: //jb :error ; I think this is right dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); dvander@157: IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN); dvander@157: IA32_Cmp_Reg_Rm(jit, AMX_REG_STK, AMX_REG_TMP, MOD_REG); dvander@157: IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_stacklow); dvander@157: } dvander@157: dvander@157: void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg) dvander@157: { dvander@157: CompData *data = (CompData *)jit->data; dvander@157: dvander@157: /* :TODO: Should this be checking for below heaplow? dvander@157: * The old JIT did not. dvander@157: */ dvander@157: dvander@157: bool call = false; dvander@157: if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) dvander@157: { dvander@157: /* If we're not in the initial generation phase, dvander@157: * Write a call to the actual routine instead. dvander@157: */ dvander@157: if ((reg == REG_EAX) && data->jit_verify_addr_eax) dvander@157: { dvander@157: jitoffs_t call = IA32_Call_Imm32(jit, 0); dvander@157: IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax); dvander@157: return; dvander@157: } else if ((reg == REG_EDX) && data->jit_verify_addr_edx) { dvander@157: jitoffs_t call = IA32_Call_Imm32(jit, 0); dvander@157: IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx); dvander@157: return; dvander@157: } dvander@157: call = true; dvander@157: } dvander@157: dvander@157: /** dvander@157: * :TODO: If we can't find a nicer way of doing this, dvander@157: * then scrap it on high optimizations. The second portion is not needed at all! dvander@157: */ dvander@157: dvander@157: /* Part 1: Check if we're in the memory bounds */ dvander@157: //cmp , dvander@157: //jae :error dvander@157: IA32_Cmp_Rm_Imm32(jit, MOD_REG, reg, ((CompData *)jit->data)->plugin->memory); dvander@157: IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess); dvander@157: dvander@157: /* Part 2: Check if we're in the invalid region between HP and SP */ dvander@157: jitoffs_t jmp; dvander@157: //cmp , [esi+info.heap] dvander@157: //jb :continue dvander@157: //lea ecx, [ebp+] dvander@157: //cmp edi, ecx dvander@157: //jb :error dvander@157: //:continue dvander@157: IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP); dvander@157: jmp = IA32_Jump_Cond_Imm8(jit, CC_B, 0); dvander@157: IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, reg, NOSCALE, 0); dvander@157: IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG); dvander@157: IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_memaccess); dvander@157: IA32_Send_Jump8_Here(jit, jmp); dvander@157: dvander@157: if (call) dvander@157: { dvander@157: IA32_Return(jit); dvander@157: } dvander@157: } dvander@157: dvander@157: void Macro_PushN_Addr(JitWriter *jit, int i) dvander@157: { dvander@157: //push eax dvander@157: //mov eax, [esi+frm] dvander@157: //loop i times: dvander@157: // lea ecx, [eax+] dvander@157: // mov [edi-4*i], ecx dvander@157: //sub edi, 4*N dvander@157: //pop eax dvander@157: dvander@157: cell_t val; dvander@157: int n = 1; dvander@157: IA32_Push_Reg(jit, AMX_REG_PRI); dvander@157: IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG); dvander@157: do dvander@157: { dvander@157: val = jit->read_cell(); dvander@157: if (val < SCHAR_MAX && val > SCHAR_MIN) dvander@157: IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, (jit_int8_t)val); dvander@157: else dvander@157: IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, val); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n); dvander@157: } while (n++ < i); dvander@157: IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG); dvander@157: IA32_Pop_Reg(jit, AMX_REG_PRI); dvander@157: } dvander@157: dvander@157: void Macro_PushN_S(JitWriter *jit, int i) dvander@157: { dvander@157: //loop i times: dvander@157: // mov ecx, [ebx+] dvander@157: // mov [edi-4*i], ecx dvander@157: //sub edi, 4*N dvander@157: dvander@157: cell_t val; dvander@157: int n = 1; dvander@157: do dvander@157: { dvander@157: val = jit->read_cell(); dvander@157: if (val < SCHAR_MAX && val > SCHAR_MIN) dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val); dvander@157: else dvander@157: IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n); dvander@157: } while (n++ < i); dvander@157: IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG); dvander@157: } dvander@157: dvander@157: void Macro_PushN_C(JitWriter *jit, int i) dvander@157: { dvander@157: //loop i times: dvander@157: // mov [edi-4*i], dvander@157: //sub edi, 4*N dvander@157: dvander@157: int n = 1; dvander@157: do dvander@157: { dvander@157: IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, jit->read_cell(), -4*n); dvander@157: } while (n++ < i); dvander@157: IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG); dvander@157: } dvander@157: dvander@157: void Macro_PushN(JitWriter *jit, int i) dvander@157: { dvander@157: //loop i times: dvander@157: // mov ecx, [ebp+] dvander@157: // mov [edi-4*i], ecx dvander@157: //sub edi, 4*N dvander@157: dvander@157: cell_t val; dvander@157: int n = 1; dvander@157: do dvander@157: { dvander@157: val = jit->read_cell(); dvander@157: if (val < SCHAR_MAX && val > SCHAR_MIN) dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val); dvander@157: else dvander@157: IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n); dvander@157: } while (n++ < i); dvander@157: IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG); dvander@157: } dvander@157: dvander@157: void WriteOp_Sysreq_C_Function(JitWriter *jit) dvander@157: { dvander@157: /* The small daddy of the big daddy of opcodes. dvander@157: * ecx - native index dvander@157: */ dvander@157: CompData *data = (CompData *)jit->data; dvander@157: dvander@157: /* save registers we will need */ dvander@157: //push edx dvander@157: IA32_Push_Reg(jit, AMX_REG_ALT); dvander@157: dvander@157: /* push some callback stuff */ dvander@157: //push edi ; stack dvander@157: //push ecx ; native index dvander@157: IA32_Push_Reg(jit, AMX_REG_STK); dvander@157: IA32_Push_Reg(jit, REG_ECX); dvander@157: dvander@157: /* Relocate stack, heap, frm information, then store back */ dvander@157: //mov eax, [esi+context] dvander@157: //mov ecx, [esi+hea] dvander@157: //sub edi, ebp dvander@157: //mov [eax+hp], ecx dvander@157: //mov ecx, [esi] dvander@157: //mov [eax+sp], edi dvander@157: //mov [eax+frm], ecx dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); dvander@157: IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp)); dvander@157: IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp)); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm)); dvander@157: dvander@157: /* finally, push the last parameter and make the call */ dvander@157: //push eax ; context dvander@157: //call NativeCallback dvander@157: IA32_Push_Reg(jit, REG_EAX); dvander@157: jitoffs_t call = IA32_Call_Imm32(jit, 0); dvander@157: if (!data->debug) dvander@157: { dvander@157: IA32_Write_Jump32_Abs(jit, call, NativeCallback); dvander@157: } else { dvander@157: IA32_Write_Jump32_Abs(jit, call, NativeCallback_Debug); dvander@157: } dvander@157: dvander@157: /* Test for error */ dvander@157: //mov ecx, [esi+context] dvander@157: //cmp [ecx+err], 0 dvander@157: //jnz :error dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); dvander@237: IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0); dvander@157: IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error); dvander@157: dvander@157: /* restore what we damaged */ dvander@157: //add esp, 4*3 dvander@157: //add edi, ebp dvander@157: //pop edx dvander@157: IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG); dvander@157: IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); dvander@157: IA32_Pop_Reg(jit, AMX_REG_ALT); dvander@157: dvander@157: //ret dvander@157: IA32_Return(jit); dvander@157: } dvander@157: dvander@157: void GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], ucell_t _dimcount, bool autozero) dvander@157: { dvander@157: cell_t vectors = 1; /* we need one vector to start off with */ dvander@157: cell_t cur_offs = 0; dvander@157: cell_t cur_write = 0; dvander@157: cell_t dimcount = _dimcount; dvander@157: dvander@157: /* Initialize rotation */ dvander@157: cur_write = dims[dimcount-1]; dvander@157: dvander@157: while (--dimcount >= 1) dvander@157: { dvander@157: cell_t cur_dim = dims[dimcount]; dvander@157: cell_t sub_dim = dims[dimcount-1]; dvander@157: for (cell_t i=0; iget_outputpos(); dvander@157: IA32_Cmp_Reg_Rm_ESP(jit, REG_EAX); dvander@157: jitoffs_t done1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0); dvander@157: IA32_Mov_Reg_Rm_Disp_Reg(jit, REG_ECX, AMX_REG_STK, REG_EAX, SCALE4); dvander@157: IA32_IMul_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG); dvander@157: IA32_Add_Rm_Imm8(jit, REG_EAX, 1, MOD_REG); dvander@157: IA32_Add_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG); dvander@157: IA32_Write_Jump8(jit, IA32_Jump_Imm8(jit, loop1), loop1); dvander@157: IA32_Send_Jump8_Here(jit, done1); dvander@157: dvander@157: /* Test if we have heap space for this */ dvander@157: //mov eax, [esi+info.heap] ;get heap pointer dvander@157: //lea eax, [eax+edx*4] ;new heap pointer dvander@157: //cmp eax, ;compare to heap low dvander@157: //jbe :error ;die if we hit this (it should always be >) dvander@157: //add eax, ebp ;relocate to stack dvander@157: //cmp eax, edi ;die if above the stack pointer dvander@157: //jae :error dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP); dvander@157: IA32_Lea_Reg_DispRegMult(jit, REG_EAX, REG_EAX, REG_EDX, SCALE4); dvander@157: IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, ((CompData *)jit->data)->plugin->data_size); dvander@157: IA32_Jump_Cond_Imm32_Abs(jit, CC_BE, ((CompData *)jit->data)->jit_error_array_too_big); dvander@157: IA32_Add_Reg_Rm(jit, REG_EAX, AMX_REG_DAT, MOD_REG); dvander@157: IA32_Cmp_Reg_Rm(jit, REG_EAX, AMX_REG_STK, MOD_REG); dvander@157: IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_array_too_big); dvander@157: dvander@157: /* Prepare for indirection iteration */ dvander@157: //mov eax, [esi+info.heap] ;get heap pointer dvander@157: //lea ebx, [eax+edx*4] ;new heap pointer dvander@157: //mov [esi+info.heap], ebx ;store back dvander@157: //push eax ;save heap pointer - we need it dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP); dvander@157: IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EDX, SCALE4); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EBX, AMX_INFO_HEAP); dvander@157: IA32_Push_Reg(jit, REG_EAX); dvander@157: dvander@157: WriteOp_Tracker_Push_Reg(jit, REG_EDX); dvander@157: dvander@157: /* This part is too messy to do in straight assembly. dvander@157: * I'm letting the compiler handle it and thus it's in C. dvander@157: */ dvander@157: //lea ebx, [ebp+eax] ;get base pointer dvander@157: //push dword [esp-8] ;push autozero dvander@157: //push dword [esp-8] ;push dimension count dvander@157: //push edi ;push dim array dvander@157: //push ebx dvander@157: //call GenerateArrayIndirectionVectors dvander@157: //add esp, 4*4 dvander@157: IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EBP, NOSCALE); dvander@157: IA32_Push_Rm_Disp8_ESP(jit, 8); dvander@157: IA32_Push_Rm_Disp8_ESP(jit, 8); dvander@157: IA32_Push_Reg(jit, REG_EDI); dvander@157: IA32_Push_Reg(jit, REG_EBX); dvander@157: IA32_Write_Jump32_Abs(jit, IA32_Call_Imm32(jit, 0), (void *)&GenerateArrayIndirectionVectors); dvander@157: IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG); dvander@157: dvander@157: /* Store the heap pointer back into the stack */ dvander@157: //pop eax ;restore heap pointer dvander@157: //pop ecx ;restore param count dvander@157: //lea edi, [edi+ecx*4-4] ;pop params-4 off the stack dvander@157: //mov [edi], eax ;store back the heap pointer dvander@157: IA32_Pop_Reg(jit, REG_EAX); dvander@157: IA32_Pop_Reg(jit, REG_ECX); dvander@157: IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, -4); dvander@157: IA32_Mov_Rm_Reg(jit, AMX_REG_STK, REG_EAX, MOD_MEM_REG); dvander@157: dvander@157: /* Return to caller */ dvander@157: //pop edx dvander@157: //pop eax dvander@157: //pop ebx dvander@157: //ret dvander@157: IA32_Pop_Reg(jit, REG_ECX); dvander@157: IA32_Pop_Reg(jit, REG_EAX); dvander@157: IA32_Pop_Reg(jit, REG_EBX); dvander@157: IA32_Return(jit); dvander@157: } dvander@157: dvander@157: void WriteOp_Sysreq_N_Function(JitWriter *jit) dvander@157: { dvander@157: /* The big daddy of opcodes. dvander@157: * eax - num_params dvander@157: * ecx - native index dvander@157: */ dvander@157: CompData *data = (CompData *)jit->data; dvander@157: dvander@157: /* store the number of parameters on the stack */ dvander@157: //mov [edi-4], eax dvander@157: //sub edi, 4 dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, REG_EAX, -4); dvander@157: IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); dvander@157: dvander@157: /* save registers we will need */ dvander@157: //push eax ; num_params for stack popping dvander@157: //push edx dvander@157: IA32_Push_Reg(jit, REG_EAX); dvander@157: IA32_Push_Reg(jit, AMX_REG_ALT); dvander@157: dvander@157: /* push some callback stuff */ dvander@157: //push edi ; stack dvander@157: //push ecx ; native index dvander@157: IA32_Push_Reg(jit, AMX_REG_STK); dvander@157: IA32_Push_Reg(jit, REG_ECX); dvander@157: dvander@157: /* Relocate stack, heap, frm information, then store back */ dvander@157: //mov eax, [esi+context] dvander@157: //mov ecx, [esi+hea] dvander@157: //sub edi, ebp dvander@157: //mov [eax+hp], ecx dvander@157: //mov ecx, [esi] dvander@157: //mov [eax+sp], edi dvander@157: //mov [eax+frm], ecx dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); dvander@157: IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp)); dvander@157: IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp)); dvander@157: IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm)); dvander@157: dvander@157: /* finally, push the last parameter and make the call */ dvander@157: //push eax ; context dvander@157: //call NativeCallback dvander@157: IA32_Push_Reg(jit, REG_EAX); dvander@157: jitoffs_t call = IA32_Call_Imm32(jit, 0); dvander@157: if (!data->debug) dvander@157: { dvander@157: IA32_Write_Jump32_Abs(jit, call, NativeCallback); dvander@157: } else { dvander@157: IA32_Write_Jump32_Abs(jit, call, NativeCallback_Debug); dvander@157: } dvander@157: dvander@157: /* Test for error */ dvander@157: //mov ecx, [esi+context] dvander@157: //cmp [ecx+err], 0 dvander@157: //jnz :error dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); dvander@237: IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0); dvander@157: IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error); dvander@157: dvander@157: /* restore what we damaged */ dvander@157: //add esp, 4*3 dvander@157: //add edi, ebp dvander@157: //pop edx dvander@157: //pop ecx ; num_params dvander@157: IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG); dvander@157: IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); dvander@157: IA32_Pop_Reg(jit, AMX_REG_ALT); dvander@157: IA32_Pop_Reg(jit, REG_ECX); dvander@157: dvander@157: /* pop the AMX stack. do not check the margins. dvander@157: * Note that this is not a true macro - we don't bother to dvander@157: * set ALT here because nothing will be using it. dvander@157: */ dvander@157: //lea edi, [edi+ecx*4+4] dvander@157: IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, 4); dvander@157: dvander@157: //ret dvander@157: IA32_Return(jit); dvander@157: } dvander@157: dvander@157: void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg) dvander@157: { dvander@157: CompData *data = (CompData *)jit->data; dvander@157: dvander@157: /* Save registers that may be damaged by the call */ dvander@157: //push eax dvander@157: //push ecx dvander@157: //push edi dvander@157: //lea edi, [*4] ; we want the count in bytes not in cells dvander@157: IA32_Push_Reg(jit, AMX_REG_PRI); dvander@157: if (reg == REG_ECX) dvander@157: { dvander@157: IA32_Push_Reg(jit, AMX_REG_TMP); dvander@157: } dvander@157: IA32_Push_Reg(jit, AMX_REG_STK); dvander@157: IA32_Lea_Reg_RegMultImm32(jit, REG_EDI, reg, SCALE4, 0); dvander@157: dvander@157: /* Get the context ptr, push it and call the check */ dvander@157: //mov eax, [esi+context] dvander@157: //push eax dvander@157: //call JIT_VerifyOrAllocateTracker dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); dvander@157: IA32_Push_Reg(jit, REG_EAX); dvander@157: jitoffs_t call = IA32_Call_Imm32(jit, 0); dvander@157: IA32_Write_Jump32_Abs(jit, call, JIT_VerifyOrAllocateTracker); dvander@157: dvander@157: /* Check for errors */ dvander@237: //cmp eax, 0 dvander@157: //jnz :error faluco@238: IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0); faluco@238: IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return); dvander@157: dvander@237: /* Restore */ dvander@237: //pop eax dvander@237: IA32_Pop_Reg(jit, REG_EAX); dvander@237: dvander@157: /* Push the register into the stack and increment pCur */ dvander@157: //mov edx, [eax+vm[]] dvander@157: //mov eax, [edx+pcur] dvander@157: //add [edx+pcur], 4 dvander@157: //mov [eax], edi dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER])); dvander@157: IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EDX, offsetof(tracker_t, pCur)); dvander@157: IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur)); dvander@157: IA32_Mov_Rm_Reg(jit, REG_EAX, REG_EDI, MOD_MEM_REG); dvander@157: dvander@157: /* Restore PRI, ALT and STK */ dvander@157: //pop edi dvander@157: //pop ecx dvander@157: //pop eax dvander@157: IA32_Pop_Reg(jit, AMX_REG_STK); dvander@157: if (reg == REG_ECX) dvander@157: { dvander@157: IA32_Pop_Reg(jit, AMX_REG_TMP); dvander@157: } dvander@157: IA32_Pop_Reg(jit, AMX_REG_PRI); dvander@157: } dvander@157: dvander@237: int JIT_VerifyOrAllocateTracker(sp_context_t *ctx) dvander@157: { dvander@157: tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]); dvander@157: dvander@157: if ((size_t)(trk->pCur - trk->pBase) >= trk->size) dvander@157: { dvander@237: return SP_ERROR_TRACKER_BOUNDS; dvander@157: } dvander@157: dvander@157: if (trk->pCur+1 - (trk->pBase + trk->size) == 0) dvander@157: { dvander@157: size_t disp = trk->size - 1; dvander@157: trk->size *= 2; dvander@157: trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t)); dvander@157: dvander@157: if (!trk->pBase) dvander@157: { dvander@237: return SP_ERROR_TRACKER_BOUNDS; dvander@157: } dvander@157: dvander@157: trk->pCur = trk->pBase + disp; dvander@157: } dvander@237: dvander@237: return SP_ERROR_NONE; dvander@157: } dvander@157: dvander@237: int JIT_VerifyLowBoundTracker(sp_context_t *ctx) dvander@157: { dvander@157: tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]); dvander@157: dvander@157: if (trk->pCur <= trk->pBase) dvander@157: { dvander@237: return SP_ERROR_TRACKER_BOUNDS; dvander@157: } dvander@237: dvander@237: return SP_ERROR_NONE; dvander@237: }