symbolS *
expr_build_uconstant (offsetT value)
{
  expressionS e;

  e.X_op = O_constant;
  e.X_add_number = value;
  e.X_unsigned = 1;
  return make_expr_symbol (&e);
}
示例#2
0
static symbolS *
expr_build_binary (operatorT op, symbolS * s1, symbolS * s2)
{
  expressionS e;

  e.X_op = op;
  e.X_add_symbol = s1;
  e.X_op_symbol = s2;
  e.X_add_number = 0;
  return make_expr_symbol (& e);
}
示例#3
0
static void
relax_inc_line_addr (int line_delta, symbolS *to_sym, symbolS *from_sym)
{
  expressionS expr;
  int max_chars;

  expr.X_op = O_subtract;
  expr.X_add_symbol = to_sym;
  expr.X_op_symbol = from_sym;
  expr.X_add_number = 0;

  /* The maximum size of the frag is the line delta with a maximum
     sized address delta.  */
  max_chars = size_inc_line_addr (line_delta, -DWARF2_LINE_MIN_INSN_LENGTH);

  frag_var (rs_dwarf2dbg, max_chars, max_chars, 1,
	    make_expr_symbol (&expr), line_delta, NULL);
}
static void
output_cfi_insn (struct cfi_insn_data *insn)
{
    offsetT offset;
    unsigned int regno;

    switch (insn->insn)
    {
    case DW_CFA_advance_loc:
    {
        symbolS *from = insn->u.ll.lab1;
        symbolS *to = insn->u.ll.lab2;

        if (symbol_get_frag (to) == symbol_get_frag (from))
        {
            addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from);
            addressT scaled = delta / DWARF2_LINE_MIN_INSN_LENGTH;

            if (scaled <= 0x3F)
                out_one (DW_CFA_advance_loc + scaled);
            else if (delta <= 0xFF)
            {
                out_one (DW_CFA_advance_loc1);
                out_one (delta);
            }
            else if (delta <= 0xFFFF)
            {
                out_one (DW_CFA_advance_loc2);
                out_two (delta);
            }
            else
            {
                out_one (DW_CFA_advance_loc4);
                out_four (delta);
            }
        }
        else
        {
            expressionS exp;

            exp.X_op = O_subtract;
            exp.X_add_symbol = to;
            exp.X_op_symbol = from;
            exp.X_add_number = 0;

            /* The code in ehopt.c expects that one byte of the encoding
               is already allocated to the frag.  This comes from the way
               that it scans the .eh_frame section looking first for the
               .byte DW_CFA_advance_loc4.  */
            frag_more (1);

            frag_var (rs_cfa, 4, 0, DWARF2_LINE_MIN_INSN_LENGTH << 3,
                      make_expr_symbol (&exp), frag_now_fix () - 1,
                      (char *) frag_now);
        }
    }
    break;

    case DW_CFA_def_cfa:
        offset = insn->u.ri.offset;
        if (offset < 0)
        {
            out_one (DW_CFA_def_cfa_sf);
            out_uleb128 (insn->u.ri.reg);
            out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT);
        }
        else
        {
            out_one (DW_CFA_def_cfa);
            out_uleb128 (insn->u.ri.reg);
            out_uleb128 (offset);
        }
        break;

    case DW_CFA_def_cfa_register:
    case DW_CFA_undefined:
    case DW_CFA_same_value:
        out_one (insn->insn);
        out_uleb128 (insn->u.r);
        break;

    case DW_CFA_def_cfa_offset:
        offset = insn->u.i;
        if (offset < 0)
        {
            out_one (DW_CFA_def_cfa_offset_sf);
            out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT);
        }
        else
        {
            out_one (DW_CFA_def_cfa_offset);
            out_uleb128 (offset);
        }
        break;

    case DW_CFA_restore:
        regno = insn->u.r;
        if (regno <= 0x3F)
        {
            out_one (DW_CFA_restore + regno);
        }
        else
        {
            out_one (DW_CFA_restore_extended);
            out_uleb128 (regno);
        }
        break;

    case DW_CFA_offset:
        regno = insn->u.ri.reg;
        offset = insn->u.ri.offset / DWARF2_CIE_DATA_ALIGNMENT;
        if (offset < 0)
        {
            out_one (DW_CFA_offset_extended_sf);
            out_uleb128 (regno);
            out_sleb128 (offset);
        }
        else if (regno <= 0x3F)
        {
            out_one (DW_CFA_offset + regno);
            out_uleb128 (offset);
        }
        else
        {
            out_one (DW_CFA_offset_extended);
            out_uleb128 (regno);
            out_uleb128 (offset);
        }
        break;

    case DW_CFA_register:
        out_one (DW_CFA_register);
        out_uleb128 (insn->u.rr.reg1);
        out_uleb128 (insn->u.rr.reg2);
        break;

    case DW_CFA_remember_state:
    case DW_CFA_restore_state:
        out_one (insn->insn);
        break;

    case DW_CFA_GNU_window_save:
        out_one (DW_CFA_GNU_window_save);
        break;

    case CFI_escape:
    {
        struct cfi_escape_data *e;
        for (e = insn->u.esc; e ; e = e->next)
            emit_expr (&e->exp, 1);
        break;
    }

    default:
        abort ();
    }
}
示例#5
0
int
check_eh_frame (expressionS *exp, unsigned int *pnbytes)
{
  struct frame_data
  {
    enum frame_state state;

    int cie_info_ok;
    struct cie_info cie_info;

    symbolS *size_end_sym;
    fragS *loc4_frag;
    int loc4_fix;

    int aug_size;
    int aug_shift;
  };

  static struct frame_data eh_frame_data;
  static struct frame_data debug_frame_data;
  struct frame_data *d;

  /* Don't optimize.  */
  if (flag_traditional_format)
    return 0;

#ifdef md_allow_eh_opt
  if (! md_allow_eh_opt)
    return 0;
#endif

  /* Select the proper section data.  */
  if (strncmp (segment_name (now_seg), ".eh_frame", 9) == 0
      && segment_name (now_seg)[9] != '_')
    d = &eh_frame_data;
  else if (strncmp (segment_name (now_seg), ".debug_frame", 12) == 0)
    d = &debug_frame_data;
  else
    return 0;

  if (d->state >= state_saw_size && S_IS_DEFINED (d->size_end_sym))
    {
      /* We have come to the end of the CIE or FDE.  See below where
         we set saw_size.  We must check this first because we may now
         be looking at the next size.  */
      d->state = state_idle;
    }

  switch (d->state)
    {
    case state_idle:
      if (*pnbytes == 4)
	{
	  /* This might be the size of the CIE or FDE.  We want to know
	     the size so that we don't accidentally optimize across an FDE
	     boundary.  We recognize the size in one of two forms: a
	     symbol which will later be defined as a difference, or a
	     subtraction of two symbols.  Either way, we can tell when we
	     are at the end of the FDE because the symbol becomes defined
	     (in the case of a subtraction, the end symbol, from which the
	     start symbol is being subtracted).  Other ways of describing
	     the size will not be optimized.  */
	  if ((exp->X_op == O_symbol || exp->X_op == O_subtract)
	      && ! S_IS_DEFINED (exp->X_add_symbol))
	    {
	      d->state = state_saw_size;
	      d->size_end_sym = exp->X_add_symbol;
	    }
	}
      break;

    case state_saw_size:
    case state_saw_cie_offset:
      /* Assume whatever form it appears in, it appears atomically.  */
      d->state = (enum frame_state) (d->state + 1);
      break;

    case state_saw_pc_begin:
      /* Decide whether we should see an augmentation.  */
      if (! d->cie_info_ok
	  && ! (d->cie_info_ok = get_cie_info (&d->cie_info)))
	d->state = state_error;
      else if (d->cie_info.z_augmentation)
	{
	  d->state = state_seeing_aug_size;
	  d->aug_size = 0;
	  d->aug_shift = 0;
	}
      else
	d->state = state_wait_loc4;
      break;

    case state_seeing_aug_size:
      /* Bytes == -1 means this comes from an leb128 directive.  */
      if ((int)*pnbytes == -1 && exp->X_op == O_constant)
	{
	  d->aug_size = exp->X_add_number;
	  d->state = state_skipping_aug;
	}
      else if (*pnbytes == 1 && exp->X_op == O_constant)
	{
	  unsigned char byte = exp->X_add_number;
	  d->aug_size |= (byte & 0x7f) << d->aug_shift;
	  d->aug_shift += 7;
	  if ((byte & 0x80) == 0)
	    d->state = state_skipping_aug;
	}
      else
	d->state = state_error;
      if (d->state == state_skipping_aug && d->aug_size == 0)
	d->state = state_wait_loc4;
      break;

    case state_skipping_aug:
      if ((int)*pnbytes < 0)
	d->state = state_error;
      else
	{
	  int left = (d->aug_size -= *pnbytes);
	  if (left == 0)
	    d->state = state_wait_loc4;
	  else if (left < 0)
	    d->state = state_error;
	}
      break;

    case state_wait_loc4:
      if (*pnbytes == 1
	  && exp->X_op == O_constant
	  && exp->X_add_number == DW_CFA_advance_loc4)
	{
	  /* This might be a DW_CFA_advance_loc4.  Record the frag and the
	     position within the frag, so that we can change it later.  */
	  frag_grow (1);
	  d->state = state_saw_loc4;
	  d->loc4_frag = frag_now;
	  d->loc4_fix = frag_now_fix ();
	}
      break;

    case state_saw_loc4:
      d->state = state_wait_loc4;
      if (*pnbytes != 4)
	break;
      if (exp->X_op == O_constant)
	{
	  /* This is a case which we can optimize.  The two symbols being
	     subtracted were in the same frag and the expression was
	     reduced to a constant.  We can do the optimization entirely
	     in this function.  */
	  if (exp->X_add_number < 0x40)
	    {
	      d->loc4_frag->fr_literal[d->loc4_fix]
		= DW_CFA_advance_loc | exp->X_add_number;
	      /* No more bytes needed.  */
	      return 1;
	    }
	  else if (exp->X_add_number < 0x100)
	    {
	      d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc1;
	      *pnbytes = 1;
	    }
	  else if (exp->X_add_number < 0x10000)
	    {
	      d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc2;
	      *pnbytes = 2;
	    }
	}
      else if (exp->X_op == O_subtract && d->cie_info.code_alignment == 1)
	{
	  /* This is a case we can optimize.  The expression was not
	     reduced, so we can not finish the optimization until the end
	     of the assembly.  We set up a variant frag which we handle
	     later.  */
	  frag_var (rs_cfa, 4, 0, 1 << 3, make_expr_symbol (exp),
		    d->loc4_fix, (char *) d->loc4_frag);
	  return 1;
	}
      else if ((exp->X_op == O_divide
		|| exp->X_op == O_right_shift)
	       && d->cie_info.code_alignment > 1)
	{
	  if (symbol_symbolS (exp->X_add_symbol)
	      && symbol_constant_p (exp->X_op_symbol)
	      && S_GET_SEGMENT (exp->X_op_symbol) == absolute_section
	      && ((exp->X_op == O_divide
		   ? *symbol_X_add_number (exp->X_op_symbol)
		   : (offsetT) 1 << *symbol_X_add_number (exp->X_op_symbol))
		  == (offsetT) d->cie_info.code_alignment))
	    {
	      expressionS *symval;

	      symval = symbol_get_value_expression (exp->X_add_symbol);
	      if (symval->X_op == O_subtract)
		{
		  /* This is a case we can optimize as well.  The
		     expression was not reduced, so we can not finish
		     the optimization until the end of the assembly.
		     We set up a variant frag which we handle later.  */
		  frag_var (rs_cfa, 4, 0, d->cie_info.code_alignment << 3,
			    make_expr_symbol (symval),
			    d->loc4_fix, (char *) d->loc4_frag);
		  return 1;
		}
	    }
	}
      break;

    case state_error:
      /* Just skipping everything.  */
      break;
    }

  return 0;
}
示例#6
0
static void
output_cfi_insn (struct cfi_insn_data *insn)
{
  offsetT offset;
  unsigned int regno;

  switch (insn->insn)
    {
    case DW_CFA_advance_loc:
      {
	symbolS *from = insn->u.ll.lab1;
	symbolS *to = insn->u.ll.lab2;

	if (symbol_get_frag (to) == symbol_get_frag (from))
	  {
	    addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from);
	    addressT scaled = delta / DWARF2_LINE_MIN_INSN_LENGTH;

	    if (scaled <= 0x3F)
	      out_one (DW_CFA_advance_loc + scaled);
	    else if (scaled <= 0xFF)
	      {
		out_one (DW_CFA_advance_loc1);
		out_one (scaled);
	      }
	    else if (scaled <= 0xFFFF)
	      {
		out_one (DW_CFA_advance_loc2);
		out_two (scaled);
	      }
	    else
	      {
		out_one (DW_CFA_advance_loc4);
		out_four (scaled);
	      }
	  }
	else
	  {
	    expressionS exp;

	    exp.X_op = O_subtract;
	    exp.X_add_symbol = to;
	    exp.X_op_symbol = from;
	    exp.X_add_number = 0;

	    /* The code in ehopt.c expects that one byte of the encoding
	       is already allocated to the frag.  This comes from the way
	       that it scans the .eh_frame section looking first for the
	       .byte DW_CFA_advance_loc4.  */
	    *frag_more (1) = DW_CFA_advance_loc4;

	    frag_var (rs_cfa, 4, 0, DWARF2_LINE_MIN_INSN_LENGTH << 3,
		      make_expr_symbol (&exp), frag_now_fix () - 1,
		      (char *) frag_now);
	  }
      }
      break;

    case DW_CFA_def_cfa:
      offset = insn->u.ri.offset;
      if (offset < 0)
	{
	  out_one (DW_CFA_def_cfa_sf);
	  out_uleb128 (insn->u.ri.reg);
	  out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT);
	}
      else
	{
	  out_one (DW_CFA_def_cfa);
	  out_uleb128 (insn->u.ri.reg);
	  out_uleb128 (offset);
	}
      break;

    case DW_CFA_def_cfa_register:
    case DW_CFA_undefined:
    case DW_CFA_same_value:
      out_one (insn->insn);
      out_uleb128 (insn->u.r);
      break;

    case DW_CFA_def_cfa_offset:
      offset = insn->u.i;
      if (offset < 0)
	{
	  out_one (DW_CFA_def_cfa_offset_sf);
	  out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT);
	}
      else
	{
	  out_one (DW_CFA_def_cfa_offset);
	  out_uleb128 (offset);
	}
      break;

    case DW_CFA_restore:
      regno = insn->u.r;
      if (regno <= 0x3F)
	{
	  out_one (DW_CFA_restore + regno);
	}
      else
	{
	  out_one (DW_CFA_restore_extended);
	  out_uleb128 (regno);
	}
      break;

    case DW_CFA_offset:
      regno = insn->u.ri.reg;
      offset = insn->u.ri.offset / DWARF2_CIE_DATA_ALIGNMENT;
      if (offset < 0)
	{
	  out_one (DW_CFA_offset_extended_sf);
	  out_uleb128 (regno);
	  out_sleb128 (offset);
	}
      else if (regno <= 0x3F)
	{
	  out_one (DW_CFA_offset + regno);
	  out_uleb128 (offset);
	}
      else
	{
	  out_one (DW_CFA_offset_extended);
	  out_uleb128 (regno);
	  out_uleb128 (offset);
	}
      break;

    case DW_CFA_register:
      out_one (DW_CFA_register);
      out_uleb128 (insn->u.rr.reg1);
      out_uleb128 (insn->u.rr.reg2);
      break;

    case DW_CFA_remember_state:
    case DW_CFA_restore_state:
      out_one (insn->insn);
      break;

    case DW_CFA_GNU_window_save:
      out_one (DW_CFA_GNU_window_save);
      break;

    case CFI_escape:
      {
	struct cfi_escape_data *e;
	for (e = insn->u.esc; e ; e = e->next)
	  emit_expr (&e->exp, 1);
	break;
      }

    case CFI_val_encoded_addr:
      {
        unsigned encoding = insn->u.ea.encoding;
        offsetT encoding_size;

	if (encoding == DW_EH_PE_omit)
	  break;
	out_one (DW_CFA_val_expression);
	out_uleb128 (insn->u.ea.reg);

        switch (encoding & 0x7)
	  {
	  case DW_EH_PE_absptr:
	    encoding_size = DWARF2_ADDR_SIZE (stdoutput);
	    break;
	  case DW_EH_PE_udata2:
	    encoding_size = 2;
	    break;
	  case DW_EH_PE_udata4:
	    encoding_size = 4;
	    break;
	  case DW_EH_PE_udata8:
	    encoding_size = 8;
	    break;
	  default:
	    abort ();
	  }

	/* If the user has requested absolute encoding,
	   then use the smaller DW_OP_addr encoding.  */
	if (insn->u.ea.encoding == DW_EH_PE_absptr)
	  {
	    out_uleb128 (1 + encoding_size);
	    out_one (DW_OP_addr);
	  }
	else
	  {
	    out_uleb128 (1 + 1 + encoding_size);
	    out_one (DW_OP_GNU_encoded_addr);
	    out_one (encoding);

	    if ((encoding & 0x70) == DW_EH_PE_pcrel)
	      {
#if CFI_DIFF_EXPR_OK
		insn->u.ea.exp.X_op = O_subtract;
		insn->u.ea.exp.X_op_symbol = symbol_temp_new_now ();
#elif defined (tc_cfi_emit_pcrel_expr)
		tc_cfi_emit_pcrel_expr (&insn->u.ea.exp, encoding_size);
		break;
#else
		abort ();
#endif
	      }
	  }
	emit_expr (&insn->u.ea.exp, encoding_size);
      }
      break;

    default:
      abort ();
    }
}
示例#7
0
const char *
gas_cgen_parse_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
		       	enum cgen_parse_operand_type want, const char **strP,
		       	int opindex, int opinfo,
		       	enum cgen_parse_operand_result *resultP,
		       	bfd_vma *valueP)
{
#ifdef __STDC__
  /* These are volatile to survive the setjmp.  */
  char * volatile hold;
  enum cgen_parse_operand_result * volatile resultP_1;
  volatile int opinfo_1;
#else
  static char *hold;
  static enum cgen_parse_operand_result *resultP_1;
  int opinfo_1;
#endif
  const char *errmsg;
  expressionS exp;

#ifdef OBJ_COMPLEX_RELC
  volatile int              signed_p = 0;
  symbolS *                 stmp = NULL;
  bfd_reloc_code_real_type  reloc_type;
  const CGEN_OPERAND *      operand;
  fixS                      dummy_fixup;
#endif
  if (want == CGEN_PARSE_OPERAND_INIT)
    {
      gas_cgen_init_parse ();
      return NULL;
    }

  resultP_1 = resultP;
  hold = input_line_pointer;
  input_line_pointer = (char *) *strP;
  opinfo_1 = opinfo;

  /* We rely on md_operand to longjmp back to us.
     This is done via gas_cgen_md_operand.  */
  if (setjmp (expr_jmp_buf) != 0)
    {
      expr_jmp_buf_p = 0;
      input_line_pointer = (char *) hold;
      *resultP_1 = CGEN_PARSE_OPERAND_RESULT_ERROR;
      return _("illegal operand");
    }

  expr_jmp_buf_p = 1;
  expression (&exp);
  expr_jmp_buf_p = 0;
  errmsg = NULL;

  *strP = input_line_pointer;
  input_line_pointer = hold;

#ifdef TC_CGEN_PARSE_FIX_EXP
  opinfo_1 = TC_CGEN_PARSE_FIX_EXP (opinfo_1, & exp);
#endif

  /* FIXME: Need to check `want'.  */

  switch (exp.X_op)
    {
    case O_illegal:
      errmsg = _("illegal operand");
      *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR;
      break;
    case O_absent:
      errmsg = _("missing operand");
      *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR;
      break;
    case O_constant:
      if (want == CGEN_PARSE_OPERAND_SYMBOLIC)
	goto de_fault;
      *valueP = exp.X_add_number;
      *resultP = CGEN_PARSE_OPERAND_RESULT_NUMBER;
      break;
    case O_register:
      *valueP = exp.X_add_number;
      *resultP = CGEN_PARSE_OPERAND_RESULT_REGISTER;
      break;
    de_fault:
    default:
#ifdef OBJ_COMPLEX_RELC
      /* Look up operand, check to see if there's an obvious
	 overflow (this helps disambiguate some insn parses).  */
      operand = cgen_operand_lookup_by_num (cd, opindex);
      errmsg = weak_operand_overflow_check (& exp, operand);

      if (! errmsg)
	{
	  /* Fragment the expression as necessary, and queue a reloc.  */
	  memset (& dummy_fixup, 0, sizeof (fixS));

	  reloc_type = md_cgen_lookup_reloc (0, operand, & dummy_fixup);

	  if (exp.X_op == O_symbol
	      && reloc_type == BFD_RELOC_RELC
	      && exp.X_add_symbol->sy_value.X_op == O_constant
	      && (!exp.X_add_symbol->bsym
		  || (exp.X_add_symbol->bsym->section != expr_section
		      && exp.X_add_symbol->bsym->section != absolute_section
		      && exp.X_add_symbol->bsym->section != undefined_section)))
	    {
	      /* Local labels will have been (eagerly) turned into constants
		 by now, due to the inappropriately deep insight of the
		 expression parser.  Unfortunately make_expr_symbol
		 prematurely dives into the symbol evaluator, and in this
		 case it gets a bad answer, so we manually create the
		 expression symbol we want here.  */
	      stmp = symbol_create (FAKE_LABEL_NAME, expr_section, 0,
				    & zero_address_frag);
	      symbol_set_value_expression (stmp, & exp);
	    }
	  else
	    stmp = make_expr_symbol (& exp);

	  /* If this is a pc-relative RELC operand, we
	     need to subtract "." from the expression.  */
 	  if (reloc_type == BFD_RELOC_RELC
	      && CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_PCREL_ADDR))
 	    stmp = expr_build_binary (O_subtract, stmp, expr_build_dot ());

	  /* FIXME: this is not a perfect heuristic for figuring out
	     whether an operand is signed: it only works when the operand
	     is an immediate. it's not terribly likely that any other
	     values will be signed relocs, but it's possible. */
	  if (operand && (operand->hw_type == HW_H_SINT))
	    signed_p = 1;

	  if (stmp->bsym && (stmp->bsym->section == expr_section)
	      && ! S_IS_LOCAL (stmp))
	    {
	      if (signed_p)
		stmp->bsym->flags |= BSF_SRELC;
	      else
		stmp->bsym->flags |= BSF_RELC;
	    }

	  /* Now package it all up for the fixup emitter.  */
	  exp.X_op = O_symbol;
	  exp.X_op_symbol = 0;
	  exp.X_add_symbol = stmp;
	  exp.X_add_number = 0;

	  /* Re-init rightshift quantity, just in case.  */
	  rightshift = operand->length;
	  queue_fixup_recursively (opindex, opinfo_1, & exp,
				   (reloc_type == BFD_RELOC_RELC) ?
				   & (operand->index_fields) : 0,
				   signed_p, -1);
	}
      * resultP = errmsg
	? CGEN_PARSE_OPERAND_RESULT_ERROR
	: CGEN_PARSE_OPERAND_RESULT_QUEUED;
      *valueP = 0;
#else
      queue_fixup (opindex, opinfo_1, &exp);
      *valueP = 0;
      *resultP = CGEN_PARSE_OPERAND_RESULT_QUEUED;
#endif
      break;
    }

  return errmsg;
}