📄 i386.c
字号:
if (! prefix) { as_bad ("no such opcode prefix ('%s')", token_start); return; } RESTORE_END_STRING (l); /* check for repeated prefix */ for (q = 0; q < i.prefixes; q++) if (i.prefix[q] == prefix->prefix_code) { as_bad ("same prefix used twice; you don't really want this!"); return; } if (i.prefixes == MAX_PREFIXES) { as_bad ("too many opcode prefixes"); return; } i.prefix[i.prefixes++] = prefix->prefix_code; if (prefix->prefix_code == REPE || prefix->prefix_code == REPNE) expecting_string_instruction = TRUE; /* skip past PREFIX_SEPERATOR and reset token_start */ token_start = ++l; } } END_STRING_AND_SAVE (l); if (token_start == l) { as_bad ("expecting opcode; got nothing"); return; } /* Lookup insn in hash; try intel & att naming conventions if appropriate; that is: we only use the opcode suffix 'b' 'w' or 'l' if we need to. */ current_templates = (templates *) hash_find (op_hash, token_start); if (! current_templates) { int last_index = strlen(token_start) - 1; char last_char = token_start[last_index]; switch (last_char) { case DWORD_OPCODE_SUFFIX: case WORD_OPCODE_SUFFIX: case BYTE_OPCODE_SUFFIX: token_start[last_index] = '\0'; current_templates = (templates *) hash_find (op_hash, token_start); token_start[last_index] = last_char; i.suffix = last_char; } if (!current_templates) { as_bad ("no such 386 instruction: `%s'", token_start); return; } } RESTORE_END_STRING (l); /* check for rep/repne without a string instruction */ if (expecting_string_instruction && ! IS_STRING_INSTRUCTION (current_templates-> start->base_opcode)) { as_bad ("expecting string instruction after rep/repne"); return; } /* There may be operands to parse. */ if (*l != END_OF_INSN && /* For string instructions, we ignore any operands if given. This kludges, for example, 'rep/movsb %ds:(%esi), %es:(%edi)' where the operands are always going to be the same, and are not really encoded in machine code. */ ! IS_STRING_INSTRUCTION (current_templates-> start->base_opcode)) { /* parse operands */ do { /* skip optional white space before operand */ while (! is_operand_char(*l) && *l != END_OF_INSN) { if (! is_space_char(*l)) { as_bad ("invalid character %s before %s operand", output_invalid(*l), ordinal_names[i.operands]); return; } l++; } token_start = l; /* after white space */ paren_not_balenced = 0; while (paren_not_balenced || *l != ',') { if (*l == END_OF_INSN) { if (paren_not_balenced) { as_bad ("unbalenced parenthesis in %s operand.", ordinal_names[i.operands]); return; } else break; /* we are done */ } else if (! is_operand_char(*l)) { as_bad ("invalid character %s in %s operand", output_invalid(*l), ordinal_names[i.operands]); return; } if (*l == '(') ++paren_not_balenced; if (*l == ')') --paren_not_balenced; l++; } if (l != token_start) { /* yes, we've read in another operand */ uint operand_ok; this_operand = i.operands++; if (i.operands > MAX_OPERANDS) { as_bad ("spurious operands; (%d operands/instruction max)", MAX_OPERANDS); return; } /* now parse operand adding info to 'i' as we go along */ END_STRING_AND_SAVE (l); operand_ok = i386_operand (token_start); RESTORE_END_STRING (l); /* restore old contents */ if (!operand_ok) return; } else { if (expecting_operand) { expecting_operand_after_comma: as_bad ("expecting operand after ','; got nothing"); return; } if (*l == ',') { as_bad ("expecting operand before ','; got nothing"); return; } } /* now *l must be either ',' or END_OF_INSN */ if (*l == ',') { if (*++l == END_OF_INSN) { /* just skip it, if it's \n complain */ goto expecting_operand_after_comma; } expecting_operand = TRUE; } } while (*l != END_OF_INSN); /* until we get end of insn */ } } /* Now we've parsed the opcode into a set of templates, and have the operands at hand. Next, we find a template that matches the given insn, making sure the overlap of the given operands types is consistent with the template operand types. */#define MATCH(overlap,given_type) \ (overlap && \ (overlap & (JumpAbsolute|BaseIndex|Mem8)) \ == (given_type & (JumpAbsolute|BaseIndex|Mem8))) /* If m0 and m1 are register matches they must be consistent with the expected operand types t0 and t1. That is, if both m0 & m1 are register matches i.e. ( ((m0 & (Reg)) && (m1 & (Reg)) ) ? then, either 1. or 2. must be true: 1. the expected operand type register overlap is null: (t0 & t1 & Reg) == 0 AND the given register overlap is null: (m0 & m1 & Reg) == 0 2. the expected operand type register overlap == the given operand type overlap: (t0 & t1 & m0 & m1 & Reg). */#define CONSISTENT_REGISTER_MATCH(m0, m1, t0, t1) \ ( ((m0 & (Reg)) && (m1 & (Reg))) ? \ ( ((t0 & t1 & (Reg)) == 0 && (m0 & m1 & (Reg)) == 0) || \ ((t0 & t1) & (m0 & m1) & (Reg)) \ ) : 1) { register uint overlap0, overlap1; expressionS * exp; uint overlap2; uint found_reverse_match; overlap0 = overlap1 = overlap2 = found_reverse_match = 0; for (t = current_templates->start; t < current_templates->end; t++) { /* must have right number of operands */ if (i.operands != t->operands) continue; else if (!t->operands) break; /* 0 operands always matches */ overlap0 = i.types[0] & t->operand_types[0]; switch (t->operands) { case 1: if (! MATCH (overlap0,i.types[0])) continue; break; case 2: case 3: overlap1 = i.types[1] & t->operand_types[1]; if (! MATCH (overlap0,i.types[0]) || ! MATCH (overlap1,i.types[1]) || ! CONSISTENT_REGISTER_MATCH(overlap0, overlap1, t->operand_types[0], t->operand_types[1])) { /* check if other direction is valid ... */ if (! (t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS)) continue; /* try reversing direction of operands */ overlap0 = i.types[0] & t->operand_types[1]; overlap1 = i.types[1] & t->operand_types[0]; if (! MATCH (overlap0,i.types[0]) || ! MATCH (overlap1,i.types[1]) || ! CONSISTENT_REGISTER_MATCH (overlap0, overlap1, t->operand_types[0], t->operand_types[1])) { /* does not match either direction */ continue; } /* found a reverse match here -- slip through */ /* found_reverse_match holds which of D or FloatD we've found */ found_reverse_match = t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS; } /* endif: not forward match */ /* found either forward/reverse 2 operand match here */ if (t->operands == 3) { overlap2 = i.types[2] & t->operand_types[2]; if (! MATCH (overlap2,i.types[2]) || ! CONSISTENT_REGISTER_MATCH (overlap0, overlap2, t->operand_types[0], t->operand_types[2]) || ! CONSISTENT_REGISTER_MATCH (overlap1, overlap2, t->operand_types[1], t->operand_types[2])) continue; } /* found either forward/reverse 2 or 3 operand match here: slip through to break */ } break; /* we've found a match; break out of loop */ } /* for (t = ... */ if (t == current_templates->end) { /* we found no match */ as_bad ("operands given don't match any known 386 instruction"); return; } /* Copy the template we found (we may change it!). */ bcopy (t, &i.tm, sizeof (template)); t = &i.tm; /* alter new copy of template */ /* If there's no opcode suffix we try to invent one based on register operands. */ if (! i.suffix && i.reg_operands) { /* We take i.suffix from the LAST register operand specified. This assumes that the last register operands is the destination register operand. */ int o; for (o = 0; o < MAX_OPERANDS; o++) if (i.types[o] & Reg) { i.suffix = (i.types[o] == Reg8) ? BYTE_OPCODE_SUFFIX : (i.types[o] == Reg16) ? WORD_OPCODE_SUFFIX : DWORD_OPCODE_SUFFIX; } } /* Make still unresolved immediate matches conform to size of immediate given in i.suffix. Note: overlap2 cannot be an immediate! We assume this. */ if ((overlap0 & (Imm8|Imm8S|Imm16|Imm32)) && overlap0 != Imm8 && overlap0 != Imm8S && overlap0 != Imm16 && overlap0 != Imm32) { if (! i.suffix) { as_bad ("no opcode suffix given; can't determine immediate size"); return; } overlap0 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8|Imm8S) : (i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32)); } if ((overlap1 & (Imm8|Imm8S|Imm16|Imm32)) && overlap1 != Imm8 && overlap1 != Imm8S && overlap1 != Imm16 && overlap1 != Imm32) { if (! i.suffix) { as_bad ("no opcode suffix given; can't determine immediate size"); return; } overlap1 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8|Imm8S) : (i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32)); } i.types[0] = overlap0; i.types[1] = overlap1; i.types[2] = overlap2; if (overlap0 & ImplicitRegister) i.reg_operands--; if (overlap1 & ImplicitRegister) i.reg_operands--; if (overlap2 & ImplicitRegister) i.reg_operands--; if (overlap0 & Imm1) i.imm_operands = 0; /* kludge for shift insns */ if (found_reverse_match) { uint save; save = t->operand_types[0]; t->operand_types[0] = t->operand_types[1]; t->operand_types[1] = save; } /* Finalize opcode. First, we change the opcode based on the operand size given by i.suffix: we never have to change things for byte insns, or when no opcode suffix is need to size the operands. */ if (! i.suffix && (t->opcode_modifier & W)) { as_bad ("no opcode suffix given and no register operands; can't size instruction"); return; } if (i.suffix && i.suffix != BYTE_OPCODE_SUFFIX) { /* Select between byte and word/dword operations. */ if (t->opcode_modifier & W) t->base_opcode |= W; /* Now select between word & dword operations via the operand size prefix. */ if (i.suffix == WORD_OPCODE_SUFFIX) { if (i.prefixes == MAX_PREFIXES) { as_bad ("%d prefixes given and 'w' opcode suffix gives too many prefixes", MAX_PREFIXES); return; } i.prefix[i.prefixes++] = WORD_PREFIX_OPCODE; } } /* For insns with operands there are more diddles to do to the opcode. */ if (i.operands) { /* If we found a reverse match we must alter the opcode direction bit found_reverse_match holds bit to set (different for int & float insns). */ if (found_reverse_match) { t->base_opcode |= found_reverse_match; } /* The imul $imm, %reg instruction is converted into imul $imm, %reg, %reg. */ if (t->opcode_modifier & imulKludge) { i.regs[2] = i.regs[1]; /* Pretend we saw the 3 operand case. */ i.reg_operands = 2; } /* Certain instructions expect the destination to be in the i.rm.reg field. This is by far the exceptional case. For these instructions, if the source operand is a register, we must reverse the i.rm.reg and i.rm.regmem fields. We accomplish this by faking that the two register operands were given in the reverse order. */ if ((t->opcode_modifier & ReverseRegRegmem) && i.reg_operands == 2) { uint first_reg_operand = (i.types[0] & Reg) ? 0 : 1; uint second_reg_operand = first_reg_operand + 1; reg_entry *tmp = i.regs[first_reg_operand]; i.regs[first_reg_operand] = i.regs[second_reg_operand]; i.regs[second_reg_operand] = tmp; } if (t->opcode_modifier & ShortForm) { /* The register or float register operand is in operand 0 or 1. */ uint o = (i.types[0] & (Reg|FloatReg)) ? 0 : 1; /* Register goes in low 3 bits of opcode. */ t->base_opcode |= i.regs[o]->reg_num; } else if (t->opcode_modifier & ShortFormW) { /* Short form with 0x8 width bit. Register is always dest. operand */ t->base_opcode |= i.regs[1]->reg_num; if (i.suffix == WORD_OPCODE_SUFFIX || i.suffix == DWORD_OPCODE_SUFFIX) t->base_opcode |= 0x8; } else if (t->opcode_modifier & Seg2ShortForm) { if (t->base_opcode == POP_SEG_SHORT && i.regs[0]->reg_num == 1) { as_bad ("you can't 'pop cs' on the 386."); return; } t->base_opcode |= (i.regs[0]->reg_num << 3); } else if (t->opcode_modifier & Seg3ShortForm) { /* 'push %fs' is 0x0fa0; 'pop %fs' is 0x0fa1. 'push %gs' is 0x0fa8; 'pop %fs' is 0x0fa9. So, only if i.regs[0]->reg_num == 5 (%gs) do we need to change the opcode. */ if (i.regs[0]->reg_num == 5) t->base_opcode |= 0x08; } else if (t->opcode_modifier & Modrm) { /* The opcode is completed (modulo t->extension_opcode which must be put into the modrm byte. Now, we make the modrm & index base bytes based on all the info we've collected. */ /* i.reg_operands MUST be the number of real register operands; implicit registers do not count. */ if (i.reg_operands == 2) { uint source, dest; source = (i.types[0] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 0 : 1; dest = source + 1; i.rm.mode = 3; /* We must be careful to make sure that all segment/control/test/ debug registers go into the i.rm.reg field (despite the whether they are source or destination operands). */ if (i.regs[dest]->reg_type & (SReg2|SReg3|Control|Debug|Test)) { i.rm.reg = i.regs[dest]->reg_num; i.rm.regmem = i.regs[source]->reg_num; } else { i.rm.reg = i.regs[source]->reg_num; i.rm.regmem = i.regs[dest]->reg_num; } } else { /* if it's not 2 reg operands... */ if (i.mem_operands) { uint fake_zero_displacement = FALSE; uint o = (i.types[0] & Mem) ? 0 : ((i.types[1] & Mem) ? 1 : 2); /* Encode memory operand into modrm byte and base index byte. */ if (i.base_reg == esp && ! i.index_reg) { /* <disp>(%esp) becomes two byte modrm with no index register. */ i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; i.rm.mode = MODE_FROM_DISP_SIZE (i.types[o]); i.bi.base = ESP_REG_NUM; i.bi.index = NO_INDEX_REGISTER; i.bi.scale = 0; /* Must be zero! */ } else if (i.base_reg == ebp && !i.index_reg) { if (! (i.types[o] & Disp)) { /* Must fake a zero byte displacement. There is no direct way to code '(%ebp)' directly. */ fake_zero_displacement = TRUE; /* fake_zero_displacement code does not set this. */ i.types[o] |= Disp8; } i.rm.mode = MODE_FROM_DISP_SIZE (i.types[o]); i.rm.regmem = EBP_REG_NUM; } else if (! i.base_reg && (i.types[o] & BaseIndex)) { /* There are three cases here. Case 1: '<32bit disp>(,1)' -- indirect absolute. (Same as cases 2 & 3 with NO index register) Case 2: <32bit disp> (,<index>) -- no base register with disp Case 3: (, <index>) --- no base register; no disp (must add 32bit 0 disp). */ i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; i.rm.mode = 0; /* 32bit mode */ i.bi.base = NO_BASE_REGISTER; i.types[o] &= ~Disp; i.types[o] |= Disp32; /* Must be 32bit! */ if (i.index_reg) { /* case 2 or case 3 */ i.bi.index = i.index_reg->reg_num; i.bi.scale = i.log2_scale_factor; if (i.disp_operands == 0) fake_zero_displacement = TRUE; /* case 3 */ } else { i.bi.index = NO_INDEX_REGISTER; i.bi.scale = 0; } } else if (i.disp_operands && !i.base_reg && !i.index_reg) { /* Operand is just <32bit disp> */ i.rm.regmem = EBP_REG_NUM; i.rm.mode = 0; i.types[o] &= ~Disp; i.types[o] |= Disp32; } else { /* It's not a special case; rev'em up. */ i.rm.regmem = i.base_reg->reg_num; i.rm.mode = MODE_FROM_DISP_SIZE (i.types[o]); if (i.index_reg) { i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; i.bi.base = i.base_reg->reg_num; i.bi.index = i.index_reg->reg_num; i.bi.scale = i.log2_scale_factor; if (i.base_reg == ebp && i.disp_operands == 0) { /* pace */ fake_zero_displacement = TRUE; i.types[o] |= Disp8; i.rm.mode = MODE_FROM_DISP_SIZE (i.types[o]); } } } if (fake_zero_displacement) { /* Fakes a zero displacement assuming that i.types[o] holds the correct displacement size. */ exp = &disp_expressions[i.disp_operands++]; i.disps[o] = exp; exp->X_seg = SEG_ABSOLUTE; exp->X_add_number = 0; exp->X_add_symbol = (symbolS *) 0; exp->X_subtract_symbol = (symbolS *) 0; } /* Select the correct segment for the memory operand. */ if (i.seg) { uint seg_index; seg_entry * default_seg; if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING) { seg_index = (i.rm.mode<<3) | i.bi.base; default_seg = two_byte_segment_defaults [seg_index]; } else { seg_index = (i.rm.mode<<3) | i.rm.regmem; default_seg = one_byte_segment_defaults [seg_index]; } /* If the specified segment is not the default, use an opcode prefix to select it */ if (i.seg != default_seg) { if (i.prefixes == MAX_PREFIXES) { as_bad ("%d prefixes given and %s segment override gives too many prefixes",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -