Ejemplo n.º 1
0
static void
subseg_set_rest (segT seg, subsegT subseg)
{
  frchainS *frcP;		/* crawl frchain chain */
  frchainS **lastPP;		/* address of last pointer */
  frchainS *newP;		/* address of new frchain */
  segment_info_type *seginfo;

  mri_common_symbol = NULL;

  if (frag_now && frchain_now)
    frchain_now->frch_frag_now = frag_now;

  gas_assert (frchain_now == 0
	  || frchain_now->frch_last == frag_now);

  subseg_change (seg, (int) subseg);

  seginfo = seg_info (seg);

  /* Attempt to find or make a frchain for that subsection.
     We keep the list sorted by subsection number.  */
  for (frcP = *(lastPP = &seginfo->frchainP);
       frcP != NULL;
       frcP = *(lastPP = &frcP->frch_next))
    if (frcP->frch_subseg >= subseg)
      break;

  if (frcP == NULL || frcP->frch_subseg != subseg)
    {
      /* This should be the only code that creates a frchainS.  */

      newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS));
      newP->frch_subseg = subseg;
      newP->fix_root = NULL;
      newP->fix_tail = NULL;
      obstack_begin (&newP->frch_obstack, chunksize);
#if __GNUC__ >= 2
      obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
#endif
      newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
      newP->frch_frag_now->fr_type = rs_fill;
      newP->frch_cfi_data = NULL;

      newP->frch_root = newP->frch_last = newP->frch_frag_now;

      *lastPP = newP;
      newP->frch_next = frcP;
      frcP = newP;
    }

  frchain_now = frcP;
  frag_now = frcP->frch_frag_now;

  gas_assert (frchain_now->frch_last == frag_now);
}
Ejemplo n.º 2
0
void
app_pop (char *arg)
{
  register struct app_save *saved = (struct app_save *) arg;

  /* There is no do_scrub_end ().  */
  state = saved->state;
  old_state = saved->old_state;
  out_string = saved->out_string;
  memcpy (out_buf, saved->out_buf, sizeof (out_buf));
  add_newlines = saved->add_newlines;
  if (saved->saved_input == NULL)
    saved_input = NULL;
  else
    {
      gas_assert (saved->saved_input_len <= sizeof (input_buffer));
      memcpy (input_buffer, saved->saved_input, saved->saved_input_len);
      saved_input = input_buffer;
      saved_input_len = saved->saved_input_len;
      free (saved->saved_input);
    }
#ifdef TC_M68K
  scrub_m68k_mri = saved->scrub_m68k_mri;
#endif
  mri_state = saved->mri_state;
  mri_last_ch = saved->mri_last_ch;
#if defined TC_ARM && defined OBJ_ELF
  symver_state = saved->symver_state;
#endif

  free (arg);
}
Ejemplo n.º 3
0
void
dwarf2dbg_convert_frag (fragS *frag)
{
  offsetT addr_diff;

  addr_diff = resolve_symbol_value (frag->fr_symbol);

  /* fr_var carries the max_chars that we created the fragment with.
     fr_subtype carries the current expected length.  We must, of
     course, have allocated enough memory earlier.  */
  gas_assert (frag->fr_var >= (int) frag->fr_subtype);

  if (DWARF2_USE_FIXED_ADVANCE_PC)
    emit_fixed_inc_line_addr (frag->fr_offset, addr_diff, frag,
			      frag->fr_literal + frag->fr_fix,
			      frag->fr_subtype);
  else
    emit_inc_line_addr (frag->fr_offset, addr_diff,
			frag->fr_literal + frag->fr_fix, frag->fr_subtype);

  frag->fr_fix += frag->fr_subtype;
  frag->fr_type = rs_fill;
  frag->fr_var = 0;
  frag->fr_offset = 0;
}
Ejemplo n.º 4
0
static void
sb_build (sb *ptr, int size)
{
  /* See if we can find one to allocate.  */
  sb_element *e;

  gas_assert (size < sb_max_power_two);

  e = free_list.size[size];
  if (!e)
    {
      /* Nothing there, allocate one and stick into the free list.  */
      e = (sb_element *) xmalloc (sizeof (sb_element) + (1 << size));
      e->next = free_list.size[size];
      e->size = 1 << size;
      free_list.size[size] = e;
      string_count[size]++;
    }

  /* Remove from free list.  */
  free_list.size[size] = e->next;

  /* Copy into callers world.  */
  ptr->ptr = e->data;
  ptr->pot = size;
  ptr->len = 0;
  ptr->item = e;
}
Ejemplo n.º 5
0
void
frag_new (int old_frags_var_max_size
	  /* Number of chars (already allocated on obstack frags) in
	     variable_length part of frag.  */)
{
  fragS *former_last_fragP;
  frchainS *frchP;

  gas_assert (frchain_now->frch_last == frag_now);

  /* Fix up old frag's fr_fix.  */
  frag_now->fr_fix = frag_now_fix_octets () - old_frags_var_max_size;
  /* Make sure its type is valid.  */
  gas_assert (frag_now->fr_type != 0);

  /* This will align the obstack so the next struct we allocate on it
     will begin at a correct boundary.  */
  obstack_finish (&frchain_now->frch_obstack);
  frchP = frchain_now;
  know (frchP);
  former_last_fragP = frchP->frch_last;
  gas_assert (former_last_fragP != 0);
  gas_assert (former_last_fragP == frag_now);
  frag_now = frag_alloc (&frchP->frch_obstack);

  as_where (&frag_now->fr_file, &frag_now->fr_line);

  /* Generally, frag_now->points to an address rounded up to next
     alignment.  However, characters will add to obstack frags
     IMMEDIATELY after the struct frag, even if they are not starting
     at an alignment address.  */
  former_last_fragP->fr_next = frag_now;
  frchP->frch_last = frag_now;

#ifndef NO_LISTING
  {
    extern struct list_info_struct *listing_tail;
    frag_now->line = listing_tail;
  }
#endif

  gas_assert (frchain_now->frch_last == frag_now);

  frag_now->fr_next = NULL;
}
Ejemplo n.º 6
0
void
eh_frame_convert_frag (fragS *frag)
{
  offsetT diff;
  fragS *loc4_frag;
  int loc4_fix, ca;

  loc4_frag = (fragS *) frag->fr_opcode;
  loc4_fix = (int) frag->fr_offset;

  diff = resolve_symbol_value (frag->fr_symbol);

  ca = frag->fr_subtype >> 3;
  gas_assert (ca > 0);
  diff /= ca;
  switch (frag->fr_subtype & 7)
    {
    case 0:
      gas_assert (diff < 0x40);
      loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc | diff;
      break;

    case 1:
      gas_assert (diff < 0x100);
      loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1;
      frag->fr_literal[frag->fr_fix] = diff;
      break;

    case 2:
      gas_assert (diff < 0x10000);
      loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc2;
      md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2);
      break;

    default:
      md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4);
      break;
    }

  frag->fr_fix += frag->fr_subtype & 7;
  frag->fr_type = rs_fill;
  frag->fr_subtype = 0;
  frag->fr_offset = 0;
}
Ejemplo n.º 7
0
static struct line_subseg *
get_line_subseg (segT seg, subsegT subseg, bfd_boolean create_p)
{
  static segT last_seg;
  static subsegT last_subseg;
  static struct line_subseg *last_line_subseg;

  struct line_seg *s;
  struct line_subseg **pss, *lss;

  if (seg == last_seg && subseg == last_subseg)
    return last_line_subseg;

  s = (struct line_seg *) hash_find (all_segs_hash, seg->name);
  if (s == NULL)
    {
      if (!create_p)
	return NULL;

      s = (struct line_seg *) xmalloc (sizeof (*s));
      s->next = NULL;
      s->seg = seg;
      s->head = NULL;
      *last_seg_ptr = s;
      last_seg_ptr = &s->next;
      hash_insert (all_segs_hash, seg->name, s);
    }
  gas_assert (seg == s->seg);

  for (pss = &s->head; (lss = *pss) != NULL ; pss = &lss->next)
    {
      if (lss->subseg == subseg)
	goto found_subseg;
      if (lss->subseg > subseg)
	break;
    }

  lss = (struct line_subseg *) xmalloc (sizeof (*lss));
  lss->next = *pss;
  lss->subseg = subseg;
  lss->head = NULL;
  lss->ptail = &lss->head;
  lss->pmove_tail = &lss->head;
  *pss = lss;

 found_subseg:
  last_seg = seg;
  last_subseg = subseg;
  last_line_subseg = lss;

  return lss;
}
Ejemplo n.º 8
0
void
cfi_add_CFA_offset (unsigned regno, offsetT offset)
{
  unsigned int abs_data_align;

  gas_assert (DWARF2_CIE_DATA_ALIGNMENT != 0);
  cfi_add_CFA_insn_reg_offset (DW_CFA_offset, regno, offset);

  abs_data_align = (DWARF2_CIE_DATA_ALIGNMENT < 0
		    ? -DWARF2_CIE_DATA_ALIGNMENT : DWARF2_CIE_DATA_ALIGNMENT);
  if (offset % abs_data_align)
    as_bad (_("register save offset not a multiple of %u"), abs_data_align);
}
Ejemplo n.º 9
0
/* @@ Ick.  */
static segT
fetch_coff_debug_section (void)
{
  static segT debug_section;

  if (!debug_section)
    {
      const asymbol *s;

      s = bfd_make_debug_symbol (stdoutput, NULL, 0);
      gas_assert (s != 0);
      debug_section = s->section;
    }
  return debug_section;
}
Ejemplo n.º 10
0
static const char *
weak_uniquify (const char * name)
{
  char *ret;
  const char * unique = "";

#ifdef TE_PE
  if (an_external_name != NULL)
    unique = an_external_name;
#endif
  gas_assert (weak_is_altname (name));

  ret = xmalloc (strlen (name) + strlen (unique) + 2);
  strcpy (ret, name);
  strcat (ret, ".");
  strcat (ret, unique);
  return ret;
}
Ejemplo n.º 11
0
void
dwarf2dbg_convert_frag (fragS *frag)
{
  offsetT addr_diff;

  if (DWARF2_USE_FIXED_ADVANCE_PC)
    {
      /* If linker relaxation is enabled then the distance bewteen the two
	 symbols in the frag->fr_symbol expression might change.  Hence we
	 cannot rely upon the value computed by resolve_symbol_value.
	 Instead we leave the expression unfinalized and allow
	 emit_fixed_inc_line_addr to create a fixup (which later becomes a
	 relocation) that will allow the linker to correctly compute the
	 actual address difference.  We have to use a fixed line advance for
	 this as we cannot (easily) relocate leb128 encoded values.  */
      int saved_finalize_syms = finalize_syms;

      finalize_syms = 0;
      addr_diff = resolve_symbol_value (frag->fr_symbol);
      finalize_syms = saved_finalize_syms;
    }
  else
    addr_diff = resolve_symbol_value (frag->fr_symbol);

  /* fr_var carries the max_chars that we created the fragment with.
     fr_subtype carries the current expected length.  We must, of
     course, have allocated enough memory earlier.  */
  gas_assert (frag->fr_var >= (int) frag->fr_subtype);

  if (DWARF2_USE_FIXED_ADVANCE_PC)
    emit_fixed_inc_line_addr (frag->fr_offset, addr_diff, frag,
			      frag->fr_literal + frag->fr_fix,
			      frag->fr_subtype);
  else
    emit_inc_line_addr (frag->fr_offset, addr_diff,
			frag->fr_literal + frag->fr_fix, frag->fr_subtype);

  frag->fr_fix += frag->fr_subtype;
  frag->fr_type = rs_fill;
  frag->fr_var = 0;
  frag->fr_offset = 0;
}
Ejemplo n.º 12
0
int
eh_frame_estimate_size_before_relax (fragS *frag)
{
  offsetT diff;
  int ca = frag->fr_subtype >> 3;
  int ret;

  diff = resolve_symbol_value (frag->fr_symbol);

  gas_assert (ca > 0);
  diff /= ca;
  if (diff < 0x40)
    ret = 0;
  else if (diff < 0x100)
    ret = 1;
  else if (diff < 0x10000)
    ret = 2;
  else
    ret = 4;

  frag->fr_subtype = (frag->fr_subtype & ~7) | ret;

  return ret;
}
Ejemplo n.º 13
0
void
input_file_open (const char *filename,
		 int pre)
{
  int c;
  char buf[80];

  preprocess = pre;

  gas_assert (filename != 0);	/* Filename may not be NULL.  */
  if (filename[0])
    {
      f_in = fopen (filename, FOPEN_RT);
      file_name = filename;
    }
  else
    {
      /* Use stdin for the input file.  */
      f_in = stdin;
      /* For error messages.  */
      file_name = _("{standard input}");
    }

  if (f_in == NULL)
    {
      as_bad (_("can't open %s for reading: %s"),
	      file_name, xstrerror (errno));
      return;
    }

  c = getc (f_in);

  if (ferror (f_in))
    {
      as_bad (_("can't read from %s: %s"),
	      file_name, xstrerror (errno));

      fclose (f_in);
      f_in = NULL;
      return;
    }

  /* Check for an empty input file.  */
  if (feof (f_in))
    {
      fclose (f_in);
      f_in = NULL;
      return;
    }
  gas_assert (c != EOF);

  if (c == '#')
    {
      /* Begins with comment, may not want to preprocess.  */
      c = getc (f_in);
      if (c == 'N')
	{
	  if (fgets (buf, sizeof (buf), f_in)
	      && !strncmp (buf, "O_APP", 5) && ISSPACE (buf[5]))
	    preprocess = 0;
	  if (!strchr (buf, '\n'))
	    ungetc ('#', f_in);	/* It was longer.  */
	  else
	    ungetc ('\n', f_in);
	}
      else if (c == 'A')
	{
	  if (fgets (buf, sizeof (buf), f_in)
	      && !strncmp (buf, "PP", 2) && ISSPACE (buf[2]))
	    preprocess = 1;
	  if (!strchr (buf, '\n'))
	    ungetc ('#', f_in);
	  else
	    ungetc ('\n', f_in);
	}
      else if (c == '\n')
	ungetc ('\n', f_in);
      else
	ungetc ('#', f_in);
    }
  else
    ungetc (c, f_in);
}
static int
i386_intel_operand (char *operand_string, int got_a_float)
{
  char *saved_input_line_pointer, *buf;
  segT exp_seg;
  expressionS exp, *expP;
  char suffix = 0;
  int ret;

  /* Initialize state structure.  */
  intel_state.op_modifier = O_absent;
  intel_state.is_mem = 0;
  intel_state.base = NULL;
  intel_state.index = NULL;
  intel_state.seg = NULL;
  operand_type_set (&intel_state.reloc_types, ~0);
  gas_assert (!intel_state.in_offset);
  gas_assert (!intel_state.in_bracket);
  gas_assert (!intel_state.in_scale);

  saved_input_line_pointer = input_line_pointer;
  input_line_pointer = buf = xstrdup (operand_string);

  /* A '$' followed by an identifier char is an identifier.  Otherwise,
     it's operator '.' followed by an expression.  */
  if (*buf == '$' && !is_identifier_char (buf[1]))
    *buf = '.';

  intel_syntax = -1;
  memset (&exp, 0, sizeof(exp));
  exp_seg = expression (&exp);
  ret = i386_intel_simplify (&exp);
  intel_syntax = 1;

  SKIP_WHITESPACE ();
  if (!is_end_of_line[(unsigned char) *input_line_pointer])
    {
      as_bad (_("junk `%s' after expression"), input_line_pointer);
      ret = 0;
    }
  else if (exp.X_op == O_illegal || exp.X_op == O_absent)
    {
      as_bad (_("invalid expression"));
      ret = 0;
    }

  input_line_pointer = saved_input_line_pointer;
  free (buf);

  gas_assert (!intel_state.in_offset);
  gas_assert (!intel_state.in_bracket);
  gas_assert (!intel_state.in_scale);

  if (!ret)
    return 0;

  if (intel_state.op_modifier != O_absent
      && current_templates->start->base_opcode != 0x8d /* lea */)
    {
      i.types[this_operand].bitfield.unspecified = 0;

      switch (intel_state.op_modifier)
	{
	case O_byte_ptr:
	  i.types[this_operand].bitfield.byte = 1;
	  suffix = BYTE_MNEM_SUFFIX;
	  break;

	case O_word_ptr:
	  i.types[this_operand].bitfield.word = 1;
	  if ((current_templates->start->name[0] == 'l'
	       && current_templates->start->name[2] == 's'
	       && current_templates->start->name[3] == 0)
	      || current_templates->start->base_opcode == 0x62 /* bound */)
	    suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
	  else if (got_a_float == 2)	/* "fi..." */
	    suffix = SHORT_MNEM_SUFFIX;
	  else
	    suffix = WORD_MNEM_SUFFIX;
	  break;

	case O_dword_ptr:
	  i.types[this_operand].bitfield.dword = 1;
	  if ((current_templates->start->name[0] == 'l'
	       && current_templates->start->name[2] == 's'
	       && current_templates->start->name[3] == 0)
	      || current_templates->start->base_opcode == 0x62 /* bound */)
	    suffix = WORD_MNEM_SUFFIX;
	  else if (flag_code == CODE_16BIT
		   && (current_templates->start->opcode_modifier.jump
		       || current_templates->start->opcode_modifier.jumpdword))
	    suffix = LONG_DOUBLE_MNEM_SUFFIX;
	  else if (got_a_float == 1)	/* "f..." */
	    suffix = SHORT_MNEM_SUFFIX;
	  else
	    suffix = LONG_MNEM_SUFFIX;
	  break;

	case O_fword_ptr:
	  i.types[this_operand].bitfield.fword = 1;
	  if (current_templates->start->name[0] == 'l'
	      && current_templates->start->name[2] == 's'
	      && current_templates->start->name[3] == 0)
	    suffix = LONG_MNEM_SUFFIX;
	  else if (!got_a_float)
	    {
	      if (flag_code == CODE_16BIT)
		add_prefix (DATA_PREFIX_OPCODE);
	      suffix = LONG_DOUBLE_MNEM_SUFFIX;
	    }
	  else
	    suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
	  break;

	case O_qword_ptr:
	  i.types[this_operand].bitfield.qword = 1;
	  if (current_templates->start->base_opcode == 0x62 /* bound */
	      || got_a_float == 1)	/* "f..." */
	    suffix = LONG_MNEM_SUFFIX;
	  else
	    suffix = QWORD_MNEM_SUFFIX;
	  break;

	case O_tbyte_ptr:
	  i.types[this_operand].bitfield.tbyte = 1;
	  if (got_a_float == 1)
	    suffix = LONG_DOUBLE_MNEM_SUFFIX;
	  else
	    suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
	  break;

	case O_oword_ptr:
	case O_xmmword_ptr:
	  i.types[this_operand].bitfield.xmmword = 1;
	  suffix = XMMWORD_MNEM_SUFFIX;
	  break;

	case O_ymmword_ptr:
	  i.types[this_operand].bitfield.ymmword = 1;
	  suffix = YMMWORD_MNEM_SUFFIX;
	  break;

	case O_far_ptr:
	  suffix = LONG_DOUBLE_MNEM_SUFFIX;
	  /* FALLTHROUGH */
	case O_near_ptr:
	  if (!current_templates->start->opcode_modifier.jump
	      && !current_templates->start->opcode_modifier.jumpdword)
	    suffix = got_a_float /* so it will cause an error */
		     ? BYTE_MNEM_SUFFIX
		     : LONG_DOUBLE_MNEM_SUFFIX;
	  break;

	default:
	  BAD_CASE (intel_state.op_modifier);
	  break;
	}

      if (!i.suffix)
	i.suffix = suffix;
      else if (i.suffix != suffix)
	{
	  as_bad (_("conflicting operand size modifiers"));
	  return 0;
	}
    }

  /* Operands for jump/call need special consideration.  */
  if (current_templates->start->opcode_modifier.jump
      || current_templates->start->opcode_modifier.jumpdword
      || current_templates->start->opcode_modifier.jumpintersegment)
    {
      if (i.op[this_operand].regs || intel_state.base || intel_state.index
	  || intel_state.is_mem > 1)
	i.types[this_operand].bitfield.jumpabsolute = 1;
      else
	switch (intel_state.op_modifier)
	  {
	  case O_near_ptr:
	    if (intel_state.seg)
	      i.types[this_operand].bitfield.jumpabsolute = 1;
	    else
	      intel_state.is_mem = 1;
	    break;
	  case O_far_ptr:
	  case O_absent:
	    if (!intel_state.seg)
	      {
		intel_state.is_mem = 1;
		if (intel_state.op_modifier == O_absent)
		  break;
		as_bad (_("cannot infer the segment part of the operand"));
		return 0;
	      }
	    else if (S_GET_SEGMENT (intel_state.seg) == reg_section)
	      i.types[this_operand].bitfield.jumpabsolute = 1;
	    else
	      {
		i386_operand_type types;

		if (i.imm_operands >= MAX_IMMEDIATE_OPERANDS)
		  {
		    as_bad (_("at most %d immediate operands are allowed"),
			    MAX_IMMEDIATE_OPERANDS);
		    return 0;
		  }
		expP = &im_expressions[i.imm_operands++];
		memset (expP, 0, sizeof(*expP));
		expP->X_op = O_symbol;
		expP->X_add_symbol = intel_state.seg;
		i.op[this_operand].imms = expP;

		resolve_expression (expP);
		operand_type_set (&types, ~0);
		if (!i386_finalize_immediate (S_GET_SEGMENT (intel_state.seg),
					      expP, types, operand_string))
		  return 0;
		if (i.operands < MAX_OPERANDS)
		  {
		    this_operand = i.operands++;
		    i.types[this_operand].bitfield.unspecified = 1;
		  }
		if (suffix == LONG_DOUBLE_MNEM_SUFFIX)
		  i.suffix = 0;
		intel_state.seg = NULL;
		intel_state.is_mem = 0;
	      }
	    break;
	  default:
	    i.types[this_operand].bitfield.jumpabsolute = 1;
	    break;
	  }
      if (i.types[this_operand].bitfield.jumpabsolute)
	intel_state.is_mem |= 1;
    }
  else if (intel_state.seg)
    intel_state.is_mem |= 1;

  if (i.op[this_operand].regs)
    {
      i386_operand_type temp;

      /* Register operand.  */
      if (intel_state.base || intel_state.index || intel_state.seg)
	{
	  as_bad (_("invalid operand"));
	  return 0;
	}

      temp = i.op[this_operand].regs->reg_type;
      temp.bitfield.baseindex = 0;
      i.types[this_operand] = operand_type_or (i.types[this_operand], temp);
      i.types[this_operand].bitfield.unspecified = 0;
      ++i.reg_operands;
    }
  else if (intel_state.base || intel_state.index || intel_state.seg
	   || intel_state.is_mem)
    {
      /* Memory operand.  */
      if (i.mem_operands
	  >= 2 - !current_templates->start->opcode_modifier.isstring)
	{
	  as_bad (_("too many memory references for `%s'"),
		  current_templates->start->name);
	  return 0;
	}

      expP = &disp_expressions[i.disp_operands];
      memcpy (expP, &exp, sizeof(exp));
      resolve_expression (expP);

      if (expP->X_op != O_constant || expP->X_add_number
	  || (!intel_state.base && !intel_state.index))
	{
	  i.op[this_operand].disps = expP;
	  i.disp_operands++;

	  if (flag_code == CODE_64BIT)
	    {
	      i.types[this_operand].bitfield.disp32 = 1;
	      if (!i.prefix[ADDR_PREFIX])
		{
		  i.types[this_operand].bitfield.disp64 = 1;
		  i.types[this_operand].bitfield.disp32s = 1;
		}
	    }
	  else if (!i.prefix[ADDR_PREFIX] ^ (flag_code == CODE_16BIT))
	    i.types[this_operand].bitfield.disp32 = 1;
	  else
	    i.types[this_operand].bitfield.disp16 = 1;

#if defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)
	  /*
	   * exp_seg is used only for verification in
	   * i386_finalize_displacement, and we can end up seeing reg_section
	   * here - but we know we removed all registers from the expression
	   * (or error-ed on any remaining ones) in i386_intel_simplify.  I
	   * consider the check in i386_finalize_displacement bogus anyway, in
	   * particular because it doesn't allow for expr_section, so I'd
	   * rather see that check (and the similar one in
	   * i386_finalize_immediate) use SEG_NORMAL(), but not being an a.out
	   * expert I can't really say whether that would have other bad side
	   * effects.
	   */
	  if (OUTPUT_FLAVOR == bfd_target_aout_flavour
	      && exp_seg == reg_section)
	    exp_seg = expP->X_op != O_constant ? undefined_section
					       : absolute_section;
#endif

	  if (!i386_finalize_displacement (exp_seg, expP,
					   intel_state.reloc_types,
					   operand_string))
	    return 0;
	}

      if (intel_state.base || intel_state.index)
	i.types[this_operand].bitfield.baseindex = 1;

      if (intel_state.seg)
	{
	  for (;;)
	    {
	      expP = symbol_get_value_expression (intel_state.seg);
	      if (expP->X_op != O_full_ptr)
		break;
	      intel_state.seg = expP->X_add_symbol;
	    }
	  if (expP->X_op != O_register)
	    {
	      as_bad (_("segment register name expected"));
	      return 0;
	    }
	  if (!i386_regtab[expP->X_add_number].reg_type.bitfield.sreg2
	      && !i386_regtab[expP->X_add_number].reg_type.bitfield.sreg3)
	    {
	      as_bad (_("invalid use of register"));
	      return 0;
	    }
	  switch (i386_regtab[expP->X_add_number].reg_num)
	    {
	    case 0: i.seg[i.mem_operands] = &es; break;
	    case 1: i.seg[i.mem_operands] = &cs; break;
	    case 2: i.seg[i.mem_operands] = &ss; break;
	    case 3: i.seg[i.mem_operands] = &ds; break;
	    case 4: i.seg[i.mem_operands] = &fs; break;
	    case 5: i.seg[i.mem_operands] = &gs; break;
	    case RegFlat: i.seg[i.mem_operands] = NULL; break;
	    }
	}

      /* Swap base and index in 16-bit memory operands like
	 [si+bx]. Since i386_index_check is also used in AT&T
	 mode we have to do that here.  */
      if (intel_state.base
	  && intel_state.index
	  && intel_state.base->reg_type.bitfield.reg16
	  && intel_state.index->reg_type.bitfield.reg16
	  && intel_state.base->reg_num >= 6
	  && intel_state.index->reg_num < 6)
	{
	  i.base_reg = intel_state.index;
	  i.index_reg = intel_state.base;
	}
      else
	{
	  i.base_reg = intel_state.base;
	  i.index_reg = intel_state.index;
	}

      if (!i386_index_check (operand_string))
	return 0;

      i.types[this_operand].bitfield.mem = 1;
      ++i.mem_operands;
    }
  else
    {
      /* Immediate.  */
      if (i.imm_operands >= MAX_IMMEDIATE_OPERANDS)
	{
	  as_bad (_("at most %d immediate operands are allowed"),
		  MAX_IMMEDIATE_OPERANDS);
	  return 0;
	}

      expP = &im_expressions[i.imm_operands++];
      i.op[this_operand].imms = expP;
      *expP = exp;

      return i386_finalize_immediate (exp_seg, expP, intel_state.reloc_types,
				      operand_string);
    }

  return 1;
}
Ejemplo n.º 15
0
static void
emit_inc_line_addr (int line_delta, addressT addr_delta, char *p, int len)
{
  unsigned int tmp, opcode;
  int need_copy = 0;
  char *end = p + len;

  /* Line number sequences cannot go backward in addresses.  This means
     we've incorrectly ordered the statements in the sequence.  */
  gas_assert ((offsetT) addr_delta >= 0);

  /* Scale the address delta by the minimum instruction length.  */
  scale_addr_delta (&addr_delta);

  /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence.
     We cannot use special opcodes here, since we want the end_sequence
     to emit the matrix entry.  */
  if (line_delta == INT_MAX)
    {
      if (addr_delta == MAX_SPECIAL_ADDR_DELTA)
	*p++ = DW_LNS_const_add_pc;
      else
	{
	  *p++ = DW_LNS_advance_pc;
	  p += output_leb128 (p, addr_delta, 0);
	}

      *p++ = DW_LNS_extended_op;
      *p++ = 1;
      *p++ = DW_LNE_end_sequence;
      goto done;
    }

  /* Bias the line delta by the base.  */
  tmp = line_delta - DWARF2_LINE_BASE;

  /* If the line increment is out of range of a special opcode, we
     must encode it with DW_LNS_advance_line.  */
  if (tmp >= DWARF2_LINE_RANGE)
    {
      *p++ = DW_LNS_advance_line;
      p += output_leb128 (p, line_delta, 1);

      line_delta = 0;
      tmp = 0 - DWARF2_LINE_BASE;
      need_copy = 1;
    }

  /* Prettier, I think, to use DW_LNS_copy instead of a "line +0, addr +0"
     special opcode.  */
  if (line_delta == 0 && addr_delta == 0)
    {
      *p++ = DW_LNS_copy;
      goto done;
    }

  /* Bias the opcode by the special opcode base.  */
  tmp += DWARF2_LINE_OPCODE_BASE;

  /* Avoid overflow when addr_delta is large.  */
  if (addr_delta < 256 + MAX_SPECIAL_ADDR_DELTA)
    {
      /* Try using a special opcode.  */
      opcode = tmp + addr_delta * DWARF2_LINE_RANGE;
      if (opcode <= 255)
	{
	  *p++ = opcode;
	  goto done;
	}

      /* Try using DW_LNS_const_add_pc followed by special op.  */
      opcode = tmp + (addr_delta - MAX_SPECIAL_ADDR_DELTA) * DWARF2_LINE_RANGE;
      if (opcode <= 255)
	{
	  *p++ = DW_LNS_const_add_pc;
	  *p++ = opcode;
	  goto done;
	}
    }

  /* Otherwise use DW_LNS_advance_pc.  */
  *p++ = DW_LNS_advance_pc;
  p += output_leb128 (p, addr_delta, 0);

  if (need_copy)
    *p++ = DW_LNS_copy;
  else
    *p++ = tmp;

 done:
  gas_assert (p == end);
}
Ejemplo n.º 16
0
void
dwarf2_finish (void)
{
  segT line_seg;
  struct line_seg *s;
  segT info_seg;
  int emit_other_sections = 0;
  int empty_debug_line = 0;

  info_seg = bfd_get_section_by_name (stdoutput, ".debug_info");
  emit_other_sections = info_seg == NULL || !seg_not_empty_p (info_seg);

  line_seg = bfd_get_section_by_name (stdoutput, ".debug_line");
  empty_debug_line = line_seg == NULL || !seg_not_empty_p (line_seg);

  /* We can't construct a new debug_line section if we already have one.
     Give an error.  */
  if (all_segs && !empty_debug_line)
    as_fatal ("duplicate .debug_line sections");

  if ((!all_segs && emit_other_sections)
      || (!emit_other_sections && !empty_debug_line))
    /* If there is no line information and no non-empty .debug_info
       section, or if there is both a non-empty .debug_info and a non-empty
       .debug_line, then we do nothing.  */
    return;

  /* Calculate the size of an address for the target machine.  */
  sizeof_address = DWARF2_ADDR_SIZE (stdoutput);

  /* Create and switch to the line number section.  */
  line_seg = subseg_new (".debug_line", 0);
  bfd_set_section_flags (stdoutput, line_seg, SEC_READONLY | SEC_DEBUGGING);

  /* For each subsection, chain the debug entries together.  */
  for (s = all_segs; s; s = s->next)
    {
      struct line_subseg *lss = s->head;
      struct line_entry **ptail = lss->ptail;

      while ((lss = lss->next) != NULL)
	{
	  *ptail = lss->head;
	  ptail = lss->ptail;
	}
    }

  out_debug_line (line_seg);

  /* If this is assembler generated line info, and there is no
     debug_info already, we need .debug_info and .debug_abbrev
     sections as well.  */
  if (emit_other_sections)
    {
      segT abbrev_seg;
      segT aranges_seg;
      segT ranges_seg;

      gas_assert (all_segs);

      info_seg = subseg_new (".debug_info", 0);
      abbrev_seg = subseg_new (".debug_abbrev", 0);
      aranges_seg = subseg_new (".debug_aranges", 0);

      bfd_set_section_flags (stdoutput, info_seg,
			     SEC_READONLY | SEC_DEBUGGING);
      bfd_set_section_flags (stdoutput, abbrev_seg,
			     SEC_READONLY | SEC_DEBUGGING);
      bfd_set_section_flags (stdoutput, aranges_seg,
			     SEC_READONLY | SEC_DEBUGGING);

      record_alignment (aranges_seg, ffs (2 * sizeof_address) - 1);

      if (all_segs->next == NULL)
	ranges_seg = NULL;
      else
	{
	  ranges_seg = subseg_new (".debug_ranges", 0);
	  bfd_set_section_flags (stdoutput, ranges_seg,
				 SEC_READONLY | SEC_DEBUGGING);
	  record_alignment (ranges_seg, ffs (2 * sizeof_address) - 1);
	  out_debug_ranges (ranges_seg);
	}

      out_debug_aranges (aranges_seg, info_seg);
      out_debug_abbrev (abbrev_seg, info_seg, line_seg);
      out_debug_info (info_seg, abbrev_seg, line_seg, ranges_seg);
    }
}
Ejemplo n.º 17
0
static const char *
weak_altname2name (const char * name)
{
  gas_assert (weak_is_altname (name));
  return xstrdup (name + 6);
}
Ejemplo n.º 18
0
static void
emit_fixed_inc_line_addr (int line_delta, addressT addr_delta, fragS *frag,
			  char *p, int len)
{
  expressionS *pexp;
  segT line_seg;
  char *end = p + len;

  /* Line number sequences cannot go backward in addresses.  This means
     we've incorrectly ordered the statements in the sequence.  */
  gas_assert ((offsetT) addr_delta >= 0);

  /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence.  */
  if (line_delta != INT_MAX)
    {
      *p++ = DW_LNS_advance_line;
      p += output_leb128 (p, line_delta, 1);
    }

  pexp = symbol_get_value_expression (frag->fr_symbol);
  line_seg = subseg_get (".debug_line", 0);

  /* The DW_LNS_fixed_advance_pc opcode has a 2-byte operand so it can
     advance the address by at most 64K.  Linker relaxation (without
     which this function would not be used) could change the operand by
     an unknown amount.  If the address increment is getting close to
     the limit, just reset the address.  */
  if (addr_delta > 50000)
    {
      symbolS *to_sym;
      expressionS exp;

      gas_assert (pexp->X_op == O_subtract);
      to_sym = pexp->X_add_symbol;

      *p++ = DW_LNS_extended_op;
      p += output_leb128 (p, sizeof_address + 1, 0);
      *p++ = DW_LNE_set_address;
      exp.X_op = O_symbol;
      exp.X_add_symbol = to_sym;
      exp.X_add_number = 0;
      subseg_change (line_seg, 0);
      emit_expr_fix (&exp, sizeof_address, frag, p);
      p += sizeof_address;
    }
  else
    {
      *p++ = DW_LNS_fixed_advance_pc;
      subseg_change (line_seg, 0);
      emit_expr_fix (pexp, 2, frag, p);
      p += 2;
    }

  if (line_delta == INT_MAX)
    {
      *p++ = DW_LNS_extended_op;
      *p++ = 1;
      *p++ = DW_LNE_end_sequence;
    }
  else
    *p++ = DW_LNS_copy;

  gas_assert (p == end);
}
Ejemplo n.º 19
0
void
coff_frob_symbol (symbolS *symp, int *punt)
{
  static symbolS *last_tagP;
  static stack *block_stack;
  static symbolS *set_end;
  symbolS *next_set_end = NULL;

  if (symp == &abs_symbol)
    {
      *punt = 1;
      return;
    }

  if (current_lineno_sym)
    coff_add_linesym (NULL);

  if (!block_stack)
    block_stack = stack_init (512, sizeof (symbolS*));

#ifdef TE_PE
  if (S_GET_STORAGE_CLASS (symp) == C_NT_WEAK
      && ! S_IS_WEAK (symp)
      && weak_is_altname (S_GET_NAME (symp)))
    {
      /* This is a weak alternate symbol.  All processing of
	 PECOFFweak symbols is done here, through the alternate.  */
      symbolS *weakp = symbol_find_noref (weak_altname2name
					  (S_GET_NAME (symp)), 1);

      gas_assert (weakp);
      gas_assert (S_GET_NUMBER_AUXILIARY (weakp) == 1);

      if (! S_IS_WEAK (weakp))
	{
	  /* The symbol was turned from weak to strong.  Discard altname.  */
	  *punt = 1;
	  return;
	}
      else if (symbol_equated_p (weakp))
	{
	  /* The weak symbol has an alternate specified; symp is unneeded.  */
	  S_SET_STORAGE_CLASS (weakp, C_NT_WEAK);
	  SA_SET_SYM_TAGNDX (weakp,
	    symbol_get_value_expression (weakp)->X_add_symbol);

	  S_CLEAR_EXTERNAL (symp);
	  *punt = 1;
	  return;
	}
      else
	{
	  /* The weak symbol has been assigned an alternate value.
             Copy this value to symp, and set symp as weakp's alternate.  */
	  if (S_GET_STORAGE_CLASS (weakp) != C_NT_WEAK)
	    {
	      S_SET_STORAGE_CLASS (symp, S_GET_STORAGE_CLASS (weakp));
	      S_SET_STORAGE_CLASS (weakp, C_NT_WEAK);
	    }

	  if (S_IS_DEFINED (weakp))
	    {
	      /* This is a defined weak symbol.  Copy value information
	         from the weak symbol itself to the alternate symbol.  */
	      symbol_set_value_expression (symp,
					   symbol_get_value_expression (weakp));
	      symbol_set_frag (symp, symbol_get_frag (weakp));
	      S_SET_SEGMENT (symp, S_GET_SEGMENT (weakp));
	    }
	  else
	    {
	      /* This is an undefined weak symbol.
		 Define the alternate symbol to zero.  */
	      S_SET_VALUE (symp, 0);
	      S_SET_SEGMENT (symp, absolute_section);
	    }

	  S_SET_NAME (symp, weak_uniquify (S_GET_NAME (symp)));
	  S_SET_STORAGE_CLASS (symp, C_EXT);

	  S_SET_VALUE (weakp, 0);
	  S_SET_SEGMENT (weakp, undefined_section);
	}
    }
#else /* TE_PE */
  if (S_IS_WEAK (symp))
    S_SET_STORAGE_CLASS (symp, C_WEAKEXT);
#endif /* TE_PE */

  if (!S_IS_DEFINED (symp)
      && !S_IS_WEAK (symp)
      && S_GET_STORAGE_CLASS (symp) != C_STAT)
    S_SET_STORAGE_CLASS (symp, C_EXT);

  if (!SF_GET_DEBUG (symp))
    {
      symbolS * real;

      if (!SF_GET_LOCAL (symp)
	  && !SF_GET_STATICS (symp)
	  && S_GET_STORAGE_CLASS (symp) != C_LABEL
	  && symbol_constant_p (symp)
	  && (real = symbol_find_noref (S_GET_NAME (symp), 1))
	  && S_GET_STORAGE_CLASS (real) == C_NULL
	  && real != symp)
	{
	  c_symbol_merge (symp, real);
	  *punt = 1;
	  return;
	}

      if (!S_IS_DEFINED (symp) && !SF_GET_LOCAL (symp))
	{
	  gas_assert (S_GET_VALUE (symp) == 0);
	  if (S_IS_WEAKREFD (symp))
	    *punt = 1;
	  else
	    S_SET_EXTERNAL (symp);
	}
      else if (S_GET_STORAGE_CLASS (symp) == C_NULL)
	{
	  if (S_GET_SEGMENT (symp) == text_section
	      && symp != seg_info (text_section)->sym)
	    S_SET_STORAGE_CLASS (symp, C_LABEL);
	  else
	    S_SET_STORAGE_CLASS (symp, C_STAT);
	}

      if (SF_GET_PROCESS (symp))
	{
	  if (S_GET_STORAGE_CLASS (symp) == C_BLOCK)
	    {
	      if (streq (S_GET_NAME (symp), ".bb"))
		stack_push (block_stack, (char *) &symp);
	      else
		{
		  symbolS *begin;

		  begin = *(symbolS **) stack_pop (block_stack);
		  if (begin == 0)
		    as_warn (_("mismatched .eb"));
		  else
		    next_set_end = begin;
		}
	    }

	  if (coff_last_function == 0 && SF_GET_FUNCTION (symp)
	      && S_IS_DEFINED (symp))
	    {
	      union internal_auxent *auxp;

	      coff_last_function = symp;
	      if (S_GET_NUMBER_AUXILIARY (symp) < 1)
		S_SET_NUMBER_AUXILIARY (symp, 1);
	      auxp = SYM_AUXENT (symp);
	      memset (auxp->x_sym.x_fcnary.x_ary.x_dimen, 0,
		      sizeof (auxp->x_sym.x_fcnary.x_ary.x_dimen));
	    }

	  if (S_GET_STORAGE_CLASS (symp) == C_EFCN
	      && S_IS_DEFINED (symp))
	    {
	      if (coff_last_function == 0)
		as_fatal (_("C_EFCN symbol for %s out of scope"),
			  S_GET_NAME (symp));
	      SA_SET_SYM_FSIZE (coff_last_function,
				(long) (S_GET_VALUE (symp)
					- S_GET_VALUE (coff_last_function)));
	      next_set_end = coff_last_function;
	      coff_last_function = 0;
	    }
	}

      if (S_IS_EXTERNAL (symp))
	S_SET_STORAGE_CLASS (symp, C_EXT);
      else if (SF_GET_LOCAL (symp))
	*punt = 1;

      if (SF_GET_FUNCTION (symp))
	symbol_get_bfdsym (symp)->flags |= BSF_FUNCTION;
    }

  /* Double check weak symbols.  */
  if (S_IS_WEAK (symp) && S_IS_COMMON (symp))
    as_bad (_("Symbol `%s' can not be both weak and common"),
	    S_GET_NAME (symp));

  if (SF_GET_TAG (symp))
    last_tagP = symp;
  else if (S_GET_STORAGE_CLASS (symp) == C_EOS)
    next_set_end = last_tagP;

#ifdef OBJ_XCOFF
  /* This is pretty horrible, but we have to set *punt correctly in
     order to call SA_SET_SYM_ENDNDX correctly.  */
  if (! symbol_used_in_reloc_p (symp)
      && ((symbol_get_bfdsym (symp)->flags & BSF_SECTION_SYM) != 0
	  || (! (S_IS_EXTERNAL (symp) || S_IS_WEAK (symp))
	      && ! symbol_get_tc (symp)->output
	      && S_GET_STORAGE_CLASS (symp) != C_FILE)))
    *punt = 1;
#endif

  if (set_end != (symbolS *) NULL
      && ! *punt
      && ((symbol_get_bfdsym (symp)->flags & BSF_NOT_AT_END) != 0
	  || (S_IS_DEFINED (symp)
	      && ! S_IS_COMMON (symp)
	      && (! S_IS_EXTERNAL (symp) || SF_GET_FUNCTION (symp)))))
    {
      SA_SET_SYM_ENDNDX (set_end, symp);
      set_end = NULL;
    }

  if (next_set_end != NULL)
    {
      if (set_end != NULL)
	as_warn (_("Warning: internal error: forgetting to set endndx of %s"),
		 S_GET_NAME (set_end));
      set_end = next_set_end;
    }

#ifndef OBJ_XCOFF
  if (! *punt
      && S_GET_STORAGE_CLASS (symp) == C_FCN
      && streq (S_GET_NAME (symp), ".bf"))
    {
      if (coff_last_bf != NULL)
	SA_SET_SYM_ENDNDX (coff_last_bf, symp);
      coff_last_bf = symp;
    }
#endif
  if (coffsymbol (symbol_get_bfdsym (symp))->lineno)
    {
      int i;
      struct line_no *lptr;
      alent *l;

      lptr = (struct line_no *) coffsymbol (symbol_get_bfdsym (symp))->lineno;
      for (i = 0; lptr; lptr = lptr->next)
	i++;
      lptr = (struct line_no *) coffsymbol (symbol_get_bfdsym (symp))->lineno;

      /* We need i entries for line numbers, plus 1 for the first
	 entry which BFD will override, plus 1 for the last zero
	 entry (a marker for BFD).  */
      l = xmalloc ((i + 2) * sizeof (* l));
      coffsymbol (symbol_get_bfdsym (symp))->lineno = l;
      l[i + 1].line_number = 0;
      l[i + 1].u.sym = NULL;
      for (; i > 0; i--)
	{
	  if (lptr->frag)
	    lptr->l.u.offset += lptr->frag->fr_address / OCTETS_PER_BYTE;
	  l[i] = lptr->l;
	  lptr = lptr->next;
	}
    }
}
Ejemplo n.º 20
0
int
atof_generic (/* return pointer to just AFTER number we read.  */
	      char **address_of_string_pointer,
	      /* At most one per number.  */
	      const char *string_of_decimal_marks,
	      const char *string_of_decimal_exponent_marks,
	      FLONUM_TYPE *address_of_generic_floating_point_number)
{
  int return_value;		/* 0 means OK.  */
  char *first_digit;
  unsigned int number_of_digits_before_decimal;
  unsigned int number_of_digits_after_decimal;
  long decimal_exponent;
  unsigned int number_of_digits_available;
  char digits_sign_char;

  /*
   * Scan the input string, abstracting (1)digits (2)decimal mark (3) exponent.
   * It would be simpler to modify the string, but we don't; just to be nice
   * to caller.
   * We need to know how many digits we have, so we can allocate space for
   * the digits' value.
   */

  char *p;
  char c;
  int seen_significant_digit;

#ifdef ASSUME_DECIMAL_MARK_IS_DOT
  gas_assert (string_of_decimal_marks[0] == '.'
	  && string_of_decimal_marks[1] == 0);
#define IS_DECIMAL_MARK(c)	((c) == '.')
#else
#define IS_DECIMAL_MARK(c)	(0 != strchr (string_of_decimal_marks, (c)))
#endif

  first_digit = *address_of_string_pointer;
  c = *first_digit;

  if (c == '-' || c == '+')
    {
      digits_sign_char = c;
      first_digit++;
    }
  else
    digits_sign_char = '+';

  switch (first_digit[0])
    {
    case 'n':
    case 'N':
      if (!strncasecmp ("nan", first_digit, 3))
	{
	  address_of_generic_floating_point_number->sign = 0;
	  address_of_generic_floating_point_number->exponent = 0;
	  address_of_generic_floating_point_number->leader =
	    address_of_generic_floating_point_number->low;
	  *address_of_string_pointer = first_digit + 3;
	  return 0;
	}
      break;

    case 'i':
    case 'I':
      if (!strncasecmp ("inf", first_digit, 3))
	{
	  address_of_generic_floating_point_number->sign =
	    digits_sign_char == '+' ? 'P' : 'N';
	  address_of_generic_floating_point_number->exponent = 0;
	  address_of_generic_floating_point_number->leader =
	    address_of_generic_floating_point_number->low;

	  first_digit += 3;
	  if (!strncasecmp ("inity", first_digit, 5))
	    first_digit += 5;

	  *address_of_string_pointer = first_digit;

	  return 0;
	}
      break;
    }

  number_of_digits_before_decimal = 0;
  number_of_digits_after_decimal = 0;
  decimal_exponent = 0;
  seen_significant_digit = 0;
  for (p = first_digit;
       (((c = *p) != '\0')
	&& (!c || !IS_DECIMAL_MARK (c))
	&& (!c || !strchr (string_of_decimal_exponent_marks, c)));
       p++)
    {
      if (ISDIGIT (c))
	{
	  if (seen_significant_digit || c > '0')
	    {
	      ++number_of_digits_before_decimal;
	      seen_significant_digit = 1;
	    }
	  else
	    {
	      first_digit++;
	    }
	}
      else
	{
	  break;		/* p -> char after pre-decimal digits.  */
	}
    }				/* For each digit before decimal mark.  */

#ifndef OLD_FLOAT_READS
  /* Ignore trailing 0's after the decimal point.  The original code here
   * (ifdef'd out) does not do this, and numbers like
   *	4.29496729600000000000e+09	(2**31)
   * come out inexact for some reason related to length of the digit
   * string.
   */
  if (c && IS_DECIMAL_MARK (c))
    {
      unsigned int zeros = 0;	/* Length of current string of zeros */

      for (p++; (c = *p) && ISDIGIT (c); p++)
	{
	  if (c == '0')
	    {
	      zeros++;
	    }
	  else
	    {
	      number_of_digits_after_decimal += 1 + zeros;
	      zeros = 0;
	    }
	}
    }
#else
  if (c && IS_DECIMAL_MARK (c))
    {
      for (p++;
	   (((c = *p) != '\0')
	    && (!c || !strchr (string_of_decimal_exponent_marks, c)));
	   p++)
	{
	  if (ISDIGIT (c))
	    {
	      /* This may be retracted below.  */
	      number_of_digits_after_decimal++;

	      if ( /* seen_significant_digit || */ c > '0')
		{
		  seen_significant_digit = TRUE;
		}
	    }
	  else
	    {
	      if (!seen_significant_digit)
		{
		  number_of_digits_after_decimal = 0;
		}
	      break;
	    }
	}			/* For each digit after decimal mark.  */
    }

  while (number_of_digits_after_decimal
	 && first_digit[number_of_digits_before_decimal
			+ number_of_digits_after_decimal] == '0')
    --number_of_digits_after_decimal;
#endif

  if (flag_m68k_mri)
    {
      while (c == '_')
	c = *++p;
    }
  if (c && strchr (string_of_decimal_exponent_marks, c))
    {
      char digits_exponent_sign_char;

      c = *++p;
      if (flag_m68k_mri)
	{
	  while (c == '_')
	    c = *++p;
	}
      if (c && strchr ("+-", c))
	{
	  digits_exponent_sign_char = c;
	  c = *++p;
	}
      else
	{
	  digits_exponent_sign_char = '+';
	}

      for (; (c); c = *++p)
	{
	  if (ISDIGIT (c))
	    {
	      decimal_exponent = decimal_exponent * 10 + c - '0';
	      /*
	       * BUG! If we overflow here, we lose!
	       */
	    }
	  else
	    {
	      break;
	    }
	}

      if (digits_exponent_sign_char == '-')
	{
	  decimal_exponent = -decimal_exponent;
	}
    }

  *address_of_string_pointer = p;

  number_of_digits_available =
    number_of_digits_before_decimal + number_of_digits_after_decimal;
  return_value = 0;
  if (number_of_digits_available == 0)
    {
      address_of_generic_floating_point_number->exponent = 0;	/* Not strictly necessary */
      address_of_generic_floating_point_number->leader
	= -1 + address_of_generic_floating_point_number->low;
      address_of_generic_floating_point_number->sign = digits_sign_char;
      /* We have just concocted (+/-)0.0E0 */

    }
  else
    {
      int count;		/* Number of useful digits left to scan.  */

      LITTLENUM_TYPE *temporary_binary_low = NULL;
      LITTLENUM_TYPE *power_binary_low = NULL;
      LITTLENUM_TYPE *digits_binary_low;
      unsigned int precision;
      unsigned int maximum_useful_digits;
      unsigned int number_of_digits_to_use;
      unsigned int more_than_enough_bits_for_digits;
      unsigned int more_than_enough_littlenums_for_digits;
      unsigned int size_of_digits_in_littlenums;
      unsigned int size_of_digits_in_chars;
      FLONUM_TYPE power_of_10_flonum;
      FLONUM_TYPE digits_flonum;

      precision = (address_of_generic_floating_point_number->high
		   - address_of_generic_floating_point_number->low
		   + 1);	/* Number of destination littlenums.  */

      /* Includes guard bits (two littlenums worth) */
      maximum_useful_digits = (((precision - 2))
			       * ( (LITTLENUM_NUMBER_OF_BITS))
			       * 1000000 / 3321928)
	+ 2;			/* 2 :: guard digits.  */

      if (number_of_digits_available > maximum_useful_digits)
	{
	  number_of_digits_to_use = maximum_useful_digits;
	}
      else
	{
	  number_of_digits_to_use = number_of_digits_available;
	}

      /* Cast these to SIGNED LONG first, otherwise, on systems with
	 LONG wider than INT (such as Alpha OSF/1), unsignedness may
	 cause unexpected results.  */
      decimal_exponent += ((long) number_of_digits_before_decimal
			   - (long) number_of_digits_to_use);

      more_than_enough_bits_for_digits
	= (number_of_digits_to_use * 3321928 / 1000000 + 1);

      more_than_enough_littlenums_for_digits
	= (more_than_enough_bits_for_digits
	   / LITTLENUM_NUMBER_OF_BITS)
	+ 2;

      /* Compute (digits) part. In "12.34E56" this is the "1234" part.
	 Arithmetic is exact here. If no digits are supplied then this
	 part is a 0 valued binary integer.  Allocate room to build up
	 the binary number as littlenums.  We want this memory to
	 disappear when we leave this function.  Assume no alignment
	 problems => (room for n objects) == n * (room for 1
	 object).  */

      size_of_digits_in_littlenums = more_than_enough_littlenums_for_digits;
      size_of_digits_in_chars = size_of_digits_in_littlenums
	* sizeof (LITTLENUM_TYPE);

      digits_binary_low = (LITTLENUM_TYPE *)
	malloc (size_of_digits_in_chars);

      memset ((char *) digits_binary_low, '\0', size_of_digits_in_chars);

      /* Digits_binary_low[] is allocated and zeroed.  */

      /*
       * Parse the decimal digits as if * digits_low was in the units position.
       * Emit a binary number into digits_binary_low[].
       *
       * Use a large-precision version of:
       * (((1st-digit) * 10 + 2nd-digit) * 10 + 3rd-digit ...) * 10 + last-digit
       */

      for (p = first_digit, count = number_of_digits_to_use; count; p++, --count)
	{
	  c = *p;
	  if (ISDIGIT (c))
	    {
	      /*
	       * Multiply by 10. Assume can never overflow.
	       * Add this digit to digits_binary_low[].
	       */

	      long carry;
	      LITTLENUM_TYPE *littlenum_pointer;
	      LITTLENUM_TYPE *littlenum_limit;

	      littlenum_limit = digits_binary_low
		+ more_than_enough_littlenums_for_digits
		- 1;

	      carry = c - '0';	/* char -> binary */

	      for (littlenum_pointer = digits_binary_low;
		   littlenum_pointer <= littlenum_limit;
		   littlenum_pointer++)
		{
		  long work;

		  work = carry + 10 * (long) (*littlenum_pointer);
		  *littlenum_pointer = work & LITTLENUM_MASK;
		  carry = work >> LITTLENUM_NUMBER_OF_BITS;
		}

	      if (carry != 0)
		{
		  /*
		   * We have a GROSS internal error.
		   * This should never happen.
		   */
		  as_fatal (_("failed sanity check"));
		}
	    }
	  else
	    {
	      ++count;		/* '.' doesn't alter digits used count.  */
	    }
	}

      /*
       * Digits_binary_low[] properly encodes the value of the digits.
       * Forget about any high-order littlenums that are 0.
       */
      while (digits_binary_low[size_of_digits_in_littlenums - 1] == 0
	     && size_of_digits_in_littlenums >= 2)
	size_of_digits_in_littlenums--;

      digits_flonum.low = digits_binary_low;
      digits_flonum.high = digits_binary_low + size_of_digits_in_littlenums - 1;
      digits_flonum.leader = digits_flonum.high;
      digits_flonum.exponent = 0;
      /*
       * The value of digits_flonum . sign should not be important.
       * We have already decided the output's sign.
       * We trust that the sign won't influence the other parts of the number!
       * So we give it a value for these reasons:
       * (1) courtesy to humans reading/debugging
       *     these numbers so they don't get excited about strange values
       * (2) in future there may be more meaning attached to sign,
       *     and what was
       *     harmless noise may become disruptive, ill-conditioned (or worse)
       *     input.
       */
      digits_flonum.sign = '+';

      {
	/*
	 * Compute the mantissa (& exponent) of the power of 10.
	 * If successful, then multiply the power of 10 by the digits
	 * giving return_binary_mantissa and return_binary_exponent.
	 */

	int decimal_exponent_is_negative;
	/* This refers to the "-56" in "12.34E-56".  */
	/* FALSE: decimal_exponent is positive (or 0) */
	/* TRUE:  decimal_exponent is negative */
	FLONUM_TYPE temporary_flonum;
	unsigned int size_of_power_in_littlenums;
	unsigned int size_of_power_in_chars;

	size_of_power_in_littlenums = precision;
	/* Precision has a built-in fudge factor so we get a few guard bits.  */

	decimal_exponent_is_negative = decimal_exponent < 0;
	if (decimal_exponent_is_negative)
	  {
	    decimal_exponent = -decimal_exponent;
	  }

	/* From now on: the decimal exponent is > 0. Its sign is separate.  */

	size_of_power_in_chars = size_of_power_in_littlenums
	  * sizeof (LITTLENUM_TYPE) + 2;

	power_binary_low = (LITTLENUM_TYPE *) malloc (size_of_power_in_chars);
	temporary_binary_low = (LITTLENUM_TYPE *) malloc (size_of_power_in_chars);

	memset ((char *) power_binary_low, '\0', size_of_power_in_chars);
	*power_binary_low = 1;
	power_of_10_flonum.exponent = 0;
	power_of_10_flonum.low = power_binary_low;
	power_of_10_flonum.leader = power_binary_low;
	power_of_10_flonum.high = power_binary_low + size_of_power_in_littlenums - 1;
	power_of_10_flonum.sign = '+';
	temporary_flonum.low = temporary_binary_low;
	temporary_flonum.high = temporary_binary_low + size_of_power_in_littlenums - 1;
	/*
	 * (power) == 1.
	 * Space for temporary_flonum allocated.
	 */

	/*
	 * ...
	 *
	 * WHILE	more bits
	 * DO	find next bit (with place value)
	 *	multiply into power mantissa
	 * OD
	 */
	{
	  int place_number_limit;
	  /* Any 10^(2^n) whose "n" exceeds this */
	  /* value will fall off the end of */
	  /* flonum_XXXX_powers_of_ten[].  */
	  int place_number;
	  const FLONUM_TYPE *multiplicand;	/* -> 10^(2^n) */

	  place_number_limit = table_size_of_flonum_powers_of_ten;

	  multiplicand = (decimal_exponent_is_negative
			  ? flonum_negative_powers_of_ten
			  : flonum_positive_powers_of_ten);

	  for (place_number = 1;/* Place value of this bit of exponent.  */
	       decimal_exponent;/* Quit when no more 1 bits in exponent.  */
	       decimal_exponent >>= 1, place_number++)
	    {
	      if (decimal_exponent & 1)
		{
		  if (place_number > place_number_limit)
		    {
		      /* The decimal exponent has a magnitude so great
			 that our tables can't help us fragment it.
			 Although this routine is in error because it
			 can't imagine a number that big, signal an
			 error as if it is the user's fault for
			 presenting such a big number.  */
		      return_value = ERROR_EXPONENT_OVERFLOW;
		      /* quit out of loop gracefully */
		      decimal_exponent = 0;
		    }
		  else
		    {
#ifdef TRACE
		      printf ("before multiply, place_number = %d., power_of_10_flonum:\n",
			      place_number);

		      flonum_print (&power_of_10_flonum);
		      (void) putchar ('\n');
#endif
#ifdef TRACE
		      printf ("multiplier:\n");
		      flonum_print (multiplicand + place_number);
		      (void) putchar ('\n');
#endif
		      flonum_multip (multiplicand + place_number,
				     &power_of_10_flonum, &temporary_flonum);
#ifdef TRACE
		      printf ("after multiply:\n");
		      flonum_print (&temporary_flonum);
		      (void) putchar ('\n');
#endif
		      flonum_copy (&temporary_flonum, &power_of_10_flonum);
#ifdef TRACE
		      printf ("after copy:\n");
		      flonum_print (&power_of_10_flonum);
		      (void) putchar ('\n');
#endif
		    } /* If this bit of decimal_exponent was computable.*/
		} /* If this bit of decimal_exponent was set.  */
	    } /* For each bit of binary representation of exponent */
#ifdef TRACE
	  printf ("after computing power_of_10_flonum:\n");
	  flonum_print (&power_of_10_flonum);
	  (void) putchar ('\n');
#endif
	}
      }

      /*
       * power_of_10_flonum is power of ten in binary (mantissa) , (exponent).
       * It may be the number 1, in which case we don't NEED to multiply.
       *
       * Multiply (decimal digits) by power_of_10_flonum.
       */

      flonum_multip (&power_of_10_flonum, &digits_flonum, address_of_generic_floating_point_number);
      /* Assert sign of the number we made is '+'.  */
      address_of_generic_floating_point_number->sign = digits_sign_char;

      if (temporary_binary_low)
	free (temporary_binary_low);
      if (power_binary_low)
	free (power_binary_low);
      free (digits_binary_low);
    }
Ejemplo n.º 21
0
static int i386_intel_simplify (expressionS *e)
{
  const reg_entry *the_reg = (this_operand >= 0
			      ? i.op[this_operand].regs : NULL);
  const reg_entry *base = intel_state.base;
  const reg_entry *state_index = intel_state.index;
  int ret;

  if (!intel_syntax)
    return 1;

  switch (e->X_op)
    {
    case O_index:
      if (e->X_add_symbol)
	{
	  if (!i386_intel_simplify_symbol (e->X_add_symbol)
	      || !i386_intel_check(the_reg, intel_state.base,
				   intel_state.index))
	    return 0;
	}
      if (!intel_state.in_offset)
	++intel_state.in_bracket;
      ret = i386_intel_simplify_symbol (e->X_op_symbol);
      if (!intel_state.in_offset)
	--intel_state.in_bracket;
      if (!ret)
	return 0;
      if (e->X_add_symbol)
	e->X_op = O_add;
      else
	i386_intel_fold (e, e->X_op_symbol);
      break;

    case O_offset:
      intel_state.has_offset = 1;
      ++intel_state.in_offset;
      ret = i386_intel_simplify_symbol (e->X_add_symbol);
      --intel_state.in_offset;
      if (!ret || !i386_intel_check(the_reg, base, state_index))
	return 0;
      i386_intel_fold (e, e->X_add_symbol);
      return ret;

    case O_byte_ptr:
    case O_word_ptr:
    case O_dword_ptr:
    case O_fword_ptr:
    case O_qword_ptr:
    case O_tbyte_ptr:
    case O_oword_ptr:
    case O_xmmword_ptr:
    case O_ymmword_ptr:
    case O_zmmword_ptr:
    case O_near_ptr:
    case O_far_ptr:
      if (intel_state.op_modifier == O_absent)
	intel_state.op_modifier = e->X_op;
      /* FALLTHROUGH */
    case O_short:
      if (symbol_get_value_expression (e->X_add_symbol)->X_op
	  == O_register)
	{
	  as_bad (_("invalid use of register"));
	  return 0;
	}
      if (!i386_intel_simplify_symbol (e->X_add_symbol))
	return 0;
      i386_intel_fold (e, e->X_add_symbol);
      break;

    case O_full_ptr:
      if (symbol_get_value_expression (e->X_op_symbol)->X_op
	  == O_register)
	{
	  as_bad (_("invalid use of register"));
	  return 0;
	}
      if (!i386_intel_simplify_symbol (e->X_op_symbol)
	  || !i386_intel_check(the_reg, intel_state.base,
			       intel_state.index))
	return 0;
      if (!intel_state.in_offset)
	intel_state.seg = e->X_add_symbol;
      i386_intel_fold (e, e->X_op_symbol);
      break;

    case O_multiply:
      if (this_operand >= 0 && intel_state.in_bracket)
	{
	  expressionS *scale = NULL;
	  int has_index = (intel_state.index != NULL);

	  if (!intel_state.in_scale++)
	    intel_state.scale_factor = 1;

	  ret = i386_intel_simplify_symbol (e->X_add_symbol);
	  if (ret && !has_index && intel_state.index)
	    scale = symbol_get_value_expression (e->X_op_symbol);

	  if (ret)
	    ret = i386_intel_simplify_symbol (e->X_op_symbol);
	  if (ret && !scale && !has_index && intel_state.index)
	    scale = symbol_get_value_expression (e->X_add_symbol);

	  if (ret && scale)
	    {
	      resolve_expression (scale);
	      if (scale->X_op != O_constant
		  || intel_state.index->reg_type.bitfield.reg16)
		scale->X_add_number = 0;
	      intel_state.scale_factor *= scale->X_add_number;
	    }

	  --intel_state.in_scale;
	  if (!ret)
	    return 0;

	  if (!intel_state.in_scale)
	    switch (intel_state.scale_factor)
	      {
	      case 1:
		i.log2_scale_factor = 0;
		break;
	      case 2:
		i.log2_scale_factor = 1;
		break;
	      case 4:
		i.log2_scale_factor = 2;
		break;
	      case 8:
		i.log2_scale_factor = 3;
		break;
	      default:
		/* esp is invalid as index */
		intel_state.index = i386_regtab + REGNAM_EAX + ESP_REG_NUM;
		break;
	      }

	  break;
	}
      goto fallthrough;

    case O_register:
      ret = i386_intel_simplify_register (e);
      if (ret == 2)
	{
	  gas_assert (e->X_add_number < (unsigned short) -1);
	  e->X_md = (unsigned short) e->X_add_number + 1;
	  e->X_op = O_constant;
	  e->X_add_number = 0;
	}
      return ret;

    case O_constant:
      if (e->X_md)
	return i386_intel_simplify_register (e);

      /* FALLTHROUGH */
    default:
fallthrough:
      if (e->X_add_symbol
	  && !i386_intel_simplify_symbol (e->X_add_symbol))
	return 0;
      if (e->X_op == O_add || e->X_op == O_subtract)
	{
	  base = intel_state.base;
	  state_index = intel_state.index;
	}
      if (!i386_intel_check (the_reg, base, state_index)
	  || (e->X_op_symbol
	      && !i386_intel_simplify_symbol (e->X_op_symbol))
	  || !i386_intel_check (the_reg,
				(e->X_op != O_add
				 ? base : intel_state.base),
				(e->X_op != O_add
				 ? state_index : intel_state.index)))
	return 0;
      break;
    }

  if (this_operand >= 0
      && e->X_op == O_symbol
      && !intel_state.in_offset)
    {
      segT seg = S_GET_SEGMENT (e->X_add_symbol);

      if (seg != absolute_section
	  && seg != reg_section
	  && seg != expr_section)
	intel_state.is_mem |= 2 - !intel_state.in_bracket;
    }

  return 1;
}