138889Sjdp/* ehopt.c--optimize gcc exception frame information.
2218822Sdim   Copyright 1998, 2000, 2001, 2003, 2005 Free Software Foundation, Inc.
338889Sjdp   Written by Ian Lance Taylor <ian@cygnus.com>.
438889Sjdp
538889SjdpThis file is part of GAS, the GNU Assembler.
638889Sjdp
738889SjdpGAS is free software; you can redistribute it and/or modify
838889Sjdpit under the terms of the GNU General Public License as published by
938889Sjdpthe Free Software Foundation; either version 2, or (at your option)
1038889Sjdpany later version.
1138889Sjdp
1238889SjdpGAS is distributed in the hope that it will be useful,
1338889Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of
1438889SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1538889SjdpGNU General Public License for more details.
1638889Sjdp
1738889SjdpYou should have received a copy of the GNU General Public License
1838889Sjdpalong with GAS; see the file COPYING.  If not, write to the Free
19218822SdimSoftware Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
20218822Sdim02110-1301, USA.  */
2138889Sjdp
2238889Sjdp#include "as.h"
2338889Sjdp#include "subsegs.h"
2438889Sjdp
2538889Sjdp/* We include this ELF file, even though we may not be assembling for
2638889Sjdp   ELF, since the exception frame information is always in a format
2738889Sjdp   derived from DWARF.  */
2838889Sjdp
2938889Sjdp#include "elf/dwarf2.h"
3038889Sjdp
3138889Sjdp/* Try to optimize gcc 2.8 exception frame information.
3238889Sjdp
3338889Sjdp   Exception frame information is emitted for every function in the
3477298Sobrien   .eh_frame or .debug_frame sections.  Simple information for a function
3577298Sobrien   with no exceptions looks like this:
3638889Sjdp
3738889Sjdp__FRAME_BEGIN__:
3838889Sjdp	.4byte	.LLCIE1	/ Length of Common Information Entry
3938889Sjdp.LSCIE1:
4077298Sobrien#if .eh_frame
4138889Sjdp	.4byte	0x0	/ CIE Identifier Tag
4277298Sobrien#elif .debug_frame
4377298Sobrien	.4byte	0xffffffff / CIE Identifier Tag
4477298Sobrien#endif
4538889Sjdp	.byte	0x1	/ CIE Version
4638889Sjdp	.byte	0x0	/ CIE Augmentation (none)
4738889Sjdp	.byte	0x1	/ ULEB128 0x1 (CIE Code Alignment Factor)
4838889Sjdp	.byte	0x7c	/ SLEB128 -4 (CIE Data Alignment Factor)
4938889Sjdp	.byte	0x8	/ CIE RA Column
5038889Sjdp	.byte	0xc	/ DW_CFA_def_cfa
5138889Sjdp	.byte	0x4	/ ULEB128 0x4
5238889Sjdp	.byte	0x4	/ ULEB128 0x4
5338889Sjdp	.byte	0x88	/ DW_CFA_offset, column 0x8
5438889Sjdp	.byte	0x1	/ ULEB128 0x1
5538889Sjdp	.align 4
5638889Sjdp.LECIE1:
5738889Sjdp	.set	.LLCIE1,.LECIE1-.LSCIE1	/ CIE Length Symbol
5838889Sjdp	.4byte	.LLFDE1	/ FDE Length
5938889Sjdp.LSFDE1:
6038889Sjdp	.4byte	.LSFDE1-__FRAME_BEGIN__	/ FDE CIE offset
6138889Sjdp	.4byte	.LFB1	/ FDE initial location
6238889Sjdp	.4byte	.LFE1-.LFB1	/ FDE address range
6338889Sjdp	.byte	0x4	/ DW_CFA_advance_loc4
6438889Sjdp	.4byte	.LCFI0-.LFB1
6538889Sjdp	.byte	0xe	/ DW_CFA_def_cfa_offset
6638889Sjdp	.byte	0x8	/ ULEB128 0x8
6738889Sjdp	.byte	0x85	/ DW_CFA_offset, column 0x5
6838889Sjdp	.byte	0x2	/ ULEB128 0x2
6938889Sjdp	.byte	0x4	/ DW_CFA_advance_loc4
7038889Sjdp	.4byte	.LCFI1-.LCFI0
7138889Sjdp	.byte	0xd	/ DW_CFA_def_cfa_register
7238889Sjdp	.byte	0x5	/ ULEB128 0x5
7338889Sjdp	.byte	0x4	/ DW_CFA_advance_loc4
7438889Sjdp	.4byte	.LCFI2-.LCFI1
7538889Sjdp	.byte	0x2e	/ DW_CFA_GNU_args_size
7638889Sjdp	.byte	0x4	/ ULEB128 0x4
7738889Sjdp	.byte	0x4	/ DW_CFA_advance_loc4
7838889Sjdp	.4byte	.LCFI3-.LCFI2
7938889Sjdp	.byte	0x2e	/ DW_CFA_GNU_args_size
8038889Sjdp	.byte	0x0	/ ULEB128 0x0
8138889Sjdp	.align 4
8238889Sjdp.LEFDE1:
8338889Sjdp	.set	.LLFDE1,.LEFDE1-.LSFDE1	/ FDE Length Symbol
8438889Sjdp
8538889Sjdp   The immediate issue we can address in the assembler is the
8638889Sjdp   DW_CFA_advance_loc4 followed by a four byte value.  The value is
8738889Sjdp   the difference of two addresses in the function.  Since gcc does
8838889Sjdp   not know this value, it always uses four bytes.  We will know the
8938889Sjdp   value at the end of assembly, so we can do better.  */
9038889Sjdp
9178828Sobrienstruct cie_info
9278828Sobrien{
9378828Sobrien  unsigned code_alignment;
9478828Sobrien  int z_augmentation;
9578828Sobrien};
9638889Sjdp
97130561Sobrienstatic int get_cie_info (struct cie_info *);
9838889Sjdp
9978828Sobrien/* Extract information from the CIE.  */
10078828Sobrien
10138889Sjdpstatic int
102130561Sobrienget_cie_info (struct cie_info *info)
10338889Sjdp{
10438889Sjdp  fragS *f;
10538889Sjdp  fixS *fix;
10638889Sjdp  int offset;
10777298Sobrien  char CIE_id;
10838889Sjdp  char augmentation[10];
10938889Sjdp  int iaug;
11078828Sobrien  int code_alignment = 0;
11138889Sjdp
11277298Sobrien  /* We should find the CIE at the start of the section.  */
11377298Sobrien
11438889Sjdp  f = seg_info (now_seg)->frchainP->frch_root;
11538889Sjdp  fix = seg_info (now_seg)->frchainP->fix_root;
11638889Sjdp
11738889Sjdp  /* Look through the frags of the section to find the code alignment.  */
11838889Sjdp
11977298Sobrien  /* First make sure that the CIE Identifier Tag is 0/-1.  */
12038889Sjdp
12177298Sobrien  if (strcmp (segment_name (now_seg), ".debug_frame") == 0)
12277298Sobrien    CIE_id = (char)0xff;
12377298Sobrien  else
12477298Sobrien    CIE_id = 0;
12577298Sobrien
12638889Sjdp  offset = 4;
12738889Sjdp  while (f != NULL && offset >= f->fr_fix)
12838889Sjdp    {
12938889Sjdp      offset -= f->fr_fix;
13038889Sjdp      f = f->fr_next;
13138889Sjdp    }
13238889Sjdp  if (f == NULL
13338889Sjdp      || f->fr_fix - offset < 4
13477298Sobrien      || f->fr_literal[offset] != CIE_id
13577298Sobrien      || f->fr_literal[offset + 1] != CIE_id
13677298Sobrien      || f->fr_literal[offset + 2] != CIE_id
13777298Sobrien      || f->fr_literal[offset + 3] != CIE_id)
13878828Sobrien    return 0;
13938889Sjdp
14038889Sjdp  /* Next make sure the CIE version number is 1.  */
14138889Sjdp
14238889Sjdp  offset += 4;
14338889Sjdp  while (f != NULL && offset >= f->fr_fix)
14438889Sjdp    {
14538889Sjdp      offset -= f->fr_fix;
14638889Sjdp      f = f->fr_next;
14738889Sjdp    }
14838889Sjdp  if (f == NULL
14938889Sjdp      || f->fr_fix - offset < 1
15038889Sjdp      || f->fr_literal[offset] != 1)
15178828Sobrien    return 0;
15238889Sjdp
15338889Sjdp  /* Skip the augmentation (a null terminated string).  */
15438889Sjdp
15538889Sjdp  iaug = 0;
15638889Sjdp  ++offset;
15738889Sjdp  while (1)
15838889Sjdp    {
15938889Sjdp      while (f != NULL && offset >= f->fr_fix)
16038889Sjdp	{
16138889Sjdp	  offset -= f->fr_fix;
16238889Sjdp	  f = f->fr_next;
16338889Sjdp	}
16438889Sjdp      if (f == NULL)
16578828Sobrien	return 0;
16678828Sobrien
16738889Sjdp      while (offset < f->fr_fix && f->fr_literal[offset] != '\0')
16838889Sjdp	{
16938889Sjdp	  if ((size_t) iaug < (sizeof augmentation) - 1)
17038889Sjdp	    {
17138889Sjdp	      augmentation[iaug] = f->fr_literal[offset];
17238889Sjdp	      ++iaug;
17338889Sjdp	    }
17438889Sjdp	  ++offset;
17538889Sjdp	}
17638889Sjdp      if (offset < f->fr_fix)
17738889Sjdp	break;
17838889Sjdp    }
17938889Sjdp  ++offset;
18038889Sjdp  while (f != NULL && offset >= f->fr_fix)
18138889Sjdp    {
18238889Sjdp      offset -= f->fr_fix;
18338889Sjdp      f = f->fr_next;
18438889Sjdp    }
18538889Sjdp  if (f == NULL)
18678828Sobrien    return 0;
18738889Sjdp
18838889Sjdp  augmentation[iaug] = '\0';
18938889Sjdp  if (augmentation[0] == '\0')
19038889Sjdp    {
19138889Sjdp      /* No augmentation.  */
19238889Sjdp    }
19338889Sjdp  else if (strcmp (augmentation, "eh") == 0)
19438889Sjdp    {
19538889Sjdp      /* We have to skip a pointer.  Unfortunately, we don't know how
19638889Sjdp	 large it is.  We find out by looking for a matching fixup.  */
19738889Sjdp      while (fix != NULL
19838889Sjdp	     && (fix->fx_frag != f || fix->fx_where != offset))
19938889Sjdp	fix = fix->fx_next;
20038889Sjdp      if (fix == NULL)
20138889Sjdp	offset += 4;
20238889Sjdp      else
20338889Sjdp	offset += fix->fx_size;
20438889Sjdp      while (f != NULL && offset >= f->fr_fix)
20538889Sjdp	{
20638889Sjdp	  offset -= f->fr_fix;
20738889Sjdp	  f = f->fr_next;
20838889Sjdp	}
20938889Sjdp      if (f == NULL)
21078828Sobrien	return 0;
21138889Sjdp    }
21278828Sobrien  else if (augmentation[0] != 'z')
21378828Sobrien    return 0;
21438889Sjdp
21538889Sjdp  /* We're now at the code alignment factor, which is a ULEB128.  If
21638889Sjdp     it isn't a single byte, forget it.  */
21738889Sjdp
21838889Sjdp  code_alignment = f->fr_literal[offset] & 0xff;
21978828Sobrien  if ((code_alignment & 0x80) != 0)
22078828Sobrien    code_alignment = 0;
22138889Sjdp
22278828Sobrien  info->code_alignment = code_alignment;
22378828Sobrien  info->z_augmentation = (augmentation[0] == 'z');
22478828Sobrien
22578828Sobrien  return 1;
22638889Sjdp}
22738889Sjdp
22838889Sjdp/* This function is called from emit_expr.  It looks for cases which
22938889Sjdp   we can optimize.
23038889Sjdp
23138889Sjdp   Rather than try to parse all this information as we read it, we
23238889Sjdp   look for a single byte DW_CFA_advance_loc4 followed by a 4 byte
23338889Sjdp   difference.  We turn that into a rs_cfa_advance frag, and handle
23438889Sjdp   those frags at the end of the assembly.  If the gcc output changes
23538889Sjdp   somewhat, this optimization may stop working.
23638889Sjdp
23738889Sjdp   This function returns non-zero if it handled the expression and
23838889Sjdp   emit_expr should not do anything, or zero otherwise.  It can also
23938889Sjdp   change *EXP and *PNBYTES.  */
24038889Sjdp
24138889Sjdpint
242130561Sobriencheck_eh_frame (expressionS *exp, unsigned int *pnbytes)
24338889Sjdp{
24477298Sobrien  struct frame_data
24577298Sobrien  {
24678828Sobrien    enum frame_state
24778828Sobrien    {
24878828Sobrien      state_idle,
24978828Sobrien      state_saw_size,
25078828Sobrien      state_saw_cie_offset,
25178828Sobrien      state_saw_pc_begin,
25278828Sobrien      state_seeing_aug_size,
25378828Sobrien      state_skipping_aug,
25478828Sobrien      state_wait_loc4,
25578828Sobrien      state_saw_loc4,
25678828Sobrien      state_error,
25778828Sobrien    } state;
25878828Sobrien
25978828Sobrien    int cie_info_ok;
26078828Sobrien    struct cie_info cie_info;
26178828Sobrien
26277298Sobrien    symbolS *size_end_sym;
26377298Sobrien    fragS *loc4_frag;
26477298Sobrien    int loc4_fix;
26578828Sobrien
26678828Sobrien    int aug_size;
26778828Sobrien    int aug_shift;
26877298Sobrien  };
26938889Sjdp
27077298Sobrien  static struct frame_data eh_frame_data;
27177298Sobrien  static struct frame_data debug_frame_data;
27277298Sobrien  struct frame_data *d;
27377298Sobrien
27477298Sobrien  /* Don't optimize.  */
27577298Sobrien  if (flag_traditional_format)
27677298Sobrien    return 0;
27777298Sobrien
27877298Sobrien  /* Select the proper section data.  */
27977298Sobrien  if (strcmp (segment_name (now_seg), ".eh_frame") == 0)
28077298Sobrien    d = &eh_frame_data;
28177298Sobrien  else if (strcmp (segment_name (now_seg), ".debug_frame") == 0)
28277298Sobrien    d = &debug_frame_data;
28377298Sobrien  else
28477298Sobrien    return 0;
28577298Sobrien
28678828Sobrien  if (d->state >= state_saw_size && S_IS_DEFINED (d->size_end_sym))
28756944Sobrien    {
28856944Sobrien      /* We have come to the end of the CIE or FDE.  See below where
28956944Sobrien         we set saw_size.  We must check this first because we may now
29056944Sobrien         be looking at the next size.  */
29178828Sobrien      d->state = state_idle;
29256944Sobrien    }
29356944Sobrien
29478828Sobrien  switch (d->state)
29538889Sjdp    {
29678828Sobrien    case state_idle:
29778828Sobrien      if (*pnbytes == 4)
29856944Sobrien	{
29978828Sobrien	  /* This might be the size of the CIE or FDE.  We want to know
30078828Sobrien	     the size so that we don't accidentally optimize across an FDE
30178828Sobrien	     boundary.  We recognize the size in one of two forms: a
30278828Sobrien	     symbol which will later be defined as a difference, or a
30378828Sobrien	     subtraction of two symbols.  Either way, we can tell when we
30478828Sobrien	     are at the end of the FDE because the symbol becomes defined
30578828Sobrien	     (in the case of a subtraction, the end symbol, from which the
30678828Sobrien	     start symbol is being subtracted).  Other ways of describing
30778828Sobrien	     the size will not be optimized.  */
30878828Sobrien	  if ((exp->X_op == O_symbol || exp->X_op == O_subtract)
30978828Sobrien	      && ! S_IS_DEFINED (exp->X_add_symbol))
31078828Sobrien	    {
31178828Sobrien	      d->state = state_saw_size;
31278828Sobrien	      d->size_end_sym = exp->X_add_symbol;
31378828Sobrien	    }
31456944Sobrien	}
31578828Sobrien      break;
31638889Sjdp
31778828Sobrien    case state_saw_size:
31878828Sobrien    case state_saw_cie_offset:
31978828Sobrien      /* Assume whatever form it appears in, it appears atomically.  */
32078828Sobrien      d->state += 1;
32178828Sobrien      break;
32238889Sjdp
32378828Sobrien    case state_saw_pc_begin:
32478828Sobrien      /* Decide whether we should see an augmentation.  */
32578828Sobrien      if (! d->cie_info_ok
32678828Sobrien	  && ! (d->cie_info_ok = get_cie_info (&d->cie_info)))
32778828Sobrien	d->state = state_error;
32878828Sobrien      else if (d->cie_info.z_augmentation)
32978828Sobrien	{
33078828Sobrien	  d->state = state_seeing_aug_size;
33178828Sobrien	  d->aug_size = 0;
33278828Sobrien	  d->aug_shift = 0;
33378828Sobrien	}
33478828Sobrien      else
33578828Sobrien	d->state = state_wait_loc4;
33678828Sobrien      break;
33738889Sjdp
33878828Sobrien    case state_seeing_aug_size:
33978828Sobrien      /* Bytes == -1 means this comes from an leb128 directive.  */
34078828Sobrien      if ((int)*pnbytes == -1 && exp->X_op == O_constant)
34138889Sjdp	{
34278828Sobrien	  d->aug_size = exp->X_add_number;
34378828Sobrien	  d->state = state_skipping_aug;
34438889Sjdp	}
34578828Sobrien      else if (*pnbytes == 1 && exp->X_op == O_constant)
34638889Sjdp	{
34778828Sobrien	  unsigned char byte = exp->X_add_number;
34878828Sobrien	  d->aug_size |= (byte & 0x7f) << d->aug_shift;
34978828Sobrien	  d->aug_shift += 7;
35078828Sobrien	  if ((byte & 0x80) == 0)
35178828Sobrien	    d->state = state_skipping_aug;
35238889Sjdp	}
35378828Sobrien      else
35478828Sobrien	d->state = state_error;
355130561Sobrien      if (d->state == state_skipping_aug && d->aug_size == 0)
356130561Sobrien	d->state = state_wait_loc4;
35778828Sobrien      break;
35878828Sobrien
35978828Sobrien    case state_skipping_aug:
36078828Sobrien      if ((int)*pnbytes < 0)
36178828Sobrien	d->state = state_error;
36278828Sobrien      else
36338889Sjdp	{
364104834Sobrien	  int left = (d->aug_size -= *pnbytes);
36578828Sobrien	  if (left == 0)
36678828Sobrien	    d->state = state_wait_loc4;
36778828Sobrien	  else if (left < 0)
36878828Sobrien	    d->state = state_error;
36938889Sjdp	}
37078828Sobrien      break;
37178828Sobrien
37278828Sobrien    case state_wait_loc4:
37378828Sobrien      if (*pnbytes == 1
37478828Sobrien	  && exp->X_op == O_constant
37578828Sobrien	  && exp->X_add_number == DW_CFA_advance_loc4)
37638889Sjdp	{
37778828Sobrien	  /* This might be a DW_CFA_advance_loc4.  Record the frag and the
37878828Sobrien	     position within the frag, so that we can change it later.  */
37978828Sobrien	  frag_grow (1);
38078828Sobrien	  d->state = state_saw_loc4;
38178828Sobrien	  d->loc4_frag = frag_now;
38278828Sobrien	  d->loc4_fix = frag_now_fix ();
38338889Sjdp	}
38478828Sobrien      break;
38538889Sjdp
38678828Sobrien    case state_saw_loc4:
38778828Sobrien      d->state = state_wait_loc4;
38878828Sobrien      if (*pnbytes != 4)
38978828Sobrien	break;
39078828Sobrien      if (exp->X_op == O_constant)
39178828Sobrien	{
39278828Sobrien	  /* This is a case which we can optimize.  The two symbols being
39378828Sobrien	     subtracted were in the same frag and the expression was
39478828Sobrien	     reduced to a constant.  We can do the optimization entirely
39578828Sobrien	     in this function.  */
39678828Sobrien	  if (d->cie_info.code_alignment > 0
39778828Sobrien	      && exp->X_add_number % d->cie_info.code_alignment == 0
39878828Sobrien	      && exp->X_add_number / d->cie_info.code_alignment < 0x40)
39978828Sobrien	    {
40078828Sobrien	      d->loc4_frag->fr_literal[d->loc4_fix]
40178828Sobrien		= DW_CFA_advance_loc
40278828Sobrien		  | (exp->X_add_number / d->cie_info.code_alignment);
40378828Sobrien	      /* No more bytes needed.  */
40478828Sobrien	      return 1;
40578828Sobrien	    }
40678828Sobrien	  else if (exp->X_add_number < 0x100)
40778828Sobrien	    {
40878828Sobrien	      d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc1;
40978828Sobrien	      *pnbytes = 1;
41078828Sobrien	    }
41178828Sobrien	  else if (exp->X_add_number < 0x10000)
41278828Sobrien	    {
41378828Sobrien	      d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc2;
41478828Sobrien	      *pnbytes = 2;
41578828Sobrien	    }
41678828Sobrien	}
41778828Sobrien      else if (exp->X_op == O_subtract)
41878828Sobrien	{
41978828Sobrien	  /* This is a case we can optimize.  The expression was not
42078828Sobrien	     reduced, so we can not finish the optimization until the end
42178828Sobrien	     of the assembly.  We set up a variant frag which we handle
42278828Sobrien	     later.  */
42378828Sobrien	  int fr_subtype;
42438889Sjdp
42578828Sobrien	  if (d->cie_info.code_alignment > 0)
42678828Sobrien	    fr_subtype = d->cie_info.code_alignment << 3;
42778828Sobrien	  else
42878828Sobrien	    fr_subtype = 0;
42938889Sjdp
43078828Sobrien	  frag_var (rs_cfa, 4, 0, fr_subtype, make_expr_symbol (exp),
43178828Sobrien		    d->loc4_fix, (char *) d->loc4_frag);
43278828Sobrien	  return 1;
43378828Sobrien	}
43478828Sobrien      break;
43578828Sobrien
43678828Sobrien    case state_error:
43778828Sobrien      /* Just skipping everything.  */
43878828Sobrien      break;
43938889Sjdp    }
44038889Sjdp
44138889Sjdp  return 0;
44238889Sjdp}
44338889Sjdp
44438889Sjdp/* The function estimates the size of a rs_cfa variant frag based on
44538889Sjdp   the current values of the symbols.  It is called before the
44678828Sobrien   relaxation loop.  We set fr_subtype{0:2} to the expected length.  */
44738889Sjdp
44838889Sjdpint
449130561Sobrieneh_frame_estimate_size_before_relax (fragS *frag)
45038889Sjdp{
45138889Sjdp  offsetT diff;
45278828Sobrien  int ca = frag->fr_subtype >> 3;
45338889Sjdp  int ret;
45438889Sjdp
45589857Sobrien  diff = resolve_symbol_value (frag->fr_symbol);
45638889Sjdp
45778828Sobrien  if (ca > 0 && diff % ca == 0 && diff / ca < 0x40)
45838889Sjdp    ret = 0;
45938889Sjdp  else if (diff < 0x100)
46038889Sjdp    ret = 1;
46138889Sjdp  else if (diff < 0x10000)
46238889Sjdp    ret = 2;
46338889Sjdp  else
46438889Sjdp    ret = 4;
46538889Sjdp
46678828Sobrien  frag->fr_subtype = (frag->fr_subtype & ~7) | ret;
46738889Sjdp
46838889Sjdp  return ret;
46938889Sjdp}
47038889Sjdp
47138889Sjdp/* This function relaxes a rs_cfa variant frag based on the current
47278828Sobrien   values of the symbols.  fr_subtype{0:2} is the current length of
47378828Sobrien   the frag.  This returns the change in frag length.  */
47438889Sjdp
47538889Sjdpint
476130561Sobrieneh_frame_relax_frag (fragS *frag)
47738889Sjdp{
47838889Sjdp  int oldsize, newsize;
47938889Sjdp
48078828Sobrien  oldsize = frag->fr_subtype & 7;
48138889Sjdp  newsize = eh_frame_estimate_size_before_relax (frag);
48238889Sjdp  return newsize - oldsize;
48338889Sjdp}
48438889Sjdp
48538889Sjdp/* This function converts a rs_cfa variant frag into a normal fill
48638889Sjdp   frag.  This is called after all relaxation has been done.
48778828Sobrien   fr_subtype{0:2} will be the desired length of the frag.  */
48838889Sjdp
48938889Sjdpvoid
490130561Sobrieneh_frame_convert_frag (fragS *frag)
49138889Sjdp{
49238889Sjdp  offsetT diff;
49338889Sjdp  fragS *loc4_frag;
49438889Sjdp  int loc4_fix;
49538889Sjdp
49638889Sjdp  loc4_frag = (fragS *) frag->fr_opcode;
49738889Sjdp  loc4_fix = (int) frag->fr_offset;
49838889Sjdp
49989857Sobrien  diff = resolve_symbol_value (frag->fr_symbol);
50038889Sjdp
50178828Sobrien  switch (frag->fr_subtype & 7)
50238889Sjdp    {
50378828Sobrien    case 0:
50478828Sobrien      {
50578828Sobrien	int ca = frag->fr_subtype >> 3;
50678828Sobrien	assert (ca > 0 && diff % ca == 0 && diff / ca < 0x40);
50778828Sobrien	loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc | (diff / ca);
50878828Sobrien      }
50978828Sobrien      break;
51038889Sjdp
51178828Sobrien    case 1:
51238889Sjdp      assert (diff < 0x100);
51338889Sjdp      loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1;
51438889Sjdp      frag->fr_literal[frag->fr_fix] = diff;
51578828Sobrien      break;
51678828Sobrien
51778828Sobrien    case 2:
51838889Sjdp      assert (diff < 0x10000);
51938889Sjdp      loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc2;
52038889Sjdp      md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2);
52178828Sobrien      break;
52278828Sobrien
52378828Sobrien    default:
52478828Sobrien      md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4);
52578828Sobrien      break;
52638889Sjdp    }
52738889Sjdp
52878828Sobrien  frag->fr_fix += frag->fr_subtype & 7;
52938889Sjdp  frag->fr_type = rs_fill;
53078828Sobrien  frag->fr_subtype = 0;
53138889Sjdp  frag->fr_offset = 0;
53238889Sjdp}
533