⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i386.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
			   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 + -