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