📄 i386.c
字号:
MAX_PREFIXES, i.seg->seg_name); return; } i.prefix[i.prefixes++] = i.seg->seg_prefix; } } } /* Fill in i.rm.reg or i.rm.regmem field with register operand (if any) based on t->extension_opcode. Again, we must be careful to make sure that segment/control/debug/test registers are coded into the i.rm.reg field. */ if (i.reg_operands) { uint o = (i.types[0] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 0 : (i.types[1] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 1 : 2; /* If there is an extension opcode to put here, the register number must be put into the regmem field. */ if (t->extension_opcode != None) i.rm.regmem = i.regs[o]->reg_num; else i.rm.reg = i.regs[o]->reg_num; /* Now, if no memory operand has set i.rm.mode = 0, 1, 2 we must set it to 3 to indicate this is a register operand int the regmem field */ if (! i.mem_operands) i.rm.mode = 3; } /* Fill in i.rm.reg field with extension opcode (if any). */ if (t->extension_opcode != None) i.rm.reg = t->extension_opcode; } } } } /* Handle conversion of 'int $3' --> special int3 insn. */ if (t->base_opcode == INT_OPCODE && i.imms[0]->X_add_number == 3) { t->base_opcode = INT3_OPCODE; i.imm_operands = 0; } /* We are ready to output the insn. */ { register char * p; /* Output jumps. */ if (t->opcode_modifier & Jump) { int n = i.disps[0]->X_add_number; switch (i.disps[0]->X_seg) { case SEG_ABSOLUTE: if (FITS_IN_SIGNED_BYTE (n)) { p = frag_more (2); p[0] = t->base_opcode; p[1] = n;#if 0 /* leave out 16 bit jumps - pace */ } else if (FITS_IN_SIGNED_WORD (n)) { p = frag_more (4); p[0] = WORD_PREFIX_OPCODE; p[1] = t->base_opcode; md_number_to_chars (&p[2], n, 2);#endif } else { /* It's an absolute dword displacement. */ if (t->base_opcode == JUMP_PC_RELATIVE) { /* pace */ /* unconditional jump */ p = frag_more (5); p[0] = 0xe9; md_number_to_chars (&p[1], n, 4); } else { /* conditional jump */ p = frag_more (6); p[0] = TWO_BYTE_OPCODE_ESCAPE; p[1] = t->base_opcode + 0x10; md_number_to_chars (&p[2], n, 4); } } break; default: /* It's a symbol; end frag & setup for relax. Make sure there are 6 chars left in the current frag; if not we'll have to start a new one. */ /* I caught it failing with obstack_room == 6, so I changed to <= pace */ if (obstack_room (&frags) <= 6) { frag_wane(frag_now); frag_new (0); } p = frag_more (1); p[0] = t->base_opcode; frag_var (rs_machine_dependent, 6, /* 2 opcode/prefix + 4 displacement */ 1, ((uchar) *p == JUMP_PC_RELATIVE ? ENCODE_RELAX_STATE (UNCOND_JUMP, BYTE) : ENCODE_RELAX_STATE (COND_JUMP, BYTE)), i.disps[0]->X_add_symbol, n, p); break; } } else if (t->opcode_modifier & (JumpByte|JumpDword)) { int size = (t->opcode_modifier & JumpByte) ? 1 : 4; int n = i.disps[0]->X_add_number; if (FITS_IN_UNSIGNED_BYTE(t->base_opcode)) { FRAG_APPEND_1_CHAR (t->base_opcode); } else { p = frag_more (2); /* opcode can be at most two bytes */ /* put out high byte first: can't use md_number_to_chars! */ *p++ = (t->base_opcode >> 8) & 0xff; *p = t->base_opcode & 0xff; } p = frag_more (size); switch (i.disps[0]->X_seg) { case SEG_ABSOLUTE: md_number_to_chars (p, n, size); if (size == 1 && ! FITS_IN_SIGNED_BYTE (n)) { as_bad ("loop/jecx only takes byte displacement; %d shortened to %d", n, *p); } break; default: fix_new (frag_now, p - frag_now->fr_literal, size, i.disps[0]->X_add_symbol, i.disps[0]->X_subtract_symbol, i.disps[0]->X_add_number, 1); break; } } else if (t->opcode_modifier & JumpInterSegment) { p = frag_more (1 + 2 + 4); /* 1 opcode; 2 segment; 4 offset */ p[0] = t->base_opcode; if (i.imms[1]->X_seg == SEG_ABSOLUTE) md_number_to_chars (p + 1, i.imms[1]->X_add_number, 4); else fix_new (frag_now, p + 1 - frag_now->fr_literal, 4, i.imms[1]->X_add_symbol, i.imms[1]->X_subtract_symbol, i.imms[1]->X_add_number, 0); if (i.imms[0]->X_seg != SEG_ABSOLUTE) as_bad ("can't handle non absolute segment in long call/jmp"); md_number_to_chars (p + 5, i.imms[0]->X_add_number, 2); } else { /* Output normal instructions here. */ register char *q; /* First the prefix bytes. */ for (q = i.prefix; q < i.prefix + i.prefixes; q++) { p = frag_more (1); md_number_to_chars (p, (uint) *q, 1); } /* Now the opcode; be careful about word order here! */ if (FITS_IN_UNSIGNED_BYTE(t->base_opcode)) { FRAG_APPEND_1_CHAR (t->base_opcode); } else if (FITS_IN_UNSIGNED_WORD(t->base_opcode)) { p = frag_more (2); /* put out high byte first: can't use md_number_to_chars! */ *p++ = (t->base_opcode >> 8) & 0xff; *p = t->base_opcode & 0xff; } else { /* opcode is either 3 or 4 bytes */ if (t->base_opcode & 0xff000000) { p = frag_more (4); *p++ = (t->base_opcode >> 24) & 0xff; } else p = frag_more (3); *p++ = (t->base_opcode >> 16) & 0xff; *p++ = (t->base_opcode >> 8) & 0xff; *p = (t->base_opcode ) & 0xff; } /* Now the modrm byte and base index byte (if present). */ if (t->opcode_modifier & Modrm) { p = frag_more (1); /* md_number_to_chars (p, i.rm, 1); */ md_number_to_chars (p, (i.rm.regmem<<0 | i.rm.reg<<3 | i.rm.mode<<6), 1); /* If i.rm.regmem == ESP (4) && i.rm.mode != Mode 3 (Register mode) ==> need second modrm byte. */ if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING && i.rm.mode != 3) { p = frag_more (1); /* md_number_to_chars (p, i.bi, 1); */ md_number_to_chars (p,(i.bi.base<<0 | i.bi.index<<3 | i.bi.scale<<6), 1); } } if (i.disp_operands) { register int n; for (n = 0; n < i.operands; n++) { if (i.disps[n]) { if (i.disps[n]->X_seg == SEG_ABSOLUTE) { if (i.types[n] & (Disp8|Abs8)) { p = frag_more (1); md_number_to_chars (p, i.disps[n]->X_add_number, 1); } else if (i.types[n] & (Disp16|Abs16)) { p = frag_more (2); md_number_to_chars (p, i.disps[n]->X_add_number, 2); } else { /* Disp32|Abs32 */ p = frag_more (4); md_number_to_chars (p, i.disps[n]->X_add_number, 4); } } else { /* not SEG_ABSOLUTE */ /* need a 32-bit fixup (don't support 8bit non-absolute disps) */ p = frag_more (4); fix_new (frag_now, p - frag_now->fr_literal, 4, i.disps[n]->X_add_symbol, i.disps[n]->X_subtract_symbol, i.disps[n]->X_add_number, 0); } } } } /* end displacement output */ /* output immediate */ if (i.imm_operands) { register int n; for (n = 0; n < i.operands; n++) { if (i.imms[n]) { if (i.imms[n]->X_seg == SEG_ABSOLUTE) { if (i.types[n] & (Imm8|Imm8S)) { p = frag_more (1); md_number_to_chars (p, i.imms[n]->X_add_number, 1); } else if (i.types[n] & Imm16) { p = frag_more (2); md_number_to_chars (p, i.imms[n]->X_add_number, 2); } else { p = frag_more (4); md_number_to_chars (p, i.imms[n]->X_add_number, 4); } } else { /* not SEG_ABSOLUTE */ /* need a 32-bit fixup (don't support 8bit non-absolute ims) */ /* try to support other sizes ... */ int size; if (i.types[n] & (Imm8|Imm8S)) size = 1; else if (i.types[n] & Imm16) size = 2; else size = 4; p = frag_more (size); fix_new (frag_now, p - frag_now->fr_literal, size, i.imms[n]->X_add_symbol, i.imms[n]->X_subtract_symbol, i.imms[n]->X_add_number, 0); } } } } /* end immediate output */ }#ifdef DEBUG386 if (flagseen ['D']) { pi (line, &i); }#endif /* DEBUG386 */ } return;}/* Parse OPERAND_STRING into the i386_insn structure I. Returns non-zero on error. */int i386_operand (operand_string) char *operand_string;{ register char *op_string = operand_string; /* Address of '\0' at end of operand_string. */ char * end_of_operand_string = operand_string + strlen(operand_string); /* Start and end of displacement string expression (if found). */ char * displacement_string_start = 0; char * displacement_string_end; /* We check for an absolute prefix (differentiating, for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */ if (*op_string == ABSOLUTE_PREFIX) { op_string++; i.types[this_operand] |= JumpAbsolute; } /* Check if operand is a register. */ if (*op_string == REGISTER_PREFIX) { register reg_entry * r; if (! (r = parse_register (op_string))) { as_bad ("bad register name ('%s')", op_string); return 0; } /* Check for segment override, rather than segment register by searching for ':' after %<x>s where <x> = s, c, d, e, f, g. */ if ((r->reg_type & (SReg2|SReg3)) && op_string[3] == ':') { switch (r->reg_num) { case 0: i.seg = &es; break; case 1: i.seg = &cs; break; case 2: i.seg = &ss; break; case 3: i.seg = &ds; break; case 4: i.seg = &fs; break; case 5: i.seg = &gs; break; } op_string += 4; /* skip % <x> s : */ operand_string = op_string; /* Pretend given string starts here. */ if (!is_digit_char(*op_string) && !is_identifier_char(*op_string) && *op_string != '(' && *op_string != ABSOLUTE_PREFIX) { as_bad ("bad memory operand after segment override"); return 0; } /* Handle case of %es:*foo. */ if (*op_string == ABSOLUTE_PREFIX) { op_string++; i.types[this_operand] |= JumpAbsolute; } goto do_memory_reference; } i.types[this_operand] |= r->reg_type; i.regs[this_operand] = r; i.reg_operands++; } else if (*op_string == IMMEDIATE_PREFIX) { /* ... or an immediate */ char * save_input_line_pointer; register expressionS *exp; segT exp_seg; if (i.imm_operands == MAX_IMMEDIATE_OPERANDS) { as_bad ("only 1 or 2 immediate operands are allowed"); return 0; } exp = &im_expressions[i.imm_operands++]; i.imms [this_operand] = exp; save_input_line_pointer = input_line_pointer; input_line_pointer = ++op_string; /* must advance op_string! */ exp_seg = expression (exp); input_line_pointer = save_input_line_pointer; switch (exp_seg) { case SEG_NONE: /* missing or bad expr becomes absolute 0 */ as_bad ("missing or invalid immediate expression '%s' taken as 0", operand_string); exp->X_seg = SEG_ABSOLUTE; exp->X_add_number = 0; exp->X_add_symbol = (symbolS *) 0; exp->X_subtract_symbol = (symbolS *) 0; i.types[this_operand] |= Imm; break; case SEG_ABSOLUTE: i.types[this_operand] |= SMALLEST_IMM_TYPE (exp->X_add_number); break; case SEG_TEXT: case SEG_DATA: case SEG_BSS: case SEG_UNKNOWN: i.types[this_operand] |= Imm32; /* this is an address ==> 32bit */ break; default:seg_unimplemented: as_bad ("Unimplemented segment type %d in parse_operand", exp_seg); return 0; } /* shorten this type of this operand if the instruction wants * fewer bits than are present in the immediate. The bit field * code can put out 'andb $0xffffff, %al', for example. pace * also 'movw $foo,(%eax)' */ switch (i.suffix) { case WORD_OPCODE_SUFFIX: i.types[this_operand] |= Imm16; break; case BYTE_OPCODE_SUFFIX: i.types[this_operand] |= Imm16 | Imm8 | Imm8S; break; } } else if (is_digit_char(*op_string) || is_identifier_char(*op_string) || *op_string == '(') { /* This is a memory reference of some sort. */ register char * base_string; uint found_base_index_form; do_memory_reference: if (i.mem_operands == MAX_MEMORY_OPERANDS) { as_bad ("more than 1 memory reference in instruction"); return 0; } i.mem_operands++; /* Determine type of memory operand from opcode_suffix; no opcode suffix implies general memory references. */ switch (i.suffix) { case BYTE_OPCODE_SUFFIX: i.types[this_operand] |= Mem8; break; case WORD_OPCODE_SUFFIX: i.types[this_operand] |= Mem16; break; case DWORD_OPCODE_SUFFIX: default: i.types[this_operand] |= Mem32; } /* Check for base index form. We detect the base index form by looking for an ')' at the end of the operand, searching for the '(' matching it, and finding a REGISTER_PREFIX or ',' after it. */ base_string = end_of_operand_string - 1; found_base_index_form = FALSE; if (*base_string == ')') { uint parens_balenced = 1; /* We've already checked that the number of left & right ()'s are equal, so this loop will not be infinite. */ do { base_string--; if (*base_string == ')') parens_balenced++; if (*base_string == '(') parens_balenced--; } while (parens_balenced); base_string++; /* Skip past '('. */ if (*base_string == REGISTER_PREFIX || *base_string == ',') found_base_index_form = TRUE; } /* If we can't parse a base index register expression, we've found a pure displacement expression. We set up displacement_string_start and displacement_string_end for the code below. */ if (! found_base_index_form) { displacement_string_start = op_string; displacement_string_end = end_of_operand_string; } else { char *base_reg_name, *index_reg_name, *num_string; int num; i.types[this_operand] |= BaseIndex; /* If there is a displacement set-up for it to be parsed later. */ if (base_string != op_string + 1) { displacement_string_start = op_string; displacement_string_end = base_string - 1; } /* Find base register (if any). */ if (*base_string != ',') { base_reg_name = base_string++; /* skip past register name & parse it */ while (isalpha(*base_string)) base_string++; if (base_string == base_reg_name+1) { as_bad ("can't find base register name after '(%c'", REGISTER_PREFIX); return 0; } END_STRING_AND_SAVE (base_string); if (! (i.base_reg = parse_register (base_reg_name))) { as_bad ("bad base register name ('%s')", base_reg_name); return 0; } RESTORE_END_STRING (base_string); } /* Now check seperator; must be ',' ==> index reg OR num ==> no index reg. just scale factor OR ')' ==> end. (scale factor = 1) */ if (*base_string != ',' && *base_string != ')') { as_bad ("expecting ',' or ')' after base register in `%s'", operand_string); return 0; } /* There may index reg here; and there may be a scale factor. */ if (*base_string == ',' && *(base_string+1) == REGISTER_PREFIX) { index_reg_name = ++base_string; while (isalpha(*++base_string)); END_STRING_AND_SAVE (base_string); if (! (i.index_reg = parse_register(index_reg_name))) { as_bad ("bad index register name ('%s')", index_reg_name); return 0; } RESTORE_END_STRING (base_string); } /* Check for scale factor. */ if (*base_string == ',' && isdigit(*(base_string+1))) { num_string = ++base_string; while (is_digit_char(*base_string)) base_string++; if (base_string == num_string) { as_bad ("can't find a scale factor after ','"); return 0; } END_STRING_AND_SAVE (base_string); /* We've got a scale factor. */ if (! sscanf (num_string, "%d", &num)) { as_bad ("can't parse scale factor from '%s'", num_string); return 0; } RESTORE_END_STRING (base_string);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -