ehopt.c revision 130561
1191783Srmacklem/* ehopt.c--optimize gcc exception frame information.
2191783Srmacklem   Copyright 1998, 2000, 2001, 2003 Free Software Foundation, Inc.
3191783Srmacklem   Written by Ian Lance Taylor <ian@cygnus.com>.
4191783Srmacklem
5191783SrmacklemThis file is part of GAS, the GNU Assembler.
6191783Srmacklem
7191783SrmacklemGAS is free software; you can redistribute it and/or modify
8191783Srmacklemit under the terms of the GNU General Public License as published by
9191783Srmacklemthe Free Software Foundation; either version 2, or (at your option)
10191783Srmacklemany later version.
11191783Srmacklem
12191783SrmacklemGAS is distributed in the hope that it will be useful,
13191783Srmacklembut WITHOUT ANY WARRANTY; without even the implied warranty of
14191783SrmacklemMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15191783SrmacklemGNU General Public License for more details.
16191783Srmacklem
17191783SrmacklemYou should have received a copy of the GNU General Public License
18191783Srmacklemalong with GAS; see the file COPYING.  If not, write to the Free
19191783SrmacklemSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
20191783Srmacklem02111-1307, USA.  */
21191783Srmacklem
22191783Srmacklem#include "as.h"
23191783Srmacklem#include "subsegs.h"
24191783Srmacklem
25191783Srmacklem/* We include this ELF file, even though we may not be assembling for
26191783Srmacklem   ELF, since the exception frame information is always in a format
27191783Srmacklem   derived from DWARF.  */
28191783Srmacklem
29191783Srmacklem#include "elf/dwarf2.h"
30191783Srmacklem
31191783Srmacklem/* Try to optimize gcc 2.8 exception frame information.
32191783Srmacklem
33191783Srmacklem   Exception frame information is emitted for every function in the
34191783Srmacklem   .eh_frame or .debug_frame sections.  Simple information for a function
35191783Srmacklem   with no exceptions looks like this:
36191783Srmacklem
37191783Srmacklem__FRAME_BEGIN__:
38223280Srmacklem	.4byte	.LLCIE1	/ Length of Common Information Entry
39223280Srmacklem.LSCIE1:
40191783Srmacklem#if .eh_frame
41191783Srmacklem	.4byte	0x0	/ CIE Identifier Tag
42191783Srmacklem#elif .debug_frame
43191783Srmacklem	.4byte	0xffffffff / CIE Identifier Tag
44191783Srmacklem#endif
45191783Srmacklem	.byte	0x1	/ CIE Version
46191783Srmacklem	.byte	0x0	/ CIE Augmentation (none)
47191783Srmacklem	.byte	0x1	/ ULEB128 0x1 (CIE Code Alignment Factor)
48191783Srmacklem	.byte	0x7c	/ SLEB128 -4 (CIE Data Alignment Factor)
49191783Srmacklem	.byte	0x8	/ CIE RA Column
50240238Skib	.byte	0xc	/ DW_CFA_def_cfa
51191783Srmacklem	.byte	0x4	/ ULEB128 0x4
52191783Srmacklem	.byte	0x4	/ ULEB128 0x4
53191783Srmacklem	.byte	0x88	/ DW_CFA_offset, column 0x8
54191783Srmacklem	.byte	0x1	/ ULEB128 0x1
55191783Srmacklem	.align 4
56191783Srmacklem.LECIE1:
57191783Srmacklem	.set	.LLCIE1,.LECIE1-.LSCIE1	/ CIE Length Symbol
58191783Srmacklem	.4byte	.LLFDE1	/ FDE Length
59191783Srmacklem.LSFDE1:
60191783Srmacklem	.4byte	.LSFDE1-__FRAME_BEGIN__	/ FDE CIE offset
61223280Srmacklem	.4byte	.LFB1	/ FDE initial location
62191783Srmacklem	.4byte	.LFE1-.LFB1	/ FDE address range
63191783Srmacklem	.byte	0x4	/ DW_CFA_advance_loc4
64191783Srmacklem	.4byte	.LCFI0-.LFB1
65191783Srmacklem	.byte	0xe	/ DW_CFA_def_cfa_offset
66191783Srmacklem	.byte	0x8	/ ULEB128 0x8
67220683Srmacklem	.byte	0x85	/ DW_CFA_offset, column 0x5
68220683Srmacklem	.byte	0x2	/ ULEB128 0x2
69191783Srmacklem	.byte	0x4	/ DW_CFA_advance_loc4
70233730Skib	.4byte	.LCFI1-.LCFI0
71191783Srmacklem	.byte	0xd	/ DW_CFA_def_cfa_register
72191783Srmacklem	.byte	0x5	/ ULEB128 0x5
73191783Srmacklem	.byte	0x4	/ DW_CFA_advance_loc4
74191783Srmacklem	.4byte	.LCFI2-.LCFI1
75191783Srmacklem	.byte	0x2e	/ DW_CFA_GNU_args_size
76249077Skib	.byte	0x4	/ ULEB128 0x4
77191783Srmacklem	.byte	0x4	/ DW_CFA_advance_loc4
78191783Srmacklem	.4byte	.LCFI3-.LCFI2
79191783Srmacklem	.byte	0x2e	/ DW_CFA_GNU_args_size
80191783Srmacklem	.byte	0x0	/ ULEB128 0x0
81191783Srmacklem	.align 4
82191783Srmacklem.LEFDE1:
83191783Srmacklem	.set	.LLFDE1,.LEFDE1-.LSFDE1	/ FDE Length Symbol
84191783Srmacklem
85191783Srmacklem   The immediate issue we can address in the assembler is the
86191783Srmacklem   DW_CFA_advance_loc4 followed by a four byte value.  The value is
87191783Srmacklem   the difference of two addresses in the function.  Since gcc does
88191783Srmacklem   not know this value, it always uses four bytes.  We will know the
89191783Srmacklem   value at the end of assembly, so we can do better.  */
90191783Srmacklem
91191783Srmacklemstruct cie_info
92191783Srmacklem{
93191783Srmacklem  unsigned code_alignment;
94191783Srmacklem  int z_augmentation;
95191783Srmacklem};
96191783Srmacklem
97191783Srmacklemstatic int get_cie_info (struct cie_info *);
98191783Srmacklem
99191783Srmacklem/* Extract information from the CIE.  */
100191783Srmacklem
101191783Srmacklemstatic int
102191783Srmacklemget_cie_info (struct cie_info *info)
103191783Srmacklem{
104191783Srmacklem  fragS *f;
105191783Srmacklem  fixS *fix;
106191783Srmacklem  int offset;
107191783Srmacklem  char CIE_id;
108194425Salc  char augmentation[10];
109191783Srmacklem  int iaug;
110191783Srmacklem  int code_alignment = 0;
111191783Srmacklem
112191783Srmacklem  /* We should find the CIE at the start of the section.  */
113191783Srmacklem
114191783Srmacklem#if defined (BFD_ASSEMBLER) || defined (MANY_SEGMENTS)
115191783Srmacklem  f = seg_info (now_seg)->frchainP->frch_root;
116194425Salc#else
117191783Srmacklem  f = frchain_now->frch_root;
118191783Srmacklem#endif
119191783Srmacklem#ifdef BFD_ASSEMBLER
120191783Srmacklem  fix = seg_info (now_seg)->frchainP->fix_root;
121191783Srmacklem#else
122191783Srmacklem  fix = *seg_fix_rootP;
123249077Skib#endif
124191783Srmacklem
125191783Srmacklem  /* Look through the frags of the section to find the code alignment.  */
126191783Srmacklem
127191783Srmacklem  /* First make sure that the CIE Identifier Tag is 0/-1.  */
128191783Srmacklem
129191783Srmacklem  if (strcmp (segment_name (now_seg), ".debug_frame") == 0)
130191783Srmacklem    CIE_id = (char)0xff;
131191783Srmacklem  else
132191783Srmacklem    CIE_id = 0;
133191783Srmacklem
134191783Srmacklem  offset = 4;
135191783Srmacklem  while (f != NULL && offset >= f->fr_fix)
136191783Srmacklem    {
137194425Salc      offset -= f->fr_fix;
138194425Salc      f = f->fr_next;
139194425Salc    }
140207669Salc  if (f == NULL
141207669Salc      || f->fr_fix - offset < 4
142194425Salc      || f->fr_literal[offset] != CIE_id
143207669Salc      || f->fr_literal[offset + 1] != CIE_id
144207669Salc      || f->fr_literal[offset + 2] != CIE_id
145191783Srmacklem      || f->fr_literal[offset + 3] != CIE_id)
146191783Srmacklem    return 0;
147194425Salc
148191783Srmacklem  /* Next make sure the CIE version number is 1.  */
149194425Salc
150191783Srmacklem  offset += 4;
151191783Srmacklem  while (f != NULL && offset >= f->fr_fix)
152191783Srmacklem    {
153191783Srmacklem      offset -= f->fr_fix;
154191783Srmacklem      f = f->fr_next;
155191783Srmacklem    }
156191783Srmacklem  if (f == NULL
157191783Srmacklem      || f->fr_fix - offset < 1
158191783Srmacklem      || f->fr_literal[offset] != 1)
159191783Srmacklem    return 0;
160191783Srmacklem
161191783Srmacklem  /* Skip the augmentation (a null terminated string).  */
162191783Srmacklem
163191783Srmacklem  iaug = 0;
164191783Srmacklem  ++offset;
165191783Srmacklem  while (1)
166191783Srmacklem    {
167191783Srmacklem      while (f != NULL && offset >= f->fr_fix)
168191783Srmacklem	{
169191783Srmacklem	  offset -= f->fr_fix;
170191783Srmacklem	  f = f->fr_next;
171191783Srmacklem	}
172191783Srmacklem      if (f == NULL)
173191783Srmacklem	return 0;
174191783Srmacklem
175191783Srmacklem      while (offset < f->fr_fix && f->fr_literal[offset] != '\0')
176191783Srmacklem	{
177191783Srmacklem	  if ((size_t) iaug < (sizeof augmentation) - 1)
178191783Srmacklem	    {
179191783Srmacklem	      augmentation[iaug] = f->fr_literal[offset];
180191783Srmacklem	      ++iaug;
181207669Salc	    }
182207669Salc	  ++offset;
183191783Srmacklem	}
184207669Salc      if (offset < f->fr_fix)
185207669Salc	break;
186191783Srmacklem    }
187191783Srmacklem  ++offset;
188194425Salc  while (f != NULL && offset >= f->fr_fix)
189191783Srmacklem    {
190191783Srmacklem      offset -= f->fr_fix;
191191783Srmacklem      f = f->fr_next;
192191783Srmacklem    }
193191783Srmacklem  if (f == NULL)
194191783Srmacklem    return 0;
195191783Srmacklem
196191783Srmacklem  augmentation[iaug] = '\0';
197191783Srmacklem  if (augmentation[0] == '\0')
198191783Srmacklem    {
199191783Srmacklem      /* No augmentation.  */
200191783Srmacklem    }
201191783Srmacklem  else if (strcmp (augmentation, "eh") == 0)
202191783Srmacklem    {
203191783Srmacklem      /* We have to skip a pointer.  Unfortunately, we don't know how
204191783Srmacklem	 large it is.  We find out by looking for a matching fixup.  */
205191783Srmacklem      while (fix != NULL
206191783Srmacklem	     && (fix->fx_frag != f || fix->fx_where != offset))
207191783Srmacklem	fix = fix->fx_next;
208191783Srmacklem      if (fix == NULL)
209192065Srmacklem	offset += 4;
210192065Srmacklem      else
211191783Srmacklem	offset += fix->fx_size;
212191783Srmacklem      while (f != NULL && offset >= f->fr_fix)
213191783Srmacklem	{
214191783Srmacklem	  offset -= f->fr_fix;
215191783Srmacklem	  f = f->fr_next;
216192231Srmacklem	}
217192986Salc      if (f == NULL)
218192231Srmacklem	return 0;
219191783Srmacklem    }
220191783Srmacklem  else if (augmentation[0] != 'z')
221239554Skib    return 0;
222239554Skib
223239554Skib  /* We're now at the code alignment factor, which is a ULEB128.  If
224239554Skib     it isn't a single byte, forget it.  */
225239554Skib
226239554Skib  code_alignment = f->fr_literal[offset] & 0xff;
227239554Skib  if ((code_alignment & 0x80) != 0)
228191783Srmacklem    code_alignment = 0;
229191783Srmacklem
230191783Srmacklem  info->code_alignment = code_alignment;
231239554Skib  info->z_augmentation = (augmentation[0] == 'z');
232239554Skib
233191783Srmacklem  return 1;
234191783Srmacklem}
235194425Salc
236191783Srmacklem/* This function is called from emit_expr.  It looks for cases which
237191783Srmacklem   we can optimize.
238191783Srmacklem
239191783Srmacklem   Rather than try to parse all this information as we read it, we
240191783Srmacklem   look for a single byte DW_CFA_advance_loc4 followed by a 4 byte
241191783Srmacklem   difference.  We turn that into a rs_cfa_advance frag, and handle
242191783Srmacklem   those frags at the end of the assembly.  If the gcc output changes
243191783Srmacklem   somewhat, this optimization may stop working.
244191783Srmacklem
245191783Srmacklem   This function returns non-zero if it handled the expression and
246191783Srmacklem   emit_expr should not do anything, or zero otherwise.  It can also
247191783Srmacklem   change *EXP and *PNBYTES.  */
248191783Srmacklem
249191783Srmacklemint
250191783Srmacklemcheck_eh_frame (expressionS *exp, unsigned int *pnbytes)
251191783Srmacklem{
252191783Srmacklem  struct frame_data
253191783Srmacklem  {
254191783Srmacklem    enum frame_state
255191783Srmacklem    {
256191783Srmacklem      state_idle,
257191783Srmacklem      state_saw_size,
258191783Srmacklem      state_saw_cie_offset,
259191783Srmacklem      state_saw_pc_begin,
260191783Srmacklem      state_seeing_aug_size,
261236096Srmacklem      state_skipping_aug,
262236096Srmacklem      state_wait_loc4,
263236096Srmacklem      state_saw_loc4,
264236096Srmacklem      state_error,
265236096Srmacklem    } state;
266191783Srmacklem
267191783Srmacklem    int cie_info_ok;
268191783Srmacklem    struct cie_info cie_info;
269191783Srmacklem
270191783Srmacklem    symbolS *size_end_sym;
271191783Srmacklem    fragS *loc4_frag;
272249077Skib    int loc4_fix;
273191783Srmacklem
274191783Srmacklem    int aug_size;
275191783Srmacklem    int aug_shift;
276191783Srmacklem  };
277191783Srmacklem
278191783Srmacklem  static struct frame_data eh_frame_data;
279191783Srmacklem  static struct frame_data debug_frame_data;
280191783Srmacklem  struct frame_data *d;
281191783Srmacklem
282249077Skib  /* Don't optimize.  */
283191783Srmacklem  if (flag_traditional_format)
284249077Skib    return 0;
285191783Srmacklem
286191783Srmacklem  /* Select the proper section data.  */
287191783Srmacklem  if (strcmp (segment_name (now_seg), ".eh_frame") == 0)
288191783Srmacklem    d = &eh_frame_data;
289191783Srmacklem  else if (strcmp (segment_name (now_seg), ".debug_frame") == 0)
290222586Skib    d = &debug_frame_data;
291191783Srmacklem  else
292191783Srmacklem    return 0;
293191783Srmacklem
294191783Srmacklem  if (d->state >= state_saw_size && S_IS_DEFINED (d->size_end_sym))
295191783Srmacklem    {
296191783Srmacklem      /* We have come to the end of the CIE or FDE.  See below where
297191783Srmacklem         we set saw_size.  We must check this first because we may now
298191783Srmacklem         be looking at the next size.  */
299191783Srmacklem      d->state = state_idle;
300191783Srmacklem    }
301191783Srmacklem
302191783Srmacklem  switch (d->state)
303191783Srmacklem    {
304191783Srmacklem    case state_idle:
305191783Srmacklem      if (*pnbytes == 4)
306191783Srmacklem	{
307191783Srmacklem	  /* This might be the size of the CIE or FDE.  We want to know
308191783Srmacklem	     the size so that we don't accidentally optimize across an FDE
309191783Srmacklem	     boundary.  We recognize the size in one of two forms: a
310191783Srmacklem	     symbol which will later be defined as a difference, or a
311191783Srmacklem	     subtraction of two symbols.  Either way, we can tell when we
312191783Srmacklem	     are at the end of the FDE because the symbol becomes defined
313191783Srmacklem	     (in the case of a subtraction, the end symbol, from which the
314191783Srmacklem	     start symbol is being subtracted).  Other ways of describing
315191783Srmacklem	     the size will not be optimized.  */
316191783Srmacklem	  if ((exp->X_op == O_symbol || exp->X_op == O_subtract)
317191783Srmacklem	      && ! S_IS_DEFINED (exp->X_add_symbol))
318191783Srmacklem	    {
319191783Srmacklem	      d->state = state_saw_size;
320191783Srmacklem	      d->size_end_sym = exp->X_add_symbol;
321191783Srmacklem	    }
322191783Srmacklem	}
323191783Srmacklem      break;
324191783Srmacklem
325191783Srmacklem    case state_saw_size:
326191783Srmacklem    case state_saw_cie_offset:
327191783Srmacklem      /* Assume whatever form it appears in, it appears atomically.  */
328207082Srmacklem      d->state += 1;
329236096Srmacklem      break;
330191783Srmacklem
331191783Srmacklem    case state_saw_pc_begin:
332191783Srmacklem      /* Decide whether we should see an augmentation.  */
333191783Srmacklem      if (! d->cie_info_ok
334233730Skib	  && ! (d->cie_info_ok = get_cie_info (&d->cie_info)))
335233730Skib	d->state = state_error;
336233730Skib      else if (d->cie_info.z_augmentation)
337233730Skib	{
338233730Skib	  d->state = state_seeing_aug_size;
339191783Srmacklem	  d->aug_size = 0;
340191783Srmacklem	  d->aug_shift = 0;
341191783Srmacklem	}
342191783Srmacklem      else
343191783Srmacklem	d->state = state_wait_loc4;
344191783Srmacklem      break;
345191783Srmacklem
346191783Srmacklem    case state_seeing_aug_size:
347191783Srmacklem      /* Bytes == -1 means this comes from an leb128 directive.  */
348191783Srmacklem      if ((int)*pnbytes == -1 && exp->X_op == O_constant)
349191783Srmacklem	{
350191783Srmacklem	  d->aug_size = exp->X_add_number;
351191783Srmacklem	  d->state = state_skipping_aug;
352191783Srmacklem	}
353191783Srmacklem      else if (*pnbytes == 1 && exp->X_op == O_constant)
354191783Srmacklem	{
355191783Srmacklem	  unsigned char byte = exp->X_add_number;
356191783Srmacklem	  d->aug_size |= (byte & 0x7f) << d->aug_shift;
357191783Srmacklem	  d->aug_shift += 7;
358191783Srmacklem	  if ((byte & 0x80) == 0)
359191783Srmacklem	    d->state = state_skipping_aug;
360191783Srmacklem	}
361191783Srmacklem      else
362191783Srmacklem	d->state = state_error;
363191783Srmacklem      if (d->state == state_skipping_aug && d->aug_size == 0)
364191783Srmacklem	d->state = state_wait_loc4;
365249077Skib      break;
366191783Srmacklem
367191783Srmacklem    case state_skipping_aug:
368191783Srmacklem      if ((int)*pnbytes < 0)
369191783Srmacklem	d->state = state_error;
370191783Srmacklem      else
371191783Srmacklem	{
372191783Srmacklem	  int left = (d->aug_size -= *pnbytes);
373193955Srmacklem	  if (left == 0)
374193955Srmacklem	    d->state = state_wait_loc4;
375193955Srmacklem	  else if (left < 0)
376193955Srmacklem	    d->state = state_error;
377193955Srmacklem	}
378191783Srmacklem      break;
379191783Srmacklem
380191783Srmacklem    case state_wait_loc4:
381191783Srmacklem      if (*pnbytes == 1
382191783Srmacklem	  && exp->X_op == O_constant
383191783Srmacklem	  && exp->X_add_number == DW_CFA_advance_loc4)
384191783Srmacklem	{
385191783Srmacklem	  /* This might be a DW_CFA_advance_loc4.  Record the frag and the
386191783Srmacklem	     position within the frag, so that we can change it later.  */
387191783Srmacklem	  frag_grow (1);
388191783Srmacklem	  d->state = state_saw_loc4;
389191783Srmacklem	  d->loc4_frag = frag_now;
390223280Srmacklem	  d->loc4_fix = frag_now_fix ();
391191783Srmacklem	}
392191783Srmacklem      break;
393191783Srmacklem
394191783Srmacklem    case state_saw_loc4:
395191783Srmacklem      d->state = state_wait_loc4;
396191783Srmacklem      if (*pnbytes != 4)
397191783Srmacklem	break;
398191783Srmacklem      if (exp->X_op == O_constant)
399191783Srmacklem	{
400191783Srmacklem	  /* This is a case which we can optimize.  The two symbols being
401191783Srmacklem	     subtracted were in the same frag and the expression was
402191783Srmacklem	     reduced to a constant.  We can do the optimization entirely
403191783Srmacklem	     in this function.  */
404191783Srmacklem	  if (d->cie_info.code_alignment > 0
405191783Srmacklem	      && exp->X_add_number % d->cie_info.code_alignment == 0
406191783Srmacklem	      && exp->X_add_number / d->cie_info.code_alignment < 0x40)
407191783Srmacklem	    {
408191783Srmacklem	      d->loc4_frag->fr_literal[d->loc4_fix]
409191783Srmacklem		= DW_CFA_advance_loc
410191783Srmacklem		  | (exp->X_add_number / d->cie_info.code_alignment);
411191783Srmacklem	      /* No more bytes needed.  */
412191783Srmacklem	      return 1;
413191783Srmacklem	    }
414191783Srmacklem	  else if (exp->X_add_number < 0x100)
415191783Srmacklem	    {
416191783Srmacklem	      d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc1;
417249077Skib	      *pnbytes = 1;
418191783Srmacklem	    }
419191783Srmacklem	  else if (exp->X_add_number < 0x10000)
420191783Srmacklem	    {
421191783Srmacklem	      d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc2;
422191783Srmacklem	      *pnbytes = 2;
423191783Srmacklem	    }
424191783Srmacklem	}
425191783Srmacklem      else if (exp->X_op == O_subtract)
426191783Srmacklem	{
427191783Srmacklem	  /* This is a case we can optimize.  The expression was not
428191783Srmacklem	     reduced, so we can not finish the optimization until the end
429191783Srmacklem	     of the assembly.  We set up a variant frag which we handle
430191783Srmacklem	     later.  */
431191783Srmacklem	  int fr_subtype;
432191783Srmacklem
433191783Srmacklem	  if (d->cie_info.code_alignment > 0)
434191783Srmacklem	    fr_subtype = d->cie_info.code_alignment << 3;
435191783Srmacklem	  else
436191783Srmacklem	    fr_subtype = 0;
437220877Srmacklem
438191783Srmacklem	  frag_var (rs_cfa, 4, 0, fr_subtype, make_expr_symbol (exp),
439209120Skib		    d->loc4_fix, (char *) d->loc4_frag);
440191783Srmacklem	  return 1;
441191783Srmacklem	}
442191783Srmacklem      break;
443191783Srmacklem
444191783Srmacklem    case state_error:
445191783Srmacklem      /* Just skipping everything.  */
446191783Srmacklem      break;
447191783Srmacklem    }
448191783Srmacklem
449191783Srmacklem  return 0;
450191783Srmacklem}
451191783Srmacklem
452191783Srmacklem/* The function estimates the size of a rs_cfa variant frag based on
453191783Srmacklem   the current values of the symbols.  It is called before the
454191783Srmacklem   relaxation loop.  We set fr_subtype{0:2} to the expected length.  */
455191783Srmacklem
456220877Srmacklemint
457191783Srmacklemeh_frame_estimate_size_before_relax (fragS *frag)
458220877Srmacklem{
459249077Skib  offsetT diff;
460191783Srmacklem  int ca = frag->fr_subtype >> 3;
461220877Srmacklem  int ret;
462249077Skib
463191783Srmacklem  diff = resolve_symbol_value (frag->fr_symbol);
464191783Srmacklem
465191783Srmacklem  if (ca > 0 && diff % ca == 0 && diff / ca < 0x40)
466191783Srmacklem    ret = 0;
467191783Srmacklem  else if (diff < 0x100)
468231330Srmacklem    ret = 1;
469191783Srmacklem  else if (diff < 0x10000)
470249077Skib    ret = 2;
471191783Srmacklem  else
472191783Srmacklem    ret = 4;
473191783Srmacklem
474191783Srmacklem  frag->fr_subtype = (frag->fr_subtype & ~7) | ret;
475191783Srmacklem
476191783Srmacklem  return ret;
477249077Skib}
478191783Srmacklem
479191783Srmacklem/* This function relaxes a rs_cfa variant frag based on the current
480249077Skib   values of the symbols.  fr_subtype{0:2} is the current length of
481191783Srmacklem   the frag.  This returns the change in frag length.  */
482191783Srmacklem
483191783Srmacklemint
484191783Srmacklemeh_frame_relax_frag (fragS *frag)
485191783Srmacklem{
486191783Srmacklem  int oldsize, newsize;
487191783Srmacklem
488191783Srmacklem  oldsize = frag->fr_subtype & 7;
489191783Srmacklem  newsize = eh_frame_estimate_size_before_relax (frag);
490191783Srmacklem  return newsize - oldsize;
491191783Srmacklem}
492191783Srmacklem
493191783Srmacklem/* This function converts a rs_cfa variant frag into a normal fill
494191783Srmacklem   frag.  This is called after all relaxation has been done.
495191783Srmacklem   fr_subtype{0:2} will be the desired length of the frag.  */
496191783Srmacklem
497191783Srmacklemvoid
498191783Srmacklemeh_frame_convert_frag (fragS *frag)
499212217Srmacklem{
500191783Srmacklem  offsetT diff;
501191783Srmacklem  fragS *loc4_frag;
502191783Srmacklem  int loc4_fix;
503191783Srmacklem
504191783Srmacklem  loc4_frag = (fragS *) frag->fr_opcode;
505191783Srmacklem  loc4_fix = (int) frag->fr_offset;
506191783Srmacklem
507191783Srmacklem  diff = resolve_symbol_value (frag->fr_symbol);
508191783Srmacklem
509191783Srmacklem  switch (frag->fr_subtype & 7)
510191783Srmacklem    {
511191783Srmacklem    case 0:
512191783Srmacklem      {
513191783Srmacklem	int ca = frag->fr_subtype >> 3;
514191783Srmacklem	assert (ca > 0 && diff % ca == 0 && diff / ca < 0x40);
515191783Srmacklem	loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc | (diff / ca);
516191783Srmacklem      }
517191783Srmacklem      break;
518191783Srmacklem
519191783Srmacklem    case 1:
520191783Srmacklem      assert (diff < 0x100);
521191783Srmacklem      loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1;
522191783Srmacklem      frag->fr_literal[frag->fr_fix] = diff;
523191783Srmacklem      break;
524191783Srmacklem
525191783Srmacklem    case 2:
526191783Srmacklem      assert (diff < 0x10000);
527191783Srmacklem      loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc2;
528191783Srmacklem      md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2);
529191783Srmacklem      break;
530191783Srmacklem
531191783Srmacklem    default:
532191783Srmacklem      md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4);
533191783Srmacklem      break;
534191783Srmacklem    }
535191783Srmacklem
536191783Srmacklem  frag->fr_fix += frag->fr_subtype & 7;
537191783Srmacklem  frag->fr_type = rs_fill;
538191783Srmacklem  frag->fr_subtype = 0;
539191783Srmacklem  frag->fr_offset = 0;
540191783Srmacklem}
541207082Srmacklem