ehopt.c revision 218822
1119418Sobrien/* ehopt.c--optimize gcc exception frame information.
2119418Sobrien   Copyright 1998, 2000, 2001, 2003, 2005 Free Software Foundation, Inc.
393746Sjulian   Written by Ian Lance Taylor <ian@cygnus.com>.
493746Sjulian
593746SjulianThis file is part of GAS, the GNU Assembler.
693746Sjulian
793746SjulianGAS is free software; you can redistribute it and/or modify
893746Sjulianit under the terms of the GNU General Public License as published by
993746Sjulianthe Free Software Foundation; either version 2, or (at your option)
1093746Sjulianany later version.
1193746Sjulian
1293746SjulianGAS is distributed in the hope that it will be useful,
1393746Sjulianbut WITHOUT ANY WARRANTY; without even the implied warranty of
1493746SjulianMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1593746SjulianGNU General Public License for more details.
1693746Sjulian
1793746SjulianYou should have received a copy of the GNU General Public License
1893746Sjulianalong with GAS; see the file COPYING.  If not, write to the Free
1993746SjulianSoftware Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
2093746Sjulian02110-1301, USA.  */
2193746Sjulian
2293746Sjulian#include "as.h"
2393746Sjulian#include "subsegs.h"
2493746Sjulian
2593746Sjulian/* We include this ELF file, even though we may not be assembling for
2693746Sjulian   ELF, since the exception frame information is always in a format
27119418Sobrien   derived from DWARF.  */
2893746Sjulian
29113038Sobrien#include "elf/dwarf2.h"
30113038Sobrien
31113038Sobrien/* Try to optimize gcc 2.8 exception frame information.
32113038Sobrien
3393746Sjulian   Exception frame information is emitted for every function in the
3493746Sjulian   .eh_frame or .debug_frame sections.  Simple information for a function
3593746Sjulian   with no exceptions looks like this:
3693746Sjulian
3793746Sjulian__FRAME_BEGIN__:
3893746Sjulian	.4byte	.LLCIE1	/ Length of Common Information Entry
3993746Sjulian.LSCIE1:
4093746Sjulian#if .eh_frame
4193746Sjulian	.4byte	0x0	/ CIE Identifier Tag
4293746Sjulian#elif .debug_frame
4393746Sjulian	.4byte	0xffffffff / CIE Identifier Tag
4495807Sjulian#endif
4595807Sjulian	.byte	0x1	/ CIE Version
4693746Sjulian	.byte	0x0	/ CIE Augmentation (none)
4793746Sjulian	.byte	0x1	/ ULEB128 0x1 (CIE Code Alignment Factor)
4893746Sjulian	.byte	0x7c	/ SLEB128 -4 (CIE Data Alignment Factor)
4993746Sjulian	.byte	0x8	/ CIE RA Column
5093746Sjulian	.byte	0xc	/ DW_CFA_def_cfa
5193746Sjulian	.byte	0x4	/ ULEB128 0x4
5293746Sjulian	.byte	0x4	/ ULEB128 0x4
53147256Sbrooks	.byte	0x88	/ DW_CFA_offset, column 0x8
5493746Sjulian	.byte	0x1	/ ULEB128 0x1
5593746Sjulian	.align 4
5693746Sjulian.LECIE1:
5793746Sjulian	.set	.LLCIE1,.LECIE1-.LSCIE1	/ CIE Length Symbol
5893746Sjulian	.4byte	.LLFDE1	/ FDE Length
5993746Sjulian.LSFDE1:
6093746Sjulian	.4byte	.LSFDE1-__FRAME_BEGIN__	/ FDE CIE offset
6193746Sjulian	.4byte	.LFB1	/ FDE initial location
6293746Sjulian	.4byte	.LFE1-.LFB1	/ FDE address range
6393746Sjulian	.byte	0x4	/ DW_CFA_advance_loc4
64119285Simp	.4byte	.LCFI0-.LFB1
65119285Simp	.byte	0xe	/ DW_CFA_def_cfa_offset
6693746Sjulian	.byte	0x8	/ ULEB128 0x8
6793746Sjulian	.byte	0x85	/ DW_CFA_offset, column 0x5
6893746Sjulian	.byte	0x2	/ ULEB128 0x2
6993746Sjulian	.byte	0x4	/ DW_CFA_advance_loc4
7093746Sjulian	.4byte	.LCFI1-.LCFI0
7193746Sjulian	.byte	0xd	/ DW_CFA_def_cfa_register
7293746Sjulian	.byte	0x5	/ ULEB128 0x5
73153084Sru	.byte	0x4	/ DW_CFA_advance_loc4
7494904Sjulian	.4byte	.LCFI2-.LCFI1
7594904Sjulian	.byte	0x2e	/ DW_CFA_GNU_args_size
7693746Sjulian	.byte	0x4	/ ULEB128 0x4
7794904Sjulian	.byte	0x4	/ DW_CFA_advance_loc4
7894904Sjulian	.4byte	.LCFI3-.LCFI2
7993746Sjulian	.byte	0x2e	/ DW_CFA_GNU_args_size
8093746Sjulian	.byte	0x0	/ ULEB128 0x0
8193746Sjulian	.align 4
8293746Sjulian.LEFDE1:
8393746Sjulian	.set	.LLFDE1,.LEFDE1-.LSFDE1	/ FDE Length Symbol
8493746Sjulian
8593746Sjulian   The immediate issue we can address in the assembler is the
86119285Simp   DW_CFA_advance_loc4 followed by a four byte value.  The value is
8793746Sjulian   the difference of two addresses in the function.  Since gcc does
8893746Sjulian   not know this value, it always uses four bytes.  We will know the
8993746Sjulian   value at the end of assembly, so we can do better.  */
9093746Sjulian
9193746Sjulianstruct cie_info
9293746Sjulian{
9393746Sjulian  unsigned code_alignment;
9493746Sjulian  int z_augmentation;
9593746Sjulian};
9693746Sjulian
9793746Sjulianstatic int get_cie_info (struct cie_info *);
9893746Sjulian
9993746Sjulian/* Extract information from the CIE.  */
10093746Sjulian
10193746Sjulianstatic int
10293746Sjulianget_cie_info (struct cie_info *info)
10393746Sjulian{
10493746Sjulian  fragS *f;
10593746Sjulian  fixS *fix;
10693746Sjulian  int offset;
10793746Sjulian  char CIE_id;
10893746Sjulian  char augmentation[10];
10993746Sjulian  int iaug;
11093746Sjulian  int code_alignment = 0;
11193746Sjulian
11293746Sjulian  /* We should find the CIE at the start of the section.  */
11393746Sjulian
11493746Sjulian  f = seg_info (now_seg)->frchainP->frch_root;
11593746Sjulian  fix = seg_info (now_seg)->frchainP->fix_root;
11693746Sjulian
11793746Sjulian  /* Look through the frags of the section to find the code alignment.  */
11893746Sjulian
11993746Sjulian  /* First make sure that the CIE Identifier Tag is 0/-1.  */
12093746Sjulian
12193746Sjulian  if (strcmp (segment_name (now_seg), ".debug_frame") == 0)
12293746Sjulian    CIE_id = (char)0xff;
12393746Sjulian  else
124149151Sjhb    CIE_id = 0;
12593746Sjulian
12693746Sjulian  offset = 4;
127149151Sjhb  while (f != NULL && offset >= f->fr_fix)
12893746Sjulian    {
12993746Sjulian      offset -= f->fr_fix;
130188172Simp      f = f->fr_next;
13193746Sjulian    }
13293746Sjulian  if (f == NULL
13393746Sjulian      || f->fr_fix - offset < 4
13493746Sjulian      || f->fr_literal[offset] != CIE_id
13593746Sjulian      || f->fr_literal[offset + 1] != CIE_id
13693746Sjulian      || f->fr_literal[offset + 2] != CIE_id
13793746Sjulian      || f->fr_literal[offset + 3] != CIE_id)
13893746Sjulian    return 0;
13993746Sjulian
14093746Sjulian  /* Next make sure the CIE version number is 1.  */
14193746Sjulian
14293746Sjulian  offset += 4;
14393746Sjulian  while (f != NULL && offset >= f->fr_fix)
14493746Sjulian    {
14593746Sjulian      offset -= f->fr_fix;
146106696Salfred      f = f->fr_next;
147106696Salfred    }
14893746Sjulian  if (f == NULL
14993746Sjulian      || f->fr_fix - offset < 1
15093746Sjulian      || f->fr_literal[offset] != 1)
15193746Sjulian    return 0;
15293746Sjulian
15393746Sjulian  /* Skip the augmentation (a null terminated string).  */
15493746Sjulian
15593746Sjulian  iaug = 0;
15693746Sjulian  ++offset;
15793746Sjulian  while (1)
15893746Sjulian    {
15993746Sjulian      while (f != NULL && offset >= f->fr_fix)
16093746Sjulian	{
16193746Sjulian	  offset -= f->fr_fix;
16293746Sjulian	  f = f->fr_next;
16393746Sjulian	}
16493746Sjulian      if (f == NULL)
16593746Sjulian	return 0;
16693746Sjulian
167113506Smdodd      while (offset < f->fr_fix && f->fr_literal[offset] != '\0')
168113506Smdodd	{
169113506Smdodd	  if ((size_t) iaug < (sizeof augmentation) - 1)
17093746Sjulian	    {
17193746Sjulian	      augmentation[iaug] = f->fr_literal[offset];
17293746Sjulian	      ++iaug;
17393746Sjulian	    }
17493746Sjulian	  ++offset;
17593746Sjulian	}
17693746Sjulian      if (offset < f->fr_fix)
17793746Sjulian	break;
178149151Sjhb    }
17993746Sjulian  ++offset;
18093746Sjulian  while (f != NULL && offset >= f->fr_fix)
18193746Sjulian    {
18293746Sjulian      offset -= f->fr_fix;
18393746Sjulian      f = f->fr_next;
18493746Sjulian    }
18593746Sjulian  if (f == NULL)
18693746Sjulian    return 0;
18793746Sjulian
18893746Sjulian  augmentation[iaug] = '\0';
18993746Sjulian  if (augmentation[0] == '\0')
19093746Sjulian    {
19193746Sjulian      /* No augmentation.  */
19293746Sjulian    }
19393746Sjulian  else if (strcmp (augmentation, "eh") == 0)
19493746Sjulian    {
19593746Sjulian      /* We have to skip a pointer.  Unfortunately, we don't know how
19693746Sjulian	 large it is.  We find out by looking for a matching fixup.  */
19793746Sjulian      while (fix != NULL
19893746Sjulian	     && (fix->fx_frag != f || fix->fx_where != offset))
19993746Sjulian	fix = fix->fx_next;
20093746Sjulian      if (fix == NULL)
20193746Sjulian	offset += 4;
20293746Sjulian      else
20393746Sjulian	offset += fix->fx_size;
20493746Sjulian      while (f != NULL && offset >= f->fr_fix)
20593746Sjulian	{
20693746Sjulian	  offset -= f->fr_fix;
20793746Sjulian	  f = f->fr_next;
20893746Sjulian	}
20993746Sjulian      if (f == NULL)
21093746Sjulian	return 0;
21193746Sjulian    }
21293746Sjulian  else if (augmentation[0] != 'z')
21393746Sjulian    return 0;
21493746Sjulian
21593746Sjulian  /* We're now at the code alignment factor, which is a ULEB128.  If
21693746Sjulian     it isn't a single byte, forget it.  */
21793746Sjulian
21893746Sjulian  code_alignment = f->fr_literal[offset] & 0xff;
21993746Sjulian  if ((code_alignment & 0x80) != 0)
22093746Sjulian    code_alignment = 0;
22193746Sjulian
22293746Sjulian  info->code_alignment = code_alignment;
22393746Sjulian  info->z_augmentation = (augmentation[0] == 'z');
224148945Sjhb
22593746Sjulian  return 1;
22693746Sjulian}
22793746Sjulian
22893746Sjulian/* This function is called from emit_expr.  It looks for cases which
22993746Sjulian   we can optimize.
230149151Sjhb
23193746Sjulian   Rather than try to parse all this information as we read it, we
23293746Sjulian   look for a single byte DW_CFA_advance_loc4 followed by a 4 byte
23393746Sjulian   difference.  We turn that into a rs_cfa_advance frag, and handle
23493746Sjulian   those frags at the end of the assembly.  If the gcc output changes
23593746Sjulian   somewhat, this optimization may stop working.
23693746Sjulian
23793746Sjulian   This function returns non-zero if it handled the expression and
23893746Sjulian   emit_expr should not do anything, or zero otherwise.  It can also
23993746Sjulian   change *EXP and *PNBYTES.  */
24093746Sjulian
24193746Sjulianint
24293746Sjuliancheck_eh_frame (expressionS *exp, unsigned int *pnbytes)
24393746Sjulian{
24493746Sjulian  struct frame_data
24593746Sjulian  {
24693746Sjulian    enum frame_state
24793746Sjulian    {
24893746Sjulian      state_idle,
24993746Sjulian      state_saw_size,
25093746Sjulian      state_saw_cie_offset,
25193746Sjulian      state_saw_pc_begin,
25293746Sjulian      state_seeing_aug_size,
25393746Sjulian      state_skipping_aug,
25493746Sjulian      state_wait_loc4,
25593746Sjulian      state_saw_loc4,
25693746Sjulian      state_error,
25793746Sjulian    } state;
25893746Sjulian
25993746Sjulian    int cie_info_ok;
26093746Sjulian    struct cie_info cie_info;
26193746Sjulian
26293746Sjulian    symbolS *size_end_sym;
26393746Sjulian    fragS *loc4_frag;
26493746Sjulian    int loc4_fix;
26593746Sjulian
26693746Sjulian    int aug_size;
26793746Sjulian    int aug_shift;
26893746Sjulian  };
26993746Sjulian
27093746Sjulian  static struct frame_data eh_frame_data;
27193746Sjulian  static struct frame_data debug_frame_data;
27293746Sjulian  struct frame_data *d;
27393746Sjulian
274149151Sjhb  /* Don't optimize.  */
27593746Sjulian  if (flag_traditional_format)
27693746Sjulian    return 0;
27793746Sjulian
27893746Sjulian  /* Select the proper section data.  */
27993746Sjulian  if (strcmp (segment_name (now_seg), ".eh_frame") == 0)
28093746Sjulian    d = &eh_frame_data;
28193746Sjulian  else if (strcmp (segment_name (now_seg), ".debug_frame") == 0)
28293746Sjulian    d = &debug_frame_data;
28393746Sjulian  else
28493746Sjulian    return 0;
28593746Sjulian
28693746Sjulian  if (d->state >= state_saw_size && S_IS_DEFINED (d->size_end_sym))
28793746Sjulian    {
28893746Sjulian      /* We have come to the end of the CIE or FDE.  See below where
28993746Sjulian         we set saw_size.  We must check this first because we may now
29093746Sjulian         be looking at the next size.  */
29193746Sjulian      d->state = state_idle;
29293746Sjulian    }
29393746Sjulian
29493746Sjulian  switch (d->state)
29593746Sjulian    {
29693746Sjulian    case state_idle:
29793746Sjulian      if (*pnbytes == 4)
29893746Sjulian	{
29993746Sjulian	  /* This might be the size of the CIE or FDE.  We want to know
30093746Sjulian	     the size so that we don't accidentally optimize across an FDE
30193746Sjulian	     boundary.  We recognize the size in one of two forms: a
30293746Sjulian	     symbol which will later be defined as a difference, or a
30393746Sjulian	     subtraction of two symbols.  Either way, we can tell when we
30493746Sjulian	     are at the end of the FDE because the symbol becomes defined
30593746Sjulian	     (in the case of a subtraction, the end symbol, from which the
30693746Sjulian	     start symbol is being subtracted).  Other ways of describing
30793746Sjulian	     the size will not be optimized.  */
30893746Sjulian	  if ((exp->X_op == O_symbol || exp->X_op == O_subtract)
30993746Sjulian	      && ! S_IS_DEFINED (exp->X_add_symbol))
31093746Sjulian	    {
31193746Sjulian	      d->state = state_saw_size;
31293746Sjulian	      d->size_end_sym = exp->X_add_symbol;
31393746Sjulian	    }
31493746Sjulian	}
31593746Sjulian      break;
31693746Sjulian
31793746Sjulian    case state_saw_size:
31893746Sjulian    case state_saw_cie_offset:
31993746Sjulian      /* Assume whatever form it appears in, it appears atomically.  */
32093746Sjulian      d->state += 1;
321149151Sjhb      break;
32293746Sjulian
323147256Sbrooks    case state_saw_pc_begin:
32493746Sjulian      /* Decide whether we should see an augmentation.  */
32593746Sjulian      if (! d->cie_info_ok
32693746Sjulian	  && ! (d->cie_info_ok = get_cie_info (&d->cie_info)))
32793746Sjulian	d->state = state_error;
32893746Sjulian      else if (d->cie_info.z_augmentation)
32993746Sjulian	{
33093746Sjulian	  d->state = state_seeing_aug_size;
33193746Sjulian	  d->aug_size = 0;
33293746Sjulian	  d->aug_shift = 0;
33393746Sjulian	}
33493746Sjulian      else
33593746Sjulian	d->state = state_wait_loc4;
33693746Sjulian      break;
33793746Sjulian
33893746Sjulian    case state_seeing_aug_size:
33993746Sjulian      /* Bytes == -1 means this comes from an leb128 directive.  */
340148654Srwatson      if ((int)*pnbytes == -1 && exp->X_op == O_constant)
34193746Sjulian	{
34293746Sjulian	  d->aug_size = exp->X_add_number;
34393746Sjulian	  d->state = state_skipping_aug;
344130270Snaddy	}
345130270Snaddy      else if (*pnbytes == 1 && exp->X_op == O_constant)
34693746Sjulian	{
34793746Sjulian	  unsigned char byte = exp->X_add_number;
34893746Sjulian	  d->aug_size |= (byte & 0x7f) << d->aug_shift;
34993746Sjulian	  d->aug_shift += 7;
35093746Sjulian	  if ((byte & 0x80) == 0)
35193746Sjulian	    d->state = state_skipping_aug;
352148654Srwatson	}
35393746Sjulian      else
35493746Sjulian	d->state = state_error;
35593746Sjulian      if (d->state == state_skipping_aug && d->aug_size == 0)
35693746Sjulian	d->state = state_wait_loc4;
35793746Sjulian      break;
35893746Sjulian
35993746Sjulian    case state_skipping_aug:
36093746Sjulian      if ((int)*pnbytes < 0)
36193746Sjulian	d->state = state_error;
36293746Sjulian      else
36393746Sjulian	{
36493746Sjulian	  int left = (d->aug_size -= *pnbytes);
36593746Sjulian	  if (left == 0)
36693746Sjulian	    d->state = state_wait_loc4;
36793746Sjulian	  else if (left < 0)
36893746Sjulian	    d->state = state_error;
36993746Sjulian	}
37093746Sjulian      break;
37193746Sjulian
372149151Sjhb    case state_wait_loc4:
37393746Sjulian      if (*pnbytes == 1
37493746Sjulian	  && exp->X_op == O_constant
37593746Sjulian	  && exp->X_add_number == DW_CFA_advance_loc4)
37693746Sjulian	{
37793746Sjulian	  /* This might be a DW_CFA_advance_loc4.  Record the frag and the
37893746Sjulian	     position within the frag, so that we can change it later.  */
37993746Sjulian	  frag_grow (1);
38093746Sjulian	  d->state = state_saw_loc4;
38193746Sjulian	  d->loc4_frag = frag_now;
38293746Sjulian	  d->loc4_fix = frag_now_fix ();
38393746Sjulian	}
38493746Sjulian      break;
38593746Sjulian
38693746Sjulian    case state_saw_loc4:
38793746Sjulian      d->state = state_wait_loc4;
38893746Sjulian      if (*pnbytes != 4)
38993746Sjulian	break;
39093746Sjulian      if (exp->X_op == O_constant)
39193746Sjulian	{
39293746Sjulian	  /* This is a case which we can optimize.  The two symbols being
39393746Sjulian	     subtracted were in the same frag and the expression was
39493746Sjulian	     reduced to a constant.  We can do the optimization entirely
39593746Sjulian	     in this function.  */
39693746Sjulian	  if (d->cie_info.code_alignment > 0
397149151Sjhb	      && exp->X_add_number % d->cie_info.code_alignment == 0
39893746Sjulian	      && exp->X_add_number / d->cie_info.code_alignment < 0x40)
39993746Sjulian	    {
400147256Sbrooks	      d->loc4_frag->fr_literal[d->loc4_fix]
40193746Sjulian		= DW_CFA_advance_loc
40293746Sjulian		  | (exp->X_add_number / d->cie_info.code_alignment);
40393746Sjulian	      /* No more bytes needed.  */
40493746Sjulian	      return 1;
40593746Sjulian	    }
40693746Sjulian	  else if (exp->X_add_number < 0x100)
40793746Sjulian	    {
40893746Sjulian	      d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc1;
40993746Sjulian	      *pnbytes = 1;
41093746Sjulian	    }
41193746Sjulian	  else if (exp->X_add_number < 0x10000)
412162321Sglebius	    {
413162321Sglebius	      d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc2;
41493746Sjulian	      *pnbytes = 2;
41593746Sjulian	    }
41693746Sjulian	}
41793746Sjulian      else if (exp->X_op == O_subtract)
41893746Sjulian	{
41993746Sjulian	  /* This is a case we can optimize.  The expression was not
42093746Sjulian	     reduced, so we can not finish the optimization until the end
42193746Sjulian	     of the assembly.  We set up a variant frag which we handle
42293746Sjulian	     later.  */
42393746Sjulian	  int fr_subtype;
42493746Sjulian
42593746Sjulian	  if (d->cie_info.code_alignment > 0)
42693746Sjulian	    fr_subtype = d->cie_info.code_alignment << 3;
42793746Sjulian	  else
42893746Sjulian	    fr_subtype = 0;
42993746Sjulian
43093746Sjulian	  frag_var (rs_cfa, 4, 0, fr_subtype, make_expr_symbol (exp),
43193746Sjulian		    d->loc4_fix, (char *) d->loc4_frag);
43293746Sjulian	  return 1;
43393746Sjulian	}
43493746Sjulian      break;
43593746Sjulian
43693746Sjulian    case state_error:
43793746Sjulian      /* Just skipping everything.  */
43893746Sjulian      break;
43993746Sjulian    }
44093746Sjulian
44193746Sjulian  return 0;
44293746Sjulian}
44393746Sjulian
44493746Sjulian/* The function estimates the size of a rs_cfa variant frag based on
44593746Sjulian   the current values of the symbols.  It is called before the
44693746Sjulian   relaxation loop.  We set fr_subtype{0:2} to the expected length.  */
44793746Sjulian
44893746Sjulianint
44993746Sjulianeh_frame_estimate_size_before_relax (fragS *frag)
45093746Sjulian{
451162321Sglebius  offsetT diff;
45293746Sjulian  int ca = frag->fr_subtype >> 3;
45393746Sjulian  int ret;
45493746Sjulian
45593746Sjulian  diff = resolve_symbol_value (frag->fr_symbol);
45693746Sjulian
457162321Sglebius  if (ca > 0 && diff % ca == 0 && diff / ca < 0x40)
45893746Sjulian    ret = 0;
45993746Sjulian  else if (diff < 0x100)
46093746Sjulian    ret = 1;
461162321Sglebius  else if (diff < 0x10000)
46293746Sjulian    ret = 2;
46393746Sjulian  else
46493746Sjulian    ret = 4;
46593746Sjulian
46693746Sjulian  frag->fr_subtype = (frag->fr_subtype & ~7) | ret;
46793746Sjulian
46893746Sjulian  return ret;
469162321Sglebius}
47093746Sjulian
47193746Sjulian/* This function relaxes a rs_cfa variant frag based on the current
47293746Sjulian   values of the symbols.  fr_subtype{0:2} is the current length of
47393746Sjulian   the frag.  This returns the change in frag length.  */
47493746Sjulian
47593746Sjulianint
47693746Sjulianeh_frame_relax_frag (fragS *frag)
47793746Sjulian{
47893746Sjulian  int oldsize, newsize;
47993746Sjulian
48093746Sjulian  oldsize = frag->fr_subtype & 7;
48195673Sphk  newsize = eh_frame_estimate_size_before_relax (frag);
48293746Sjulian  return newsize - oldsize;
48393746Sjulian}
48493746Sjulian
48593746Sjulian/* This function converts a rs_cfa variant frag into a normal fill
48693746Sjulian   frag.  This is called after all relaxation has been done.
48793746Sjulian   fr_subtype{0:2} will be the desired length of the frag.  */
48893746Sjulian
48993746Sjulianvoid
49093746Sjulianeh_frame_convert_frag (fragS *frag)
49193746Sjulian{
49293746Sjulian  offsetT diff;
49393746Sjulian  fragS *loc4_frag;
49495673Sphk  int loc4_fix;
49593746Sjulian
49693746Sjulian  loc4_frag = (fragS *) frag->fr_opcode;
49793746Sjulian  loc4_fix = (int) frag->fr_offset;
49893746Sjulian
49993746Sjulian  diff = resolve_symbol_value (frag->fr_symbol);
50093746Sjulian
50193746Sjulian  switch (frag->fr_subtype & 7)
50293746Sjulian    {
50393746Sjulian    case 0:
50493746Sjulian      {
50593746Sjulian	int ca = frag->fr_subtype >> 3;
50693746Sjulian	assert (ca > 0 && diff % ca == 0 && diff / ca < 0x40);
50793746Sjulian	loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc | (diff / ca);
50893746Sjulian      }
50993746Sjulian      break;
51093746Sjulian
51193746Sjulian    case 1:
51293746Sjulian      assert (diff < 0x100);
51393746Sjulian      loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1;
51493746Sjulian      frag->fr_literal[frag->fr_fix] = diff;
51593746Sjulian      break;
51693746Sjulian
51793746Sjulian    case 2:
51893746Sjulian      assert (diff < 0x10000);
51993746Sjulian      loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc2;
52093746Sjulian      md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2);
52193746Sjulian      break;
52293746Sjulian
52393746Sjulian    default:
52493746Sjulian      md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4);
52593746Sjulian      break;
52693746Sjulian    }
52793746Sjulian
52893746Sjulian  frag->fr_fix += frag->fr_subtype & 7;
52993746Sjulian  frag->fr_type = rs_fill;
53093746Sjulian  frag->fr_subtype = 0;
53193746Sjulian  frag->fr_offset = 0;
53293746Sjulian}
53393746Sjulian