dwarf2asm.c revision 90075
1/* Dwarf2 assembler output helper routines.
2   Copyright (C) 2001, 2002 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 2, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING.  If not, write to the Free
18Software Foundation, 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA.  */
20
21
22#include "config.h"
23#include "system.h"
24#include "flags.h"
25#include "tree.h"
26#include "rtl.h"
27#include "output.h"
28#include "target.h"
29#include "dwarf2asm.h"
30#include "dwarf2.h"
31#include "splay-tree.h"
32#include "ggc.h"
33#include "tm_p.h"
34
35
36/* How to start an assembler comment.  */
37#ifndef ASM_COMMENT_START
38#define ASM_COMMENT_START ";#"
39#endif
40
41
42/* Output an unaligned integer with the given value and size.  Prefer not
43   to print a newline, since the caller may want to add a comment.  */
44
45void
46dw2_assemble_integer (size, x)
47     int size;
48     rtx x;
49{
50  const char *op = integer_asm_op (size, FALSE);
51
52  if (op)
53    {
54      fputs (op, asm_out_file);
55      if (GET_CODE (x) == CONST_INT)
56	fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
57      else
58	output_addr_const (asm_out_file, x);
59    }
60  else
61    assemble_integer (x, size, BITS_PER_UNIT, 1);
62}
63
64
65/* Output an immediate constant in a given size.  */
66
67void
68dw2_asm_output_data VPARAMS ((int size, unsigned HOST_WIDE_INT value,
69			      const char *comment, ...))
70{
71  VA_OPEN (ap, comment);
72  VA_FIXEDARG (ap, int, size);
73  VA_FIXEDARG (ap, unsigned HOST_WIDE_INT, value);
74  VA_FIXEDARG (ap, const char *, comment);
75
76  if (size * 8 < HOST_BITS_PER_WIDE_INT)
77    value &= ~(~(unsigned HOST_WIDE_INT) 0 << (size * 8));
78
79  dw2_assemble_integer (size, GEN_INT (value));
80
81  if (flag_debug_asm && comment)
82    {
83      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
84      vfprintf (asm_out_file, comment, ap);
85    }
86  fputc ('\n', asm_out_file);
87
88  VA_CLOSE (ap);
89}
90
91/* Output the difference between two symbols in a given size.  */
92/* ??? There appear to be assemblers that do not like such
93   subtraction, but do support ASM_SET_OP.  It's unfortunately
94   impossible to do here, since the ASM_SET_OP for the difference
95   symbol must appear after both symbols are defined.  */
96
97void
98dw2_asm_output_delta VPARAMS ((int size, const char *lab1, const char *lab2,
99			       const char *comment, ...))
100{
101  VA_OPEN (ap, comment);
102  VA_FIXEDARG (ap, int, size);
103  VA_FIXEDARG (ap, const char *, lab1);
104  VA_FIXEDARG (ap, const char *, lab2);
105  VA_FIXEDARG (ap, const char *, comment);
106
107  dw2_assemble_integer (size,
108			gen_rtx_MINUS (Pmode,
109				       gen_rtx_SYMBOL_REF (Pmode, lab1),
110				       gen_rtx_SYMBOL_REF (Pmode, lab2)));
111
112  if (flag_debug_asm && comment)
113    {
114      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
115      vfprintf (asm_out_file, comment, ap);
116    }
117  fputc ('\n', asm_out_file);
118
119  VA_CLOSE (ap);
120}
121
122/* Output a section-relative reference to a label.  In general this
123   can only be done for debugging symbols.  E.g. on most targets with
124   the GNU linker, this is accomplished with a direct reference and
125   the knowledge that the debugging section will be placed at VMA 0.
126   Some targets have special relocations for this that we must use.  */
127
128void
129dw2_asm_output_offset VPARAMS ((int size, const char *label,
130			       const char *comment, ...))
131{
132  VA_OPEN (ap, comment);
133  VA_FIXEDARG (ap, int, size);
134  VA_FIXEDARG (ap, const char *, label);
135  VA_FIXEDARG (ap, const char *, comment);
136
137#ifdef ASM_OUTPUT_DWARF_OFFSET
138  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label);
139#else
140  dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
141#endif
142
143  if (flag_debug_asm && comment)
144    {
145      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
146      vfprintf (asm_out_file, comment, ap);
147    }
148  fputc ('\n', asm_out_file);
149
150  VA_CLOSE (ap);
151}
152
153/* Output a self-relative reference to a label, possibly in a
154   different section or object file.  */
155
156void
157dw2_asm_output_pcrel VPARAMS ((int size ATTRIBUTE_UNUSED,
158			       const char *label ATTRIBUTE_UNUSED,
159			       const char *comment, ...))
160{
161  VA_OPEN (ap, comment);
162  VA_FIXEDARG (ap, int, size);
163  VA_FIXEDARG (ap, const char *, label);
164  VA_FIXEDARG (ap, const char *, comment);
165
166#ifdef ASM_OUTPUT_DWARF_PCREL
167  ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, label);
168#else
169  dw2_assemble_integer (size,
170			gen_rtx_MINUS (Pmode,
171				       gen_rtx_SYMBOL_REF (Pmode, label),
172				       pc_rtx));
173#endif
174
175  if (flag_debug_asm && comment)
176    {
177      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
178      vfprintf (asm_out_file, comment, ap);
179    }
180  fputc ('\n', asm_out_file);
181
182  VA_CLOSE (ap);
183}
184
185/* Output an absolute reference to a label.  */
186
187void
188dw2_asm_output_addr VPARAMS ((int size, const char *label,
189			      const char *comment, ...))
190{
191  VA_OPEN (ap, comment);
192  VA_FIXEDARG (ap, int, size);
193  VA_FIXEDARG (ap, const char *, label);
194  VA_FIXEDARG (ap, const char *, comment);
195
196  dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
197
198  if (flag_debug_asm && comment)
199    {
200      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
201      vfprintf (asm_out_file, comment, ap);
202    }
203  fputc ('\n', asm_out_file);
204
205  VA_CLOSE (ap);
206}
207
208/* Similar, but use an RTX expression instead of a text label.  */
209
210void
211dw2_asm_output_addr_rtx VPARAMS ((int size, rtx addr,
212				  const char *comment, ...))
213{
214  VA_OPEN (ap, comment);
215  VA_FIXEDARG (ap, int, size);
216  VA_FIXEDARG (ap, rtx, addr);
217  VA_FIXEDARG (ap, const char *, comment);
218
219  dw2_assemble_integer (size, addr);
220
221  if (flag_debug_asm && comment)
222    {
223      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
224      vfprintf (asm_out_file, comment, ap);
225    }
226  fputc ('\n', asm_out_file);
227
228  VA_CLOSE (ap);
229}
230
231void
232dw2_asm_output_nstring VPARAMS ((const char *str, size_t orig_len,
233				 const char *comment, ...))
234{
235  size_t i, len;
236
237  VA_OPEN (ap, comment);
238  VA_FIXEDARG (ap, const char *, str);
239  VA_FIXEDARG (ap, size_t, orig_len);
240  VA_FIXEDARG (ap, const char *, comment);
241
242  len = orig_len;
243
244  if (len == (size_t) -1)
245    len = strlen (str);
246
247  if (flag_debug_asm && comment)
248    {
249      fputs ("\t.ascii \"", asm_out_file);
250      for (i = 0; i < len; i++)
251	{
252	  int c = str[i];
253	  if (c == '\"' || c == '\\')
254	    fputc ('\\', asm_out_file);
255	  if (ISPRINT(c))
256	    fputc (c, asm_out_file);
257	  else
258	    fprintf (asm_out_file, "\\%o", c);
259	}
260      fprintf (asm_out_file, "\\0\"\t%s ", ASM_COMMENT_START);
261      vfprintf (asm_out_file, comment, ap);
262      fputc ('\n', asm_out_file);
263    }
264  else
265    {
266      /* If an explicit length was given, we can't assume there
267	 is a null termination in the string buffer.  */
268      if (orig_len == (size_t) -1)
269	len += 1;
270      ASM_OUTPUT_ASCII (asm_out_file, str, len);
271      if (orig_len != (size_t) -1)
272	assemble_integer (const0_rtx, 1, BITS_PER_UNIT, 1);
273    }
274
275  VA_CLOSE (ap);
276}
277
278
279/* Return the size of an unsigned LEB128 quantity.  */
280
281int
282size_of_uleb128 (value)
283     unsigned HOST_WIDE_INT value;
284{
285  int size = 0, byte;
286
287  do
288    {
289      byte = (value & 0x7f);
290      value >>= 7;
291      size += 1;
292    }
293  while (value != 0);
294
295  return size;
296}
297
298/* Return the size of a signed LEB128 quantity.  */
299
300int
301size_of_sleb128 (value)
302     HOST_WIDE_INT value;
303{
304  int size = 0, byte;
305
306  do
307    {
308      byte = (value & 0x7f);
309      value >>= 7;
310      size += 1;
311    }
312  while (!((value == 0 && (byte & 0x40) == 0)
313	   || (value == -1 && (byte & 0x40) != 0)));
314
315  return size;
316}
317
318/* Given an encoding, return the number of bytes the format occupies.
319   This is only defined for fixed-size encodings, and so does not
320   include leb128.  */
321
322int
323size_of_encoded_value (encoding)
324     int encoding;
325{
326  if (encoding == DW_EH_PE_omit)
327    return 0;
328
329  switch (encoding & 0x07)
330    {
331    case DW_EH_PE_absptr:
332      return POINTER_SIZE / BITS_PER_UNIT;
333    case DW_EH_PE_udata2:
334      return 2;
335    case DW_EH_PE_udata4:
336      return 4;
337    case DW_EH_PE_udata8:
338      return 8;
339    }
340  abort ();
341}
342
343/* Yield a name for a given pointer encoding.  */
344
345const char *
346eh_data_format_name (format)
347     int format;
348{
349#if HAVE_DESIGNATED_INITIALIZERS
350#define S(p, v)		[p] = v,
351#else
352#define S(p, v)		case p: return v;
353#endif
354
355#if HAVE_DESIGNATED_INITIALIZERS
356  __extension__ static const char * const format_names[256] = {
357#else
358  switch (format) {
359#endif
360
361  S(DW_EH_PE_absptr, "absolute")
362  S(DW_EH_PE_omit, "omit")
363  S(DW_EH_PE_aligned, "aligned absolute")
364
365  S(DW_EH_PE_uleb128, "uleb128")
366  S(DW_EH_PE_udata2, "udata2")
367  S(DW_EH_PE_udata4, "udata4")
368  S(DW_EH_PE_udata8, "udata8")
369  S(DW_EH_PE_sleb128, "sleb128")
370  S(DW_EH_PE_sdata2, "sdata2")
371  S(DW_EH_PE_sdata4, "sdata4")
372  S(DW_EH_PE_sdata8, "sdata8")
373
374  S(DW_EH_PE_absptr | DW_EH_PE_pcrel, "pcrel")
375  S(DW_EH_PE_uleb128 | DW_EH_PE_pcrel, "pcrel uleb128")
376  S(DW_EH_PE_udata2 | DW_EH_PE_pcrel, "pcrel udata2")
377  S(DW_EH_PE_udata4 | DW_EH_PE_pcrel, "pcrel udata4")
378  S(DW_EH_PE_udata8 | DW_EH_PE_pcrel, "pcrel udata8")
379  S(DW_EH_PE_sleb128 | DW_EH_PE_pcrel, "pcrel sleb128")
380  S(DW_EH_PE_sdata2 | DW_EH_PE_pcrel, "pcrel sdata2")
381  S(DW_EH_PE_sdata4 | DW_EH_PE_pcrel, "pcrel sdata4")
382  S(DW_EH_PE_sdata8 | DW_EH_PE_pcrel, "pcrel sdata8")
383
384  S(DW_EH_PE_absptr | DW_EH_PE_textrel, "textrel")
385  S(DW_EH_PE_uleb128 | DW_EH_PE_textrel, "textrel uleb128")
386  S(DW_EH_PE_udata2 | DW_EH_PE_textrel, "textrel udata2")
387  S(DW_EH_PE_udata4 | DW_EH_PE_textrel, "textrel udata4")
388  S(DW_EH_PE_udata8 | DW_EH_PE_textrel, "textrel udata8")
389  S(DW_EH_PE_sleb128 | DW_EH_PE_textrel, "textrel sleb128")
390  S(DW_EH_PE_sdata2 | DW_EH_PE_textrel, "textrel sdata2")
391  S(DW_EH_PE_sdata4 | DW_EH_PE_textrel, "textrel sdata4")
392  S(DW_EH_PE_sdata8 | DW_EH_PE_textrel, "textrel sdata8")
393
394  S(DW_EH_PE_absptr | DW_EH_PE_datarel, "datarel")
395  S(DW_EH_PE_uleb128 | DW_EH_PE_datarel, "datarel uleb128")
396  S(DW_EH_PE_udata2 | DW_EH_PE_datarel, "datarel udata2")
397  S(DW_EH_PE_udata4 | DW_EH_PE_datarel, "datarel udata4")
398  S(DW_EH_PE_udata8 | DW_EH_PE_datarel, "datarel udata8")
399  S(DW_EH_PE_sleb128 | DW_EH_PE_datarel, "datarel sleb128")
400  S(DW_EH_PE_sdata2 | DW_EH_PE_datarel, "datarel sdata2")
401  S(DW_EH_PE_sdata4 | DW_EH_PE_datarel, "datarel sdata4")
402  S(DW_EH_PE_sdata8 | DW_EH_PE_datarel, "datarel sdata8")
403
404  S(DW_EH_PE_absptr | DW_EH_PE_funcrel, "funcrel")
405  S(DW_EH_PE_uleb128 | DW_EH_PE_funcrel, "funcrel uleb128")
406  S(DW_EH_PE_udata2 | DW_EH_PE_funcrel, "funcrel udata2")
407  S(DW_EH_PE_udata4 | DW_EH_PE_funcrel, "funcrel udata4")
408  S(DW_EH_PE_udata8 | DW_EH_PE_funcrel, "funcrel udata8")
409  S(DW_EH_PE_sleb128 | DW_EH_PE_funcrel, "funcrel sleb128")
410  S(DW_EH_PE_sdata2 | DW_EH_PE_funcrel, "funcrel sdata2")
411  S(DW_EH_PE_sdata4 | DW_EH_PE_funcrel, "funcrel sdata4")
412  S(DW_EH_PE_sdata8 | DW_EH_PE_funcrel, "funcrel sdata8")
413
414  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_pcrel,
415    "indirect pcrel")
416  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_pcrel,
417    "indirect pcrel uleb128")
418  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_pcrel,
419    "indirect pcrel udata2")
420  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_pcrel,
421    "indirect pcrel udata4")
422  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_pcrel,
423    "indirect pcrel udata8")
424  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_pcrel,
425    "indirect pcrel sleb128")
426  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_pcrel,
427    "indirect pcrel sdata2")
428  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_pcrel,
429    "indirect pcrel sdata4")
430  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_pcrel,
431    "indirect pcrel sdata8")
432
433  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_textrel,
434    "indirect textrel")
435  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_textrel,
436    "indirect textrel uleb128")
437  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_textrel,
438    "indirect textrel udata2")
439  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_textrel,
440    "indirect textrel udata4")
441  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_textrel,
442    "indirect textrel udata8")
443  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_textrel,
444    "indirect textrel sleb128")
445  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_textrel,
446    "indirect textrel sdata2")
447  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_textrel,
448    "indirect textrel sdata4")
449  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_textrel,
450    "indirect textrel sdata8")
451
452  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_datarel,
453    "indirect datarel")
454  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_datarel,
455    "indirect datarel uleb128")
456  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_datarel,
457    "indirect datarel udata2")
458  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_datarel,
459    "indirect datarel udata4")
460  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_datarel,
461    "indirect datarel udata8")
462  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_datarel,
463    "indirect datarel sleb128")
464  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_datarel,
465    "indirect datarel sdata2")
466  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_datarel,
467    "indirect datarel sdata4")
468  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_datarel,
469    "indirect datarel sdata8")
470
471  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_funcrel,
472    "indirect funcrel")
473  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_funcrel,
474    "indirect funcrel uleb128")
475  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_funcrel,
476    "indirect funcrel udata2")
477  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_funcrel,
478    "indirect funcrel udata4")
479  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_funcrel,
480    "indirect funcrel udata8")
481  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_funcrel,
482    "indirect funcrel sleb128")
483  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_funcrel,
484    "indirect funcrel sdata2")
485  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_funcrel,
486    "indirect funcrel sdata4")
487  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_funcrel,
488    "indirect funcrel sdata8")
489
490#if HAVE_DESIGNATED_INITIALIZERS
491  };
492
493  if (format < 0 || format > 0xff || format_names[format] == NULL)
494    abort ();
495  return format_names[format];
496#else
497  }
498  abort ();
499#endif
500}
501
502/* Output an unsigned LEB128 quantity.  */
503
504void
505dw2_asm_output_data_uleb128 VPARAMS ((unsigned HOST_WIDE_INT value,
506				      const char *comment, ...))
507{
508  VA_OPEN (ap, comment);
509  VA_FIXEDARG (ap, unsigned HOST_WIDE_INT, value);
510  VA_FIXEDARG (ap, const char *, comment);
511
512#ifdef HAVE_AS_LEB128
513  fputs ("\t.uleb128 ", asm_out_file);
514  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, value);
515
516  if (flag_debug_asm && comment)
517    {
518      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
519      vfprintf (asm_out_file, comment, ap);
520    }
521#else
522  {
523    unsigned HOST_WIDE_INT work = value;
524    const char *byte_op = targetm.asm_out.byte_op;
525
526    if (byte_op)
527      fputs (byte_op, asm_out_file);
528    do
529      {
530	int byte = (work & 0x7f);
531	work >>= 7;
532	if (work != 0)
533	  /* More bytes to follow.  */
534	  byte |= 0x80;
535
536	if (byte_op)
537	  {
538	    fprintf (asm_out_file, "0x%x", byte);
539	    if (work != 0)
540	      fputc (',', asm_out_file);
541	  }
542	else
543	  assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
544      }
545    while (work != 0);
546
547  if (flag_debug_asm)
548    {
549      fprintf (asm_out_file, "\t%s uleb128 ", ASM_COMMENT_START);
550      fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, value);
551      if (comment)
552	{
553	  fputs ("; ", asm_out_file);
554	  vfprintf (asm_out_file, comment, ap);
555	}
556    }
557  }
558#endif
559  fputc ('\n', asm_out_file);
560
561  VA_CLOSE (ap);
562}
563
564/* Output an signed LEB128 quantity.  */
565
566void
567dw2_asm_output_data_sleb128 VPARAMS ((HOST_WIDE_INT value,
568				      const char *comment, ...))
569{
570  VA_OPEN (ap, comment);
571  VA_FIXEDARG (ap, HOST_WIDE_INT, value);
572  VA_FIXEDARG (ap, const char *, comment);
573
574#ifdef HAVE_AS_LEB128
575  fputs ("\t.sleb128 ", asm_out_file);
576  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, value);
577
578  if (flag_debug_asm && comment)
579    {
580      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
581      vfprintf (asm_out_file, comment, ap);
582    }
583#else
584  {
585    HOST_WIDE_INT work = value;
586    int more, byte;
587    const char *byte_op = targetm.asm_out.byte_op;
588
589    if (byte_op)
590      fputs (byte_op, asm_out_file);
591    do
592      {
593	byte = (work & 0x7f);
594	/* arithmetic shift */
595	work >>= 7;
596	more = !((work == 0 && (byte & 0x40) == 0)
597		 || (work == -1 && (byte & 0x40) != 0));
598	if (more)
599	  byte |= 0x80;
600
601	if (byte_op)
602	  {
603	    fprintf (asm_out_file, "0x%x", byte);
604	    if (more)
605	      fputc (',', asm_out_file);
606	  }
607	else
608	  assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
609      }
610    while (more);
611
612  if (flag_debug_asm)
613    {
614      fprintf (asm_out_file, "\t%s sleb128 ", ASM_COMMENT_START);
615      fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, value);
616      if (comment)
617	{
618	  fputs ("; ", asm_out_file);
619	  vfprintf (asm_out_file, comment, ap);
620	}
621    }
622  }
623#endif
624  fputc ('\n', asm_out_file);
625
626  VA_CLOSE (ap);
627}
628
629void
630dw2_asm_output_delta_uleb128 VPARAMS ((const char *lab1 ATTRIBUTE_UNUSED,
631				       const char *lab2 ATTRIBUTE_UNUSED,
632				       const char *comment, ...))
633{
634  VA_OPEN (ap, comment);
635  VA_FIXEDARG (ap, const char *, lab1);
636  VA_FIXEDARG (ap, const char *, lab2);
637  VA_FIXEDARG (ap, const char *, comment);
638
639#ifdef HAVE_AS_LEB128
640  fputs ("\t.uleb128 ", asm_out_file);
641  assemble_name (asm_out_file, lab1);
642  fputc ('-', asm_out_file);
643  assemble_name (asm_out_file, lab2);
644#else
645  abort ();
646#endif
647
648  if (flag_debug_asm && comment)
649    {
650      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
651      vfprintf (asm_out_file, comment, ap);
652    }
653  fputc ('\n', asm_out_file);
654
655  VA_CLOSE (ap);
656}
657
658void
659dw2_asm_output_delta_sleb128 VPARAMS ((const char *lab1 ATTRIBUTE_UNUSED,
660				       const char *lab2 ATTRIBUTE_UNUSED,
661				       const char *comment, ...))
662{
663  VA_OPEN (ap, comment);
664  VA_FIXEDARG (ap, const char *, lab1);
665  VA_FIXEDARG (ap, const char *, lab2);
666  VA_FIXEDARG (ap, const char *, comment);
667
668#ifdef HAVE_AS_LEB128
669  fputs ("\t.sleb128 ", asm_out_file);
670  assemble_name (asm_out_file, lab1);
671  fputc ('-', asm_out_file);
672  assemble_name (asm_out_file, lab2);
673#else
674  abort ();
675#endif
676
677  if (flag_debug_asm && comment)
678    {
679      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
680      vfprintf (asm_out_file, comment, ap);
681    }
682  fputc ('\n', asm_out_file);
683
684  VA_CLOSE (ap);
685}
686
687static int mark_indirect_pool_entry PARAMS ((splay_tree_node, void *));
688static void mark_indirect_pool PARAMS ((PTR arg));
689static rtx dw2_force_const_mem PARAMS ((rtx));
690static int dw2_output_indirect_constant_1 PARAMS ((splay_tree_node, void *));
691
692static splay_tree indirect_pool;
693
694#if defined(HAVE_GAS_HIDDEN) && defined(SUPPORTS_ONE_ONLY)
695# define USE_LINKONCE_INDIRECT 1
696#else
697# define USE_LINKONCE_INDIRECT 0
698#endif
699
700/* Mark all indirect constants for GC.  */
701
702static int
703mark_indirect_pool_entry (node, data)
704     splay_tree_node node;
705     void* data ATTRIBUTE_UNUSED;
706{
707  ggc_mark_nonnull_tree ((tree) node->value);
708  return 0;
709}
710
711/* Mark all indirect constants for GC.  */
712
713static void
714mark_indirect_pool (arg)
715     PTR arg ATTRIBUTE_UNUSED;
716{
717  splay_tree_foreach (indirect_pool, mark_indirect_pool_entry, NULL);
718}
719
720/* Put X, a SYMBOL_REF, in memory.  Return a SYMBOL_REF to the allocated
721   memory.  Differs from force_const_mem in that a single pool is used for
722   the entire unit of translation, and the memory is not guaranteed to be
723   "near" the function in any interesting sense.  */
724
725static rtx
726dw2_force_const_mem (x)
727     rtx x;
728{
729  splay_tree_node node;
730  const char *str;
731  tree decl;
732
733  if (! indirect_pool)
734    {
735      indirect_pool = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
736      ggc_add_root (&indirect_pool, 1, sizeof indirect_pool, mark_indirect_pool);
737    }
738
739  if (GET_CODE (x) != SYMBOL_REF)
740    abort ();
741
742  STRIP_NAME_ENCODING (str, XSTR (x, 0));
743  node = splay_tree_lookup (indirect_pool, (splay_tree_key) str);
744  if (node)
745    decl = (tree) node->value;
746  else
747    {
748      tree id;
749
750      if (USE_LINKONCE_INDIRECT)
751	{
752	  char *ref_name = alloca (strlen (str) + sizeof "DW.ref.");
753
754	  sprintf (ref_name, "DW.ref.%s", str);
755	  id = get_identifier (ref_name);
756	  decl = build_decl (VAR_DECL, id, ptr_type_node);
757	  DECL_ARTIFICIAL (decl) = 1;
758	  TREE_PUBLIC (decl) = 1;
759	  DECL_INITIAL (decl) = decl;
760	  make_decl_one_only (decl);
761	}
762      else
763	{
764	  extern int const_labelno;
765	  char label[32];
766
767	  ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
768	  ++const_labelno;
769	  id = get_identifier (label);
770	  decl = build_decl (VAR_DECL, id, ptr_type_node);
771	  DECL_ARTIFICIAL (decl) = 1;
772	  TREE_STATIC (decl) = 1;
773	  DECL_INITIAL (decl) = decl;
774	}
775
776      id = maybe_get_identifier (str);
777      if (id)
778	TREE_SYMBOL_REFERENCED (id) = 1;
779
780      splay_tree_insert (indirect_pool, (splay_tree_key) str,
781			 (splay_tree_value) decl);
782    }
783
784  return XEXP (DECL_RTL (decl), 0);
785}
786
787/* A helper function for dw2_output_indirect_constants called through
788   splay_tree_foreach.  Emit one queued constant to memory.  */
789
790static int
791dw2_output_indirect_constant_1 (node, data)
792     splay_tree_node node;
793     void* data ATTRIBUTE_UNUSED;
794{
795  const char *sym;
796  rtx sym_ref;
797
798  sym = (const char *) node->key;
799  sym_ref = gen_rtx_SYMBOL_REF (Pmode, sym);
800  if (USE_LINKONCE_INDIRECT)
801    fprintf (asm_out_file, "\t.hidden DW.ref.%s\n", sym);
802  assemble_variable ((tree) node->value, 1, 1, 1);
803  assemble_integer (sym_ref, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
804
805  return 0;
806}
807
808/* Emit the constants queued through dw2_force_const_mem.  */
809
810void
811dw2_output_indirect_constants ()
812{
813  if (indirect_pool)
814    splay_tree_foreach (indirect_pool, dw2_output_indirect_constant_1, NULL);
815}
816
817/* Like dw2_asm_output_addr_rtx, but encode the pointer as directed.  */
818
819void
820dw2_asm_output_encoded_addr_rtx VPARAMS ((int encoding,
821					  rtx addr,
822					  const char *comment, ...))
823{
824  int size;
825
826  VA_OPEN (ap, comment);
827  VA_FIXEDARG (ap, int, encoding);
828  VA_FIXEDARG (ap, rtx, addr);
829  VA_FIXEDARG (ap, const char *, comment);
830
831  size = size_of_encoded_value (encoding);
832
833  if (encoding == DW_EH_PE_aligned)
834    {
835      assemble_align (POINTER_SIZE);
836      assemble_integer (addr, size, POINTER_SIZE, 1);
837      return;
838    }
839
840  /* NULL is _always_ represented as a plain zero, as is 1 for Ada's
841     "all others".  */
842  if (addr == const0_rtx || addr == const1_rtx)
843    assemble_integer (addr, size, BITS_PER_UNIT, 1);
844  else
845    {
846    restart:
847      /* Allow the target first crack at emitting this.  Some of the
848	 special relocations require special directives instead of
849	 just ".4byte" or whatever.  */
850#ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
851      ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX (asm_out_file, encoding, size,
852					 addr, done);
853#endif
854
855      /* Indirection is used to get dynamic relocations out of a
856	 read-only section.  */
857      if (encoding & DW_EH_PE_indirect)
858	{
859	  /* It is very tempting to use force_const_mem so that we share data
860	     with the normal constant pool.  However, we've already emitted
861	     the constant pool for this function.  Moreover, we'd like to
862	     share these constants across the entire unit of translation,
863	     or better, across the entire application (or DSO).  */
864	  addr = dw2_force_const_mem (addr);
865	  encoding &= ~DW_EH_PE_indirect;
866	  goto restart;
867	}
868
869      switch (encoding & 0xF0)
870	{
871	case DW_EH_PE_absptr:
872	  dw2_assemble_integer (size, addr);
873	  break;
874
875	case DW_EH_PE_pcrel:
876	  if (GET_CODE (addr) != SYMBOL_REF)
877	    abort ();
878#ifdef ASM_OUTPUT_DWARF_PCREL
879	  ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, XSTR (addr, 0));
880#else
881	  dw2_assemble_integer (size, gen_rtx_MINUS (Pmode, addr, pc_rtx));
882#endif
883	  break;
884
885	default:
886	  /* Other encodings should have been handled by
887	     ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX.  */
888	  abort ();
889	}
890
891#ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
892    done:;
893#endif
894    }
895
896  if (flag_debug_asm && comment)
897    {
898      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
899      vfprintf (asm_out_file, comment, ap);
900    }
901  fputc ('\n', asm_out_file);
902
903  VA_CLOSE (ap);
904}
905