www.pudn.com > coremp4-1.0.zip > DynamicARMCode.cpp
/***************************************************************************** * * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * The Core Pocket Media Player * Copyright (c) 2004-2005 Gabor Kovacs * ****************************************************************************/ #if defined __SYMBIAN32__ #include#elif defined _WIN32_WCE #include #endif //---------------------------- #include "DynamicArmCode.h" #include "Util.h" #include "C_buffer.h" //mode //1: I2 rd:16,rn:12 //2: I2C rd:16,rn:12,imm[3]:0 //4: I3 rd:0,rnlo:12,rnhi:16 //6: I2 rd:12,rn:16 //7: I3 rd:12,rn:16,rm:0 //8: I3C rd:12,rn:16,rm:0,imm[3]:20 //9: I2C rd:12,rn:16,imm[8]:0|20 //F: I2C,I1P rd:12,rn:16,imm[8]:0 (w or q *4) //---------------------------- void *CodeAlloc(int size){ #if defined __SYMBIAN32__ || defined __PALMOS__ //Symbian return new(true) byte[size]; #elif defined _WIN32_WCE return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READ); #else #error #endif } //---------------------------- void CodeFree(void *code, int size){ #if defined __SYMBIAN32__ || defined __PALMOS__ //Symbian delete[] (byte*)code; #elif defined _WIN32_WCE VirtualFree(code, size, MEM_DECOMMIT); VirtualFree(code, 0, MEM_RELEASE); #else #error #endif } //---------------------------- void CodeLock(void *code, int size){ #if defined _WIN32_WCE DWORD protect; VirtualProtect(code, size, PAGE_READWRITE | PAGE_NOCACHE, &protect); #endif } //---------------------------- void CodeUnlock(void *code, int size){ //flush cache #ifdef __SYMBIAN32__ User::IMB_Range(code, (byte*)code+size); #elif defined _WIN32_WCE DWORD protect; VirtualProtect(code, size, PAGE_EXECUTE_READ, &protect); static void (WINAPI *FuncCacheSync)(DWORD); static HMODULE CoreDLL; if(!FuncCacheSync && !CoreDLL){ CoreDLL = LoadLibrary(L"coredll.dll"); if(CoreDLL) *(FARPROC*)&FuncCacheSync = GetProcAddress(CoreDLL, L"CacheSync"); } if(FuncCacheSync) FuncCacheSync(2); #elif defined __PALMOS__ byte *mem = new byte[65536]; if(mem){ MemCpy(mem, mem, 65536); delete[] mem; } #else #error #endif } //---------------------------- //detect caps dword C_dyn_code::GetCpuCaps(){ dword caps = 0; #if defined _WIN32_WCE HINSTANCE hi = LoadLibrary(L"Coredll.dll"); if(hi){ typedef BOOL (t_IsProcessorFeaturePresent)(DWORD); t_IsProcessorFeaturePresent *fp = (t_IsProcessorFeaturePresent*)GetProcAddress(hi, L"IsProcessorFeaturePresent"); if(fp){ const dword _PF_ARM_INTEL_WMMX = 0x80010003; if((*fp)(_PF_ARM_INTEL_WMMX) != 0) caps |= CPU_WIRELESS_MMX; } FreeLibrary(hi); } #endif return caps; } //---------------------------- //---------------------------- class C_dyn_code_imp: public C_dyn_code{ struct S_instruction{ S_instruction *next, *prev; int tag; int read_flags; int write_flags; dword read_regs; dword write_regs; S_instruction *realloc; bool branch; //branch label bool is_function; dword code_small; byte *code_large; int code_size; byte *address; S_instruction(): tag(0), next(NULL), prev(NULL), read_flags(0), write_flags(0), read_regs(0), write_regs(0), realloc(NULL), branch(false), is_function(false), code_small(0), code_large(NULL), address(NULL) {} }; E_CONDITION next_cond; bool next_set, next_byte, next_half, next_sign; dword max_align; //---------------------------- struct S_dynamic_code{ byte *alloc_base; dword alloc_size; byte *code; //dword size; S_dynamic_code(): alloc_base(NULL), code(NULL), //size(0), alloc_size(0) {} ~S_dynamic_code(){ Free(); } void Free(){ if(alloc_base) CodeFree(alloc_base, alloc_size); alloc_base = NULL; code = NULL; //size = alloc_size = 0; } C_buffer functions; } dynamic_code; //---------------------------- S_instruction *inst_begin, *inst_end; bool move_back; //bool delay_slot; dword local_vars_size; //---------------------------- void InstInit(); //---------------------------- inline void StoreReg(dword ®s, dword reg){ if(reg != NONE){ if(reg<32) regs |= 1 << reg; else regs |= 256 << (reg-32); } } //---------------------------- S_instruction *InstCreate(const void *code, int code_size, byte write_reg, byte read_reg_1, byte read_reg_2, int read_flags, int write_flags); //---------------------------- static bool InstReadWrite(const S_instruction *a, const S_instruction *b){ return ((a->read_flags&b->write_flags) || (a->read_regs&b->write_regs)); } static bool InstBothWrite(const S_instruction *a, const S_instruction *b){ return ((a->write_flags&b->write_flags) || (a->write_regs&b->write_regs)); } //---------------------------- static int InstructionSize(const S_instruction *p, int pos){ if(p->code_size >= 0) return p->code_size; pos = pos % -p->code_size; if(pos) pos = -p->code_size - pos; return pos; } static byte *InstCode(S_instruction *p){ return p->code_large ? p->code_large : (byte*)&p->code_small; } //---------------------------- void InstAdd(S_instruction *ins){ assert(ins); S_instruction *p = inst_end; //insert after p /* if(delay_slot){ assert(p && !p->branch && !InstReadWrite(p, ins) && !InstReadWrite(ins, p) && !InstBothWrite(p, ins)); p->branch = true; p = p->prev; delay_slot = false; } */ if(move_back){ while(p && !p->branch && !p->is_function && !InstReadWrite(p, ins) && !InstReadWrite(ins, p) && !InstBothWrite(p, ins)) p = p->prev; move_back = false; } if(p){ if(p->next) p->next->prev = ins; else inst_end = ins; ins->next = p->next; ins->prev = p; p->next = ins; }else{ if(inst_begin) inst_begin->prev = ins; else inst_end = ins; ins->next = inst_begin; ins->prev = NULL; inst_begin = ins; } } //---------------------------- S_instruction *InstCreate32(int Code32, byte write_reg = NONE, byte read_reg_1 = NONE, byte read_reg_2 = NONE, int read_flags = 0, int write_flags = 0){ return InstCreate(&Code32, 4, write_reg, read_reg_1, read_reg_2, read_flags, write_flags); } /* S_instruction *InstCreate16(int Code16, byte write_reg, byte read_reg_1, byte read_reg_2, int read_flags, int write_flags){ return InstCreate(&Code16, 2, write_reg, read_reg_1, read_reg_2, read_flags, write_flags); } */ //---------------------------- void FreeInstructions(); //---------------------------- bool InstReAlloc(S_instruction *p, const S_instruction *realloc); //---------------------------- void IPLD(int *code, byte *dest); //---------------------------- public: C_dyn_code_imp(): move_back(false), local_vars_size(0), inst_begin(NULL), inst_end(NULL), max_align(0) { InstInit(); } ~C_dyn_code_imp(){ Close(); } void Close(){ FreeInstructions(); dynamic_code.Free(); } //---------------------------- virtual void Byte(){ next_byte = true; next_sign = false; } virtual void Half(){ next_half = true; next_sign = false; } virtual void SByte(){ next_byte = true; next_sign = true; } virtual void SHalf(){ next_half = true; next_sign = true; } virtual void Cond(E_CONDITION c){ next_cond = c; } virtual void Set(){ next_set = true; } virtual void MoveBack(){ move_back = true; } //was: MB() //void DS(){ delay_slot = true; } void InstPost(S_instruction *p){ InstAdd(p); InstInit(); } //---------------------------- virtual void *Label(bool do_post){ S_instruction *p = InstCreate(NULL, 0, NONE, NONE, NONE, 0, 0); p->branch = true; if(do_post) InstPost(p); return p; } //---------------------------- virtual void PutLabel(void *label){ S_instruction *ins = (S_instruction*)label; //make sure it was not already posted assert(!ins->next); InstPost(ins); } //---------------------------- virtual void *DeclareData(void *data, dword data_size){ S_instruction *p = InstCreate(data, data_size, NONE, NONE, NONE, 0, 0); p->branch = true; return p; } //---------------------------- virtual void StoreLabelAddress(void *label){ S_instruction *p = InstCreate32(NULL, NONE, NONE, NONE, 0, 0); p->realloc = (S_instruction*)label; p->branch = true; InstPost(p); } //---------------------------- virtual void Align(dword bytes){ S_instruction *p = InstCreate(NULL, -(int)bytes, NONE, NONE, NONE, 0, 0); p->branch = true; InstPost(p); max_align = Max(max_align, bytes); } //---------------------------- /* void Break(){ S_instruction *p = InstCreate32((next_cond << 28) | (15 << 24)); p->branch = true; InstPost(p); } */ //---------------------------- virtual void FunctionBegin(dword _local_vars_size){ // stmfd sp!, { r4 - r11, lr } S_instruction *p = InstCreate32(0xe92d4ff0, sp); p->is_function = true; for(int i=4; i<16; ++i) p->read_regs |= 1 << i; InstPost(p); //allocate space for local variables local_vars_size = _local_vars_size; if(local_vars_size) I2C(SUB, sp, sp, local_vars_size); } //---------------------------- virtual void FunctionEnd(){ if(local_vars_size){ I2C(ADD, sp, sp, local_vars_size); local_vars_size = 0; } // ldmfd sp!, { r4 - r11, pc } S_instruction *p = InstCreate32(0xe8bd8ff0, sp); for(int i=4;i<16;++i) p->write_regs |= 1 << i; InstPost(p); } //---------------------------- virtual void CodeBuild(); //---------------------------- virtual void I3C(int code, byte Dest, byte op_1, byte Op2, int constant); virtual void I3(int code, byte Dest, byte op_1, byte Op2); virtual void I3S(int code, byte Dest, byte op_1, byte Op2, E_SHIFT_TYPE ShiftType, int Shift); virtual void I4(int code, byte Dest, byte op_1, byte Op2, byte Op3); virtual void IConst(byte Dest, int constant); virtual void I2(int code, byte Dest, byte op_1); virtual void I2C(int code, byte Dest, byte op_1, int constant); virtual void I1P(int code, byte Dest, void *block, int Ofs); virtual void I0P(int code, int Cond, void *target); virtual void MulC(E_REGISTER dst, E_REGISTER src, int constant); //---------------------------- virtual void *Code(dword fnc_index) const{ if(fnc_index >= dynamic_code.functions.Size()) return NULL; return dynamic_code.functions[fnc_index]; } }; //---------------------------- void C_dyn_code_imp::InstInit(){ next_cond = AL; next_set = false; next_byte = false; next_half = false; next_sign = false; } //---------------------------- C_dyn_code_imp::S_instruction *C_dyn_code_imp::InstCreate(const void *code, int code_size, byte write_reg, byte read_reg_1, byte read_reg_2, int read_flags, int write_flags){ S_instruction *p = new(true) S_instruction(); p->read_flags = read_flags; p->write_flags = write_flags; p->code_size = code_size; if(code_size <= (int)sizeof(p->code_small)){ if(code) p->code_small = *(dword*)code; }else{ p->code_large = new(true) byte[code_size]; if(code) MemCpy(p->code_large, code, code_size); else MemSet(p->code_large, 0, code_size); } StoreReg(p->write_regs, write_reg); StoreReg(p->read_regs, read_reg_1); StoreReg(p->read_regs, read_reg_2); /* if(write_reg != NONE){ if(write_reg<32) p->write_regs |= 1 << write_reg; else p->write_flags |= 256 << (write_reg-32); } if(read_reg_1 != NONE){ if(read_reg_1<32) p->read_regs |= 1 << read_reg_1; else p->read_flags |= 256 << (read_reg_1-32); } if(read_reg_2 != NONE){ if(read_reg_2<32) p->read_regs |= 1 << read_reg_2; else p->read_flags |= 256 << (read_reg_2-32); } */ return p; } //---------------------------- void C_dyn_code_imp::FreeInstructions(){ for(S_instruction *p = inst_begin; p; ){ S_instruction *q = p; p = p->next; if(q->code_large) delete[] q->code_large; delete q; } inst_begin = NULL; inst_end = NULL; } //---------------------------- bool C_dyn_code_imp::InstReAlloc(S_instruction *p, const S_instruction *realloc){ int Diff = realloc->address - (p->address+8); int *code = (int*)InstCode(p); if(((*code >> 25) & 7) == 6){ //wldr,wstr int Ofs = Diff + p->tag; int OfsUnsigned = 1; if(Ofs < 0){ Ofs = -Ofs; OfsUnsigned = 0; } if(*code & 256){ if(Ofs & 3) Ofs = 256; else Ofs >>= 2; } if(Ofs < 256){ *code &= ~(1<<23); *code |= OfsUnsigned<<23; *code &= ~255; *code |= Ofs; return true; } //DEBUG_MSG1(-1,T("Realloc failed for wldr,wstr %d"),Ofs); }else if(((*code >> 25) & 7) == 5){ //branch *code &= 0xff000000; *code |= (Diff >> 2) & ~0xff000000; return true; }else if(((*code >> 25) & 7) == 1){ //add dest,pc,#const int Shift; int Ofs = Diff + p->tag; *code &= ~((15 << 21)|4095); if(Ofs < 0){ Ofs = -Ofs; *code |= (SUB << 21); }else *code |= (ADD << 21); for(Shift = 0;Shift<32;Shift+=2){ if (Ofs >= 0 && Ofs <= 255) break; Ofs = (Ofs << 2) | ((Ofs >> 30) & 3); } if(Ofs >= 0 && Ofs <= 255){ *code |= (Shift << 7) | Ofs; return true; } //DEBUG_MSG1(-1,T("Realloc failed for add dest,pc,#const %d"),Ofs); }else if(((*code >> 25) & 7) == 2){ //ldr,str int Ofs = Diff + p->tag; int OfsUnsigned = 1; if(Ofs < 0){ Ofs = -Ofs; OfsUnsigned = 0; } if(Ofs < 4096){ *code &= ~(1<<23); *code |= OfsUnsigned<<23; *code &= ~4095; *code |= Ofs; return true; } //DEBUG_MSG1(-1,T("Realloc failed for ldr,str %d"),Ofs); }else if(!*code){ //plain address instantiation *code = (int)realloc->address; return true; } return false; } //---------------------------- void C_dyn_code_imp::IPLD(int *code, byte *dest){ switch(*code){ case PLD: next_cond = NV; next_byte = true; *code = LDR; *dest = pc; break; case PLD_PRE: next_cond = NV; next_byte = true; *code = LDR_PRE; *dest = pc; break; case PLD_POST: next_cond = NV; next_byte = true; *code = LDR_POST; *dest = pc; break; case PLD_PRESUB: next_cond = NV; next_byte = true; *code = LDR_PRESUB; *dest = pc; break; case PLD_POSTSUB: next_cond = NV; next_byte = true; *code = LDR_POSTSUB; *dest = pc; break; } } //---------------------------- #define MODE(x) ((dword)(x) >> 28) #define MODEMASK ~0xF0000000 void C_dyn_code_imp::I3C(int code, byte Dest, byte op_1, byte Op2, int constant){ S_instruction *p = NULL; if(MODE(code) == 8 && constant>=0 && constant<8){ p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 12) | ((op_1 & 15) << 16) | ((Op2 & 15) << 0) | (constant << 20), Dest, op_1, Op2, (next_cond != AL)?1:0, 0); } InstPost(p); } //---------------------------- void C_dyn_code_imp::I3(int code, byte Dest, byte op_1, byte Op2){ if(MODE(code) == 4){ S_instruction *p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 0) | ((op_1 & 15) << 12) | ((Op2 & 15) << 16), Dest, op_1, Op2, (next_cond != AL)?1:0, 0); InstPost(p); }else if(MODE(code) == 7){ S_instruction *p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 12) | ((op_1 & 15) << 16) | ((Op2 & 15) << 0), Dest, op_1, Op2, (next_cond != AL)?1:0, 0); InstPost(p); }else I3S(code,Dest,op_1,Op2, LSL, 0); } //---------------------------- void C_dyn_code_imp::I3S(int code, byte Dest, byte op_1, byte Op2, E_SHIFT_TYPE ShiftType, int Shift){ S_instruction *p = NULL; //if(Shift == 0) //ShiftType = LSL; if(ShiftType == LSL && Shift < 0){ ShiftType = LSR; Shift = -Shift; } if((ShiftType == LSR || ShiftType == ASR) && Shift < 0){ ShiftType = LSL; Shift = -Shift; } if(ShiftType == ROR && Shift < 0) Shift = Shift & 31; assert(Shift >= 0 && Shift < 32); if(code >= 0 && code < 16){ if (code == CMP || code == TST || code == CMN || code == TEQ) next_set = 1; p = InstCreate32((next_cond << 28) | (code << 21) | ((next_set?1:0)<<20) | ((op_1==NONE ? r0 : op_1) << 16) | ((Dest==NONE ? r0 : Dest) << 12) | (Shift << 7) | (ShiftType << 5) | (Op2), Dest, op_1, Op2, (next_cond != AL)?1:0, next_set?1:0); } if (Shift == 0){ if (code == MUL && Dest != op_1){ p = InstCreate32((next_cond << 28) | ((next_set?1:0)<<20) | (Dest << 16) | (Op2 << 8) | 0x90 | (op_1), Dest, op_1, Op2, (next_cond != AL)?1:0, next_set?1:0); } if (code >= QADD && code <= QDSUB){ p = InstCreate32((next_cond << 28) | (Dest << 12) | (op_1) | (Op2 << 16) | (0x5 << 4) | (1<<24) | ((code-QADD)<<21), Dest, op_1, Op2, (next_cond != AL)?1:0, next_set?1:0); } } IPLD(&code, &Dest); if (code == LDR || code == STR || code == LDR_PRE || code == STR_PRE || code == LDR_POST|| code == STR_POST || code == LDR_PRESUB || code == STR_PRESUB || code == LDR_POSTSUB || code == STR_POSTSUB) { bool pre = (code != LDR_POST) && (code != STR_POST) && (code != LDR_POSTSUB) && (code != STR_POSTSUB); bool pre_write = (code == LDR_PRE) || (code == STR_PRE) || (code == LDR_PRESUB) || (code == STR_PRESUB); bool load = (code == LDR) || (code == LDR_PRE) || (code == LDR_POST) || (code == LDR_PRESUB) || (code == LDR_POSTSUB); bool un_signed = (code != LDR_PRESUB) && (code != STR_PRESUB) && (code != LDR_POSTSUB) && (code != STR_POSTSUB); if(next_half || next_sign){ if(Shift==0 && (next_half || next_byte)){ p = InstCreate32((next_cond << 28) | ((pre ? 1 : 0)<<24) | (un_signed<<23) | ((pre_write ? 1 : 0)<<21) | (load<<20) | (next_sign << 6) | (next_half << 5) | (op_1 << 16) | (Dest << 12) | (9 << 4) | Op2, NONE, op_1, Op2, (next_cond != AL)?1:0, 0); } }else{ p = InstCreate32((next_cond << 28) | (3 << 25) | ((pre ? 1 : 0)<<24) | (un_signed<<23) | (next_byte<<22) | ((pre_write ? 1 : 0)<<21) | (load<<20) | (op_1 << 16) | (Dest << 12) | (Shift << 7) | (ShiftType << 5) | Op2, NONE, op_1, Op2, (next_cond != AL)?1:0, 0); } if(p){ if(load) p->write_regs |= 1 << Dest; else p->read_regs |= 1 << Dest; if(!pre || pre_write) p->write_regs |= 1 << op_1; } } InstPost(p); } //---------------------------- void C_dyn_code_imp::I4(int code, byte Dest, byte op_1, byte Op2, byte Op3){ S_instruction *p = NULL; if (code == MLA){ p = InstCreate32((next_cond << 28) | (1 << 21) | ((next_set?1:0)<<20) | (Dest << 16) | (Op3 << 12) | (Op2 << 8) | 0x90 | (op_1), Dest, op_1, Op2, (next_cond != AL)?1:0, next_set?1:0); p->read_regs |= 1 << Op3; } InstPost(p); } //---------------------------- void C_dyn_code_imp::MulC(E_REGISTER dst, E_REGISTER src, int constant){ if(dst == src){ assert(0); InstPost(NULL); } switch(constant){ case 0: Mov(dst, 0); break; case 1: Mov(dst, src); break; case 2: Mov(dst, src, LSL, 1); break; case 3: Add(dst, src, src, LSL, 1); break; case 4: Mov(dst, src, LSL, 2); break; case 5: Add(dst, src, src, LSL, 2); break; case 6: Mov(dst, src, LSL, 1); Add(dst, dst, dst, LSL, 1); break; //2*3 case 7: Rsb(dst, src, src, LSL, 3); break; case 8: Mov(dst, src, LSL, 3); break; case 9: Add(dst, src, src, LSL, 3); break; case 10: Mov(dst, src, LSL, 1); Add(dst, dst, dst, LSL, 2); break; //2*5 case 11: Rsb(dst, src, src, LSL, 3); Add(dst, dst, src, LSL, 2); break; //7+4 case 12: Add(dst, src, src, LSL, 1); Mov(dst, dst, LSL, 2); break; //3*4 case 13: Add(dst, src, src, LSL, 3); Add(dst, dst, src, LSL, 2); break; //9+4 case 14: Rsb(dst, src, src, LSL, 3); Add(dst, dst, dst); break; //7*2 case 15: Rsb(dst, src, src, LSL, 4); break; case 16: Mov(dst, src, LSL, 4); break; case 17: Add(dst, src, src, LSL, 4); break; default: Mov(dst, constant); Mul(dst, src, dst); break; } } //---------------------------- void C_dyn_code_imp::IConst(byte Dest, int constant){ S_instruction *p = NULL; int Shift,code; if(constant < 0){ code = MVN; constant = -constant-1; }else code = MOV; constant = (constant << 8) | ((constant >> 24) & 255); for(Shift=8;Shift<=32;Shift+=2){ if(constant & 0xC0) break; constant = (constant << 2) | ((constant >> 30) & 3); } Shift &= 31; constant &= 255; p = InstCreate32((next_cond << 28) | (1<<25) | (code << 21) | ((next_set?1:0)<<20) | (Dest << 12) | (Shift << 7) | constant, Dest, NONE, NONE, (next_cond != AL)?1:0, next_set?1:0); InstPost(p); } //---------------------------- void C_dyn_code_imp::I2(int code, byte Dest, byte op_1){ if (MODE(code) == 1){ S_instruction *p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 16) | ((op_1 & 15) << 12), Dest, op_1, NONE, (next_cond != AL)?1:0, 0); InstPost(p); } else if (MODE(code) == 6){ S_instruction *p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 12) | ((op_1 & 15) << 16), Dest, op_1, NONE, (next_cond != AL)?1:0, 0); InstPost(p); }else I2C(code,Dest,op_1,0); } //---------------------------- void C_dyn_code_imp::I2C(int code, byte Dest, byte op_1, int constant){ S_instruction *p = NULL; if(MODE(code) == 2 && constant>=0 && constant<8){ p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 16) | ((op_1 & 15) << 12) | (constant << 0), Dest, op_1, NONE, (next_cond != AL)?1:0, 0); } if(MODE(code) == 9 && constant>=0 && constant<256){ p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 12) | ((op_1 & 15) << 16) | ((constant & 15) << 0) | ((constant & 0xF0) << 16), Dest, op_1, NONE, (next_cond != AL)?1:0, 0); } if(MODE(code) == 15){ if(constant<0){ code ^= (1<<23); constant = -constant; } if(code & 256){ // dword or qword if(constant & 3) constant = -1; else constant >>= 2; } if(constant>=0 && constant<256){ p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 12) | ((op_1 & 15) << 16) | (constant << 0), NONE, op_1, NONE, (next_cond != AL)?1:0, 0); if(code & (1<<20)) p->write_regs |= 1 << Dest; else p->read_regs |= 1 << Dest; if(!(code & (1<<24)) || (code & (1<<21))) p->write_regs |= 1 << op_1; } } if(code >= 0 && code < 16){ if(code==MOV && constant<0){ code = MVN; constant = -constant-1; }else if(code==ADD && constant<0){ code = SUB; constant = -constant; } else if(code==SUB && constant<0){ code = ADD; constant = -constant; } if(code == CMP || code == TST || code == CMN || code == TEQ) next_set = 1; int shift; for(shift = 0; shift<32; shift+=2){ if(constant>=0 && constant<=255) break; constant = (constant << 2) | ((constant >> 30) & 3); } if(constant >= 0 && constant <= 255){ p = InstCreate32((next_cond << 28) | (1<<25) | (code << 21) | ((next_set?1:0)<<20) | ((op_1==NONE ? r0 : op_1) << 16) | ((Dest==NONE ? r0 : Dest) << 12) | (shift << 7) | constant, Dest, op_1, NONE, (next_cond != AL)?1:0, next_set?1:0); } } IPLD(&code,&Dest); if(code == LDR || code == STR || code == LDR_PRE || code == STR_PRE || code == LDR_POST|| code == STR_POST || code == LDR_PRESUB || code == STR_PRESUB || code == LDR_POSTSUB || code == STR_POSTSUB){ bool pre = (code != LDR_POST) && (code != STR_POST) && (code != LDR_POSTSUB) && (code != STR_POSTSUB); bool pre_write = (code == LDR_PRE) || (code == STR_PRE) || (code == LDR_PRESUB) || (code == STR_PRESUB); bool load = (code == LDR) || (code == LDR_PRE) || (code == LDR_POST) || (code == LDR_PRESUB) || (code == LDR_POSTSUB); bool un_signed = (code != LDR_PRESUB) && (code != STR_PRESUB) && (code != LDR_POSTSUB) && (code != STR_POSTSUB); if(constant == 0){ pre = true; pre_write = false; } if(constant < 0){ constant = -constant; un_signed = !un_signed; } if(next_half || next_sign){ if (constant >= 0 && constant < 256 && (next_half || next_byte)) p = InstCreate32((next_cond << 28) | ((pre ? 1 : 0)<<24) | (un_signed<<23) | (1 << 22) | ((pre_write ? 1 : 0)<<21) | (load<<20) | (next_sign << 6) | (next_half << 5) | (op_1 << 16) | (Dest << 12) | ((constant >> 4) << 8) | (9 << 4) | (constant & 15), NONE, op_1, NONE, (next_cond != AL)?1:0, 0); }else if(constant >= 0 && constant < 4096){ p = InstCreate32((next_cond << 28) | (1 << 26) | ((pre ? 1 : 0)<<24) | (un_signed<<23) | (next_byte<<22) | ((pre_write ? 1 : 0)<<21) | (load<<20) | (op_1 << 16) | (Dest << 12) | constant, NONE, op_1, NONE, (next_cond != AL)?1:0, 0); } if(p){ if(load) p->write_regs |= 1 << Dest; else p->read_regs |= 1 << Dest; if(!pre || pre_write) p->write_regs |= 1 << op_1; } } InstPost(p); } //---------------------------- void C_dyn_code_imp::I1P(int code, byte Dest, void *block, int Ofs){ S_instruction *p = NULL; if(MODE(code)==15){ p = InstCreate32((next_cond << 28) | (code & MODEMASK) | (pc << 16) | ((Dest & 15) << 12), Dest, pc, NONE, (next_cond != AL)?1:0, 0); p->tag = Ofs; p->realloc = (S_instruction*)block; } if(code == LDR || code == STR){ int load = (code == LDR); p = InstCreate32((next_cond << 28) | (1 << 26) | (1<<24) | (next_byte<<22) | (load<<20) | (pc << 16) | (Dest << 12), Dest, pc, NONE, (next_cond != AL)?1:0, 0); p->tag = Ofs; p->realloc = (S_instruction*)block; }else if(code == MOV){ // ADD|SUB,Dst,R15,Ofs p = InstCreate32((next_cond << 28) | (1<<25) | (pc << 16) | (Dest << 12), Dest, pc, NONE, (next_cond != AL)?1:0, 0); p->tag = Ofs; p->realloc = (S_instruction*)block; } InstPost(p); } //---------------------------- void C_dyn_code_imp::I0P(int code, int Cond, void *target){ S_instruction *p = NULL; if(code == B || code == BL){ p = InstCreate32((Cond << 28) | (5 << 25) | ((code == BL?1:0)<<24), pc, NONE, NONE, (Cond != AL)?1:0, 0); if(code == BL) p->write_regs |= 1 << lr; p->realloc = (S_instruction*)target; p->branch = true; } InstPost(p); } //---------------------------- void C_dyn_code_imp::CodeBuild(){ //determine code size int code_size = 0; int num_functions = 0; for(S_instruction *p=inst_begin; p; p=p->next){ code_size += InstructionSize(p, code_size); if(p->is_function) ++num_functions; } dynamic_code.functions.Resize(num_functions); //allocate code //if(code_size > dynamic_code.allocated){ dynamic_code.Free(); dynamic_code.alloc_size = code_size; if(max_align) dynamic_code.alloc_size += max_align-1; dynamic_code.alloc_base = (byte*)CodeAlloc(dynamic_code.alloc_size); if(!dynamic_code.alloc_base) return; dynamic_code.code = dynamic_code.alloc_base; if(max_align) dynamic_code.code = (byte*)((dword(dynamic_code.alloc_base)+max_align-1) & -max_align); //} //dynamic_code.size = code_size; //if(dynamic_code.code) { int fnc_index = 0; CodeLock(dynamic_code.alloc_base, dynamic_code.alloc_size); byte *addr = dynamic_code.code; S_instruction *p; for(p=inst_begin; p; p=p->next){ p->address = addr; if(p->is_function) dynamic_code.functions[fnc_index++] = addr; addr += InstructionSize(p, addr - dynamic_code.code); } for(p=inst_begin; p; p=p->next){ if(p->realloc && (!p->realloc->address || !InstReAlloc(p, p->realloc))){ //dynamic_code.size = 0; assert(0); break; } if(p->code_large) MemCpy(p->address, p->code_large, p->code_size); else if(p->code_size>0){ if(p->code_size == sizeof(dword)) *(dword*)p->address = p->code_small; else{ assert(0); } } } CodeUnlock(dynamic_code.alloc_base, dynamic_code.alloc_size); }//else //dynamic_code.size = 0; FreeInstructions(); } //---------------------------- C_dyn_code *C_dyn_code::Create(){ return new(true) C_dyn_code_imp; } //----------------------------