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

📄 i386.c

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