www.pudn.com > ASM86_64.rar > operand.c
/* * * */ #include "a64-2.h" #include "operand.h" #include "error.h" #include "label.h" #includeint is_variable(char *s) { return 0; } /********************************************************* example: parameter: s = "(dword)es:[eax+ecx*8+0xc]" (one operand) o_key = get a operand's key word return value: error if errno is set successed if errno is 0 last change: 02-17-2006 21:24 by mik last change: 02-19-2006 21:05 by mik **********************************************************/ errno_t get_o_key(o_key_t *o_key, char *s) { if (!s || !s[0]) return 0; errno_t errno = 0; /* return value */ char *p = s; char str[80]; int i = 0; unsigned char c = 0; if (!o_key) return ERR_OPERAND; /* the operand is a memory operand */ if (get_c(s, '[') == 1) o_key->mem = (mem_t *)a64_malloc(sizeof(mem_t)); /* parse operand * * for example: (dword)es:[ecx*8+eax+0xc] */ char tmp_msg[120]; char *msg = get_err_msg_addr(); while (*p) { if (is_c(*p) || is_n(*p)) { str[i++] = *p; } else switch (*p) { case '(': if (p != s) { /* it's not head */ sprintf(tmp_msg, "at %d: %s\n", line, "parse error at before '('"); if (str_len(msg) + str_len(tmp_msg) < ERR_MSG_SIZE) { str_cat(msg, tmp_msg); } } if (get_c(s,')') != 1) errno |= ERR_SLBRACKET; i = 0; break; case ')': /* get operand size cast value */ if (get_c(s, '(') != 1) errno |= ERR_SRBRACKET; str[i] = 0; unsigned char cast = get_castid(str); if (!check_cast(cast)) errno |= ERR_CAST; if (o_key->mem) { if (cast == NEAR_ID || cast == FAR_ID) o_key->mem->transfer_cast = cast; else /* it's a memory cast */ o_key->mem->cast = cast; } else { /* it's a immediate cast */ o_key->imme = (imme_t *)a64_malloc(sizeof(mem_t)); o_key->imme->cast = cast; } i = 0; break; case ':': /* segment override */ /* get segment override size byte */ str[i] = 0; o_key->mem->oseg = get_osegid(str); if (!check_oseg(o_key->mem->oseg)) { if (current_bits == 64) { sprintf(tmp_msg, "error at %d: %s\n", line, "in 64-bit mode: the " "prefix illegal! "); mount_err_link(0, 0, tmp_msg); errno |= ERR_ERROR; } else errno |= ERR_PREFIX; } i = 0; break; case '[': /* memory operand */ /******************************* TO DO: this is reserved for var .... example: var1[eax] this is same as [eax + var1] *****************************/ #ifdef RESERVED_VAR str[i] = 0; /* check var at var table */ if (!check_var(str)) errno |= ERR_OPERAND; p++; /* skip '[' */ #else /* xxx[...] is error */ if (i) errno |= ERR_OPERAND; #endif if (get_c(s, ']') != 1) errno |= ERR_MRBRACKET; i = 0; break; case '+': case ']': if (*p == ']') { if (get_c(s, '[') != 1) errno |= ERR_MLBRACKET; if ((*(p+1) != 0) && (*(p+1) != '!')) { /* not tail and not comment */ /* errno |= ERR_OPERAND; */ sprintf(tmp_msg, "at %d: %s\n", line, "parse error at after ']'"); if (str_len(msg) + str_len(tmp_msg) < ERR_MSG_SIZE) { str_cat(msg, tmp_msg); } } } str[i] = 0; c = get_regid(str); if (check_mreg(c)) { /* it's valid register */ if (!o_key->mem->base) o_key->mem->base = c; else if (!o_key->mem->index) o_key->mem->index = c; else errno |= ERR_BASE; /* check base register and index register */ if (o_key->mem->base && o_key->mem->index) if ((o_key->mem->base & 0xf0) != (o_key->mem->index & 0xf0)) errno |= ERR_BASE; /* this is a disp value or scale value */ } else if (is_numeric(str)) { if (is_n(*(p-1)) && (*(p-2) == '*')) { /* scale value */ o_key->mem->scale = get_scaleid(str); if (!o_key->mem->scale) errno |= ERR_SCALE; } else if (!o_key->mem->disp) { /* displacement value */ o_key->mem->disp = str_to_n(str); } else errno |= ERR_DISP; } else { /* illegal operand */ /* errno |= ERR_OPERAND; */ sprintf(tmp_msg, "at %d: parse error at %s\n", line, str); if (str_len(msg) + str_len(tmp_msg) < ERR_MSG_SIZE) { str_cat(msg, tmp_msg); } } i = 0; break; case '-': str[i] = 0; c = get_regid(str); if (check_mreg(c)) { /* valid regiser */ if (!o_key->mem->base) o_key->mem->base = c; else if (!o_key->mem->index) o_key->mem->index = c; else errno |= ERR_BASE; if (o_key->mem->base && o_key->mem->index) if ((o_key->mem->base & 0xf0) != (o_key->mem->index & 0xf0)) errno != ERR_BASE; /*********************************** * TODO: reserved for disp or scale value ***********************************/ } else { /* errno |= ERR_OPERAND; */ sprintf(tmp_msg, "at %d: parse error at %s\n", line, str); if (str_len(msg) + str_len(tmp_msg) < ERR_MSG_SIZE) str_cat(msg, tmp_msg); } /***************************************/ char *tp = p + 1; i = 0; while (*tp && *tp != ']') str[i++] = *tp++; str[i] = 0; if (is_numeric(str) && (!o_key->mem->disp)) o_key->mem->disp = -str_to_n(str); else return errno | ERR_OPERAND; p = tp; i = 0; break; case '*': /* it's a index register */ str[i] = 0; c = get_regid(str); if (check_mreg(c) && !o_key->mem->index) { /* it's index register */ o_key->mem->index = c; if (o_key->mem->base && ((o_key->mem->base & 0xf0) != (o_key->mem->index & 0xf0))) errno |= ERR_BASE; } else errno |= ERR_INDEX; i = 0; break; case '@': /* it's a label string */ if (i) errno |= ERR_OPERAND; /* while (*p != ' ') str[i++] = *p++; str[i] = 0; */ /**************** * mount_hole_link() ***************/ i = 0; break; case 0x09: /* it's a tab */ i = 0; break; case '!': while (*p) p++; continue; default: errno |= ERR_CHARACTER; } p++; } if (errno || str_len(msg)) { if (str_len(msg) == 0) { sprintf(msg, "at %d: ", line); } mount_err_link(errno, ops_errmsg, msg); goto do_error; } str[i] = 0; if (o_key->mem) { /* memory operand */ mem_t *mem = o_key->mem; /* check base register invalid */ /* example: [esp*4+ecx] is invalid */ if (((mem->index == ESP) || (mem->index == RSP)) && mem->scale) { sprintf(msg, "at %d: %s\n", line, "When index register is \"sp\"" "the scale value error"); mount_err_link(0, 0, msg); /* errno |= ERR_BASE; */ goto do_error; } /**** check 16-bit address size ****/ /* In 16-bit address size mode: [bx+bp] or [si+di] are error */ if (((mem->base == BX) && (mem->index == BP)) || ((mem->base == SI) && (mem->index == DI))) { errno |= ERR_BASE; mount_err_link(errno, ops_errmsg, 0); goto do_error; } if (mem->disp) { /* the disp example: [eax+0x0808004] */ /* example: disp is 8bytes and size is 32bit */ if (get_sizeof(o_key->mem->disp) > (current_bits >> 3)) { union { long long ll; /* 64-bit */ short word; /* 16-bit */ int dword; /* 32-bit */ } u; u.ll = o_key->mem->disp; switch (current_bits) { case 16: o_key->mem->disp = u.word; break; case 32: o_key->mem->disp = u.dword; break; } } } /* if: disp */ if (o_key->mem->base) o_key->mem->addr = (o_key->mem->base & 0xf0) >> 1; else if (o_key->mem->index) o_key->mem->addr = (o_key->mem->index & 0xf0) >> 1; /* else o_key->mem->addr = current_bits; */ return errno; } else if (o_key->reg = get_regid(str)) { /* register operand */ /******************** TODO: check_reg() ********************/ } else if (is_numeric(str)) { /* immedeate operand */ /******************* TODO: check_imme() ********************/ if (!o_key->imme) o_key->imme = (imme_t *)a64_malloc(sizeof(imme_t)); o_key->imme->imme_value = (long long)str_to_n(str); /* union{ long l[2]; long long ll; }u; u.ll = o_key->imme->imme_value; printf("--%x%x--\n",u.l[1],u.l[0]); */ unsigned int imme_size = 0; if (o_key->imme->cast > current_bits) errno |= ERR_CAST; else if (o_key->imme->cast) imme_size = o_key->imme->cast; else o_key->imme->cast = get_sizeof(o_key->imme->imme_value) * 8; #if 0 else if (get_sizeof(o_key->imme->imme_value) > (current_bits >> 3)) { imme_size = current_bits; } if (imme_size) { union { long long ll; int dword; short word; } u; u.ll = o_key->imme->imme_value; switch (current_bits) { case 16: o_key->imme->imme_value = u.word; break; case 32: o_key->imme->imme_value = u.dword; } } #endif } else if (is_label(str)) { /* this is a label for "jmp" or "call" */ } else if (is_variable(str)) { /* is a variable value */ /********************************** * TODO: reserved for is_variable() *********************************/ } else { errno |= ERR_OPERAND; mount_err_link(errno, ops_errmsg, 0); } do_error: /* it's not memory operand, so free o_key->mem */ if (o_key->mem) { a64_free(o_key->mem); o_key->mem = 0; } return errno; } /************************************************************* example: parameter: s = "eax,(dword)es:[eax+ecx*8+0xc]" ops_key = get the ops_key_t value for parameter s; return value: error if errno value is set succssed if errno is 0 last change: 02-18-2006 14:20 by mik **************************************************************/ errno_t get_ops_key(ops_key_t *ops_key, char *s) { /* have no operands */ if (!s || !*s) return 0; int i = 0; char str[80]; char trims[200]; errno_t errno = 0; /* return value */ if (!trim_space(trims, s) || !ops_key) return ERR_OPERAND; s = trims; char *p = s + str_len(s) - 1; char *q = s; char tmp_msg[80]; char *msg = get_err_msg_addr(); /* find operands and get operand key word */ while (*p) { q = p; while (*p != ',') { /* search last ',' */ if (p <= s) break; p--; } i = 0; if (*p == ',') { while (p+i+1 <= q) { str[i] = *(p+i+1); i++; } } else if (p == s) { /* head */ while (p+i <= q) { str[i] = *(p+i); i++; } } str[i] = 0; o_key_t *okey = (o_key_t *)a64_malloc(sizeof(o_key_t)); /* get operands key word */ if (!ops_key->so_key) { /* this is a source operand */ ops_key->so_key = okey; } else if (!ops_key->do_key) { /* this is a dest operand */ ops_key->do_key = okey; } else if (!ops_key->to_key) { /* this is a three operand */ ops_key->to_key = okey; } else { a64_free(okey); sprintf(tmp_msg, "at %d: %s\n", line, "operands over three"); if (str_len(msg) + str_len(tmp_msg) < ERR_MSG_SIZE) { str_cat(msg, tmp_msg); mount_err_link(0, 0, msg); } else { errno |= ERR_OPERAND; mount_err_link(errno, ops_errmsg, 0); return errno; } } errno |= get_o_key(okey, str); if (p <= s) break; p--; /* search next operand */ } return errno; } /*********************************************************************** function: unsigned int get_attr(o_key_t* o_key); parameter: o_key: a operand key word return value: unsigned int operand attribute word last change: 02-17-2006 21:10 by mik ***********************************************************************/ unsigned int get_attr(o_key_t *o_key) { if (!o_key) return 0; unsigned int o_attr = 0; if (o_key->reg) { o_attr |= 0x80000000 >> (o_key->reg & 0x07); switch (o_key->reg & 0xf0) { case 0x10: case 0x20: case 0x40: case 0x80: o_attr |= GPR | ((o_key->reg & 0xf0) >> 4); break; case 0xa0: o_attr |= SREG | SIZE16; break; case 0xc0: o_attr |= CREG | SIZE32; break; case 0xd0: o_attr |= DREG | SIZE32; break; case 0xe0: o_attr |= MMX | SIZE64; break; case 0xf0: o_attr |= XMM | SIZE128; break; } } else if (o_key->mem) { if (!o_key->mem->base && !o_key->mem->index) { if (o_key->mem->disp) o_attr |= MOFFSET; } else o_attr |= MEM; /* get memory operand size */ /* example: case is 32 chang to SIZE32 = cast >> 3 */ o_attr |= o_key->mem->cast >> 3; } else if (o_key->imme) { /* immediate operand not size */ if (o_key->imme->imme_value == 1) o_attr |= IMME_1; else o_attr |= IMME; unsigned int size = get_sizeof(o_key->imme->imme_value); /****************************** * TODO: reserved for imme size * example: (dword)0x0c ******************************/ if (o_key->imme->cast) { o_attr |= (o_key->imme->cast >> 3); } else { if (size == 1) o_attr |= 0x01; else if (size <= current_bits) { o_attr |= current_bits >> 3; o_key->imme->cast = current_bits; } } } return o_attr; } /************************************************************************ function: errno get_ops_attr(ops_attr_t *ops_attr, ops_key_t *ops_key); parameter: ops_key: operands key words return value: error if errno is set successed if errno is 0 last change: 02-17-2006 21:32 by mik ************************************************************************/ errno_t get_ops_attr(ops_attr_t *ops_attr, ops_key_t *ops_key) { if (!ops_attr) return ERR_OPERAND; if (!ops_key) { /* no operands */ ops_attr->so_attr = 0; ops_attr->do_attr = 0; ops_attr->to_attr = 0; return 0; } /* source operand is immediate. dest operand is register */ if (ops_key->so_key && ops_key->so_key->imme && ops_key->do_key && ops_key->do_key->reg) { if (get_sizeof(ops_key->so_key->imme->imme_value) > ((ops_key->do_key->reg & 0xf0) >> 4)) { mount_err_link(ERR_OPERAND, ops_errmsg, 0); return ERR_OPERAND; } } ops_attr->so_attr = get_attr(ops_key->so_key); ops_attr->do_attr = get_attr(ops_key->do_key); ops_attr->to_attr = get_attr(ops_key->to_key); if (((OPTYPE(ops_attr->so_attr) == MEM) && (OPTYPE(ops_attr->do_attr) == MEM)) || ((OPTYPE(ops_attr->so_attr) == IMME) && (OPTYPE(ops_attr->do_attr) == IMME))) { mount_err_link(ERR_OPERAND, ops_errmsg, 0); return ERR_OPERAND; } return 0; } /************** the function get operands type ************ last change: 02-18-2006 12:11 by mik ***********************************************************/ ops_type_t get_ops_type(ops_key_t *ops_key) { ops_type_t ops_type = 0; if (!ops_key) return 0; o_key_t *so_key = ops_key->so_key; o_key_t *do_key = ops_key->do_key; o_key_t *to_key = ops_key->to_key; /* get source operand type */ if (so_key) ops_type |= so_key->reg ? S_R : so_key->mem ? S_M : so_key->imme ? S_I : 0; /* get dest operand type */ if (do_key) ops_type |= do_key->reg ? D_R : do_key->mem ? D_M : do_key->imme ? D_I : 0; /* get three operand type */ if (to_key) ops_type |= to_key->reg ? T_R : to_key->mem ? T_M : to_key->imme ? T_I : 0; return ops_type; } unsigned int get_o_size(o_key_t *o_key) { unsigned int o_size = 0; if (!o_key) return 0; if (o_key->reg) o_size = get_reg_size(o_key->reg); else if (o_key->mem) o_size = o_key->mem->cast; else if (o_key->imme) { if (o_key->imme->cast) o_size = o_key->imme->cast; else if (o_key->imme->imme_value == 0) o_size = current_bits; else o_size = get_sizeof(o_key->imme->imme_value) * 8; } return o_size; } /***************************************************************** the function get operands size last change: 02-17-2006 21:54 by mik ******************************************************************/ unsigned int get_ops_size(ops_key_t *ops_key) { unsigned int ops_size = 0; if (!ops_key) return 0; o_key_t *so_key = ops_key->so_key; o_key_t *do_key = ops_key->do_key; o_key_t *to_key = ops_key->to_key; if (so_key && !do_key && !to_key) { /* only one operand */ if (so_key->reg) { ops_size = get_reg_size(so_key->reg); } else if (so_key->mem) { /* only one operand case: * the operand size must be casted */ ops_size = so_key->mem->cast; } else if (so_key->imme) { /************************************** * TODO: reserver for check imme size **************************************/ if (so_key->imme->cast) { ops_size = so_key->imme->cast; } else if (so_key->imme->imme_value == 0) { ops_size = current_bits; } else ops_size = get_sizeof(so_key->imme->imme_value) * 8; } } else if (so_key && do_key && !to_key) { /* two operands */ unsigned int reg_size = 0; if (so_key->reg && do_key->reg) { reg_size = get_reg_size(so_key->reg); if (get_reg_size(do_key->reg) > reg_size) reg_size = get_reg_size(do_key->reg); } else if (so_key->reg) reg_size = get_reg_size(so_key->reg); else if (do_key->reg) reg_size = get_reg_size(do_key->reg); unsigned int mem_size = so_key->mem ? so_key->mem->cast : do_key->mem ? do_key->mem->cast : 0; unsigned int imme_size = so_key->imme ? get_sizeof(so_key->imme->imme_value) * 8 : do_key->imme ? get_sizeof(do_key->imme->imme_value) * 8 : 0; if (reg_size) { if ((mem_size > reg_size) || (imme_size > reg_size)) ops_size = 0; else ops_size = reg_size; } else if (mem_size) { if (imme_size > mem_size) ops_size = 0; else ops_size = mem_size; } else ops_size = 0; } else if (so_key && do_key && to_key) { /* three operands */ ops_size = get_reg_size(to_key->reg); } return ops_size; } /****************************************************** * the function get operands address size * * last change: 02-18-2006 14:40 by mik ******************************************************/ unsigned int get_ops_addr(ops_key_t *ops_key) { unsigned int addr = 0; if (!ops_key) return 0; mem_t *mem = ops_key->so_key && ops_key->so_key->mem ? ops_key->so_key->mem : ops_key->do_key && ops_key->do_key->mem ? ops_key->do_key->mem : ops_key->to_key && ops_key->to_key->mem ? ops_key->to_key->mem : 0; /* if (mem) { addr = mem->base ? (mem->base & 0xf0) >> 1 : mem->index ? (mem->index & 0xf0) >> 1: mem->disp ? get_sizeof(mem->disp) * 8 : 0; } */ addr = mem ? mem->addr : 0; return addr; } /********************************************************* * the function check operand valid * * last change: 02-18-2006 14:15 by mik ********************************************************/ int check_ops_key(ops_key_t *ops_key) { /* have no operand */ if (!ops_key) return 1; int ops_size = get_ops_size(ops_key); int so_size = get_o_size(ops_key->so_key); int do_size = get_o_size(ops_key->do_key); int to_size = get_o_size(ops_key->to_key); int addr = get_ops_addr(ops_key); o_key_t *so_key = ops_key->so_key; o_key_t *do_key = ops_key->do_key; o_key_t *to_key = ops_key->to_key; if ((ops_size >= 64) && (current_bits != 64)) return 0; if ((addr >= 64) && (current_bits != 64)) return 0; if ((so_key && is_eGPR(so_key->reg)) || (do_key && is_eGPR(do_key->reg)) || (to_key && is_eGPR(to_key->reg))) if (current_bits != 64) return 0; switch (get_ops_type(ops_key)) { case D_R|S_R: if (do_size < so_size) return 0; break; case D_M|S_R: if (do_size && (do_size != so_size)) return 0; break; case T_R|D_R|S_I: /* this case for imul Gv, Ev, Iv */ case T_R|D_M|S_I: case T_M|D_R|S_I: /* this case for shld Ev,Gv,Ib */ if (to_size < do_size) return 0; break; case T_M|D_R|S_R: if (do_size < so_size || to_size < do_size) return 0; break; } #if 0 if (ops_size && (ops_size <= current_bits) && (addr <= current_bits)) { if ((current_bits == 64) && addr && (addr <= 16)) return 0; return 1; } else if ((current_bits == 16) && (ops_size < 64)) return 1; #endif return 1; } /*************************************************** follow for test.... ***************************************************/ void release_o_key(o_key_t *o_key); void release_ops_key(ops_key_t *ops_key) { if (ops_key->so_key) release_o_key(ops_key->so_key); if (ops_key->do_key) release_o_key(ops_key->do_key); if (ops_key->to_key) release_o_key(ops_key->to_key); } void release_o_key(o_key_t *o_key) { if (o_key) { if (o_key->mem) free(o_key->mem); free(o_key); } } /****************************************************************/ void print_okey(o_key_t* o_key) { printf("-----------------------------------\n"); printf("reg is %x\n", o_key->reg); printf("imme is %f\n", o_key->imme); union { long long ll; long l[2]; } l; if (o_key->mem) { printf("---base is %x\n", o_key->mem->base); printf("---index is %x\n", o_key->mem->index); printf("---scale is %x\n", o_key->mem->scale); l.ll = o_key->mem->disp; printf("---disp is %x\n", l.l[1]); printf("---disp is %x\n", l.l[0]); printf("---oseg is %x\n", o_key->mem->oseg); printf("---cast is %d\n", o_key->mem->cast); printf("---addr is %d\n", o_key->mem->addr); } printf("-----------------------------------------\n"); } void print_ops(ops_key_t *ops) { if (ops) { if (ops->so_key) print_okey(ops->so_key); if (ops->do_key) print_okey(ops->do_key); if (ops->to_key) print_okey(ops->to_key); } // release_ops_key(ops); } void print_ops_attr(ops_attr_t *ops_attr) { printf("so_attr: %x\n", ops_attr->so_attr); printf("do_attr: %x\n", ops_attr->do_attr); printf("to_attr: %x\n", ops_attr->to_attr); } static void print_ekey(e_key_t *e_key) { while (e_key) { print_ops(e_key->ops_key); puts("**************************************"); e_key = e_key->next; } }