1/* Dwarf2 assembler output helper routines.
2   Copyright (C) 2001-2015 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 3, 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 COPYING3.  If not see
18<http://www.gnu.org/licenses/>.  */
19
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
25#include "flags.h"
26#include "hash-set.h"
27#include "machmode.h"
28#include "vec.h"
29#include "double-int.h"
30#include "input.h"
31#include "alias.h"
32#include "symtab.h"
33#include "wide-int.h"
34#include "inchash.h"
35#include "real.h"
36#include "tree.h"
37#include "stringpool.h"
38#include "varasm.h"
39#include "rtl.h"
40#include "output.h"
41#include "target.h"
42#include "dwarf2asm.h"
43#include "dwarf2.h"
44#include "hash-map.h"
45#include "ggc.h"
46#include "tm_p.h"
47
48
49/* Output an unaligned integer with the given value and size.  Prefer not
50   to print a newline, since the caller may want to add a comment.  */
51
52void
53dw2_assemble_integer (int size, rtx x)
54{
55  const char *op = integer_asm_op (size, FALSE);
56
57  if (op)
58    {
59      fputs (op, asm_out_file);
60      if (CONST_INT_P (x))
61	fprint_whex (asm_out_file, (unsigned HOST_WIDE_INT) INTVAL (x));
62      else
63	output_addr_const (asm_out_file, x);
64    }
65  else
66    assemble_integer (x, size, BITS_PER_UNIT, 1);
67}
68
69
70/* Output a value of a given size in target byte order.  */
71
72void
73dw2_asm_output_data_raw (int size, unsigned HOST_WIDE_INT value)
74{
75  unsigned char bytes[8];
76  int i;
77
78  for (i = 0; i < 8; ++i)
79    {
80      bytes[i] = value & 0xff;
81      value >>= 8;
82    }
83
84  if (BYTES_BIG_ENDIAN)
85    {
86      for (i = size - 1; i > 0; --i)
87	fprintf (asm_out_file, "%#x,", bytes[i]);
88      fprintf (asm_out_file, "%#x", bytes[0]);
89    }
90  else
91    {
92      for (i = 0; i < size - 1; ++i)
93	fprintf (asm_out_file, "%#x,", bytes[i]);
94      fprintf (asm_out_file, "%#x", bytes[i]);
95    }
96}
97
98/* Output an immediate constant in a given SIZE in bytes.  */
99
100void
101dw2_asm_output_data (int size, unsigned HOST_WIDE_INT value,
102		     const char *comment, ...)
103{
104  va_list ap;
105  const char *op = integer_asm_op (size, FALSE);
106
107  va_start (ap, comment);
108
109  if (size * 8 < HOST_BITS_PER_WIDE_INT)
110    value &= ~(~(unsigned HOST_WIDE_INT) 0 << (size * 8));
111
112  if (op)
113    {
114      fputs (op, asm_out_file);
115      fprint_whex (asm_out_file, value);
116    }
117  else
118    assemble_integer (GEN_INT (value), size, BITS_PER_UNIT, 1);
119
120  if (flag_debug_asm && comment)
121    {
122      fputs ("\t" ASM_COMMENT_START " ", asm_out_file);
123      vfprintf (asm_out_file, comment, ap);
124    }
125  putc ('\n', asm_out_file);
126
127  va_end (ap);
128}
129
130/* Output the difference between two symbols in a given size.  */
131/* ??? There appear to be assemblers that do not like such
132   subtraction, but do support ASM_SET_OP.  It's unfortunately
133   impossible to do here, since the ASM_SET_OP for the difference
134   symbol must appear after both symbols are defined.  */
135
136void
137dw2_asm_output_delta (int size, const char *lab1, const char *lab2,
138		      const char *comment, ...)
139{
140  va_list ap;
141
142  va_start (ap, comment);
143
144#ifdef ASM_OUTPUT_DWARF_DELTA
145  ASM_OUTPUT_DWARF_DELTA (asm_out_file, size, lab1, lab2);
146#else
147  dw2_assemble_integer (size,
148			gen_rtx_MINUS (Pmode,
149				       gen_rtx_SYMBOL_REF (Pmode, lab1),
150				       gen_rtx_SYMBOL_REF (Pmode, lab2)));
151#endif
152  if (flag_debug_asm && comment)
153    {
154      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
155      vfprintf (asm_out_file, comment, ap);
156    }
157  fputc ('\n', asm_out_file);
158
159  va_end (ap);
160}
161
162#ifdef ASM_OUTPUT_DWARF_VMS_DELTA
163/* Output the difference between two symbols in instruction units
164   in a given size.  */
165
166void
167dw2_asm_output_vms_delta (int size ATTRIBUTE_UNUSED,
168			  const char *lab1, const char *lab2,
169			  const char *comment, ...)
170{
171  va_list ap;
172
173  va_start (ap, comment);
174
175  ASM_OUTPUT_DWARF_VMS_DELTA (asm_out_file, size, lab1, lab2);
176  if (flag_debug_asm && comment)
177    {
178      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
179      vfprintf (asm_out_file, comment, ap);
180    }
181  fputc ('\n', asm_out_file);
182
183  va_end (ap);
184}
185#endif
186
187/* Output a section-relative reference to a LABEL, which was placed in
188   BASE.  In general this can only be done for debugging symbols.
189   E.g. on most targets with the GNU linker, this is accomplished with
190   a direct reference and the knowledge that the debugging section
191   will be placed at VMA 0.  Some targets have special relocations for
192   this that we must use.  */
193
194void
195dw2_asm_output_offset (int size, const char *label,
196		       section *base ATTRIBUTE_UNUSED,
197		       const char *comment, ...)
198{
199  va_list ap;
200
201  va_start (ap, comment);
202
203#ifdef ASM_OUTPUT_DWARF_OFFSET
204  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label, base);
205#else
206  dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
207#endif
208
209  if (flag_debug_asm && comment)
210    {
211      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
212      vfprintf (asm_out_file, comment, ap);
213    }
214  fputc ('\n', asm_out_file);
215
216  va_end (ap);
217}
218
219#if 0
220
221/* Output a self-relative reference to a label, possibly in a
222   different section or object file.  */
223
224void
225dw2_asm_output_pcrel (int size ATTRIBUTE_UNUSED,
226		      const char *label ATTRIBUTE_UNUSED,
227		      const char *comment, ...)
228{
229  va_list ap;
230
231  va_start (ap, comment);
232
233#ifdef ASM_OUTPUT_DWARF_PCREL
234  ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, label);
235#else
236  dw2_assemble_integer (size,
237			gen_rtx_MINUS (Pmode,
238				       gen_rtx_SYMBOL_REF (Pmode, label),
239				       pc_rtx));
240#endif
241
242  if (flag_debug_asm && comment)
243    {
244      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
245      vfprintf (asm_out_file, comment, ap);
246    }
247  fputc ('\n', asm_out_file);
248
249  va_end (ap);
250}
251#endif /* 0 */
252
253/* Output an absolute reference to a label.  */
254
255void
256dw2_asm_output_addr (int size, const char *label,
257		     const char *comment, ...)
258{
259  va_list ap;
260
261  va_start (ap, comment);
262
263  dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
264
265  if (flag_debug_asm && comment)
266    {
267      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
268      vfprintf (asm_out_file, comment, ap);
269    }
270  fputc ('\n', asm_out_file);
271
272  va_end (ap);
273}
274
275/* Similar, but use an RTX expression instead of a text label.  */
276
277void
278dw2_asm_output_addr_rtx (int size, rtx addr,
279			 const char *comment, ...)
280{
281  va_list ap;
282
283  va_start (ap, comment);
284
285  dw2_assemble_integer (size, addr);
286
287  if (flag_debug_asm && comment)
288    {
289      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
290      vfprintf (asm_out_file, comment, ap);
291    }
292  fputc ('\n', asm_out_file);
293
294  va_end (ap);
295}
296
297/* Output the first ORIG_LEN characters of STR as a string.
298   If ORIG_LEN is equal to -1, ignore this parameter and output
299   the entire STR instead.
300   If COMMENT is not NULL and comments in the debug information
301   have been requested by the user, append the given COMMENT
302   to the generated output.  */
303
304void
305dw2_asm_output_nstring (const char *str, size_t orig_len,
306			const char *comment, ...)
307{
308  size_t i, len;
309  va_list ap;
310
311  va_start (ap, comment);
312
313  len = orig_len;
314
315  if (len == (size_t) -1)
316    len = strlen (str);
317
318  if (flag_debug_asm && comment)
319    {
320      fputs ("\t.ascii \"", asm_out_file);
321      for (i = 0; i < len; i++)
322	{
323	  int c = str[i];
324	  if (c == '\"' || c == '\\')
325	    fputc ('\\', asm_out_file);
326	  if (ISPRINT (c))
327	    fputc (c, asm_out_file);
328	  else
329	    fprintf (asm_out_file, "\\%o", c);
330	}
331      fprintf (asm_out_file, "\\0\"\t%s ", ASM_COMMENT_START);
332      vfprintf (asm_out_file, comment, ap);
333      fputc ('\n', asm_out_file);
334    }
335  else
336    {
337      /* If an explicit length was given, we can't assume there
338	 is a null termination in the string buffer.  */
339      if (orig_len == (size_t) -1)
340	len += 1;
341      ASM_OUTPUT_ASCII (asm_out_file, str, len);
342      if (orig_len != (size_t) -1)
343	assemble_integer (const0_rtx, 1, BITS_PER_UNIT, 1);
344    }
345
346  va_end (ap);
347}
348
349
350/* Return the size of an unsigned LEB128 quantity.  */
351
352int
353size_of_uleb128 (unsigned HOST_WIDE_INT value)
354{
355  int size = 0;
356
357  do
358    {
359      value >>= 7;
360      size += 1;
361    }
362  while (value != 0);
363
364  return size;
365}
366
367/* Return the size of a signed LEB128 quantity.  */
368
369int
370size_of_sleb128 (HOST_WIDE_INT value)
371{
372  int size = 0, byte;
373
374  do
375    {
376      byte = (value & 0x7f);
377      value >>= 7;
378      size += 1;
379    }
380  while (!((value == 0 && (byte & 0x40) == 0)
381	   || (value == -1 && (byte & 0x40) != 0)));
382
383  return size;
384}
385
386/* Given an encoding, return the number of bytes the format occupies.
387   This is only defined for fixed-size encodings, and so does not
388   include leb128.  */
389
390int
391size_of_encoded_value (int encoding)
392{
393  if (encoding == DW_EH_PE_omit)
394    return 0;
395
396  switch (encoding & 0x07)
397    {
398    case DW_EH_PE_absptr:
399      return POINTER_SIZE_UNITS;
400    case DW_EH_PE_udata2:
401      return 2;
402    case DW_EH_PE_udata4:
403      return 4;
404    case DW_EH_PE_udata8:
405      return 8;
406    default:
407      gcc_unreachable ();
408    }
409}
410
411/* Yield a name for a given pointer encoding.  */
412
413const char *
414eh_data_format_name (int format)
415{
416#if HAVE_DESIGNATED_INITIALIZERS
417#define S(p, v)		[p] = v,
418#else
419#define S(p, v)		case p: return v;
420#endif
421
422#if HAVE_DESIGNATED_INITIALIZERS
423  __extension__ static const char * const format_names[256] = {
424#else
425  switch (format) {
426#endif
427
428  S(DW_EH_PE_absptr, "absolute")
429  S(DW_EH_PE_omit, "omit")
430  S(DW_EH_PE_aligned, "aligned absolute")
431
432  S(DW_EH_PE_uleb128, "uleb128")
433  S(DW_EH_PE_udata2, "udata2")
434  S(DW_EH_PE_udata4, "udata4")
435  S(DW_EH_PE_udata8, "udata8")
436  S(DW_EH_PE_sleb128, "sleb128")
437  S(DW_EH_PE_sdata2, "sdata2")
438  S(DW_EH_PE_sdata4, "sdata4")
439  S(DW_EH_PE_sdata8, "sdata8")
440
441  S(DW_EH_PE_absptr | DW_EH_PE_pcrel, "pcrel")
442  S(DW_EH_PE_uleb128 | DW_EH_PE_pcrel, "pcrel uleb128")
443  S(DW_EH_PE_udata2 | DW_EH_PE_pcrel, "pcrel udata2")
444  S(DW_EH_PE_udata4 | DW_EH_PE_pcrel, "pcrel udata4")
445  S(DW_EH_PE_udata8 | DW_EH_PE_pcrel, "pcrel udata8")
446  S(DW_EH_PE_sleb128 | DW_EH_PE_pcrel, "pcrel sleb128")
447  S(DW_EH_PE_sdata2 | DW_EH_PE_pcrel, "pcrel sdata2")
448  S(DW_EH_PE_sdata4 | DW_EH_PE_pcrel, "pcrel sdata4")
449  S(DW_EH_PE_sdata8 | DW_EH_PE_pcrel, "pcrel sdata8")
450
451  S(DW_EH_PE_absptr | DW_EH_PE_textrel, "textrel")
452  S(DW_EH_PE_uleb128 | DW_EH_PE_textrel, "textrel uleb128")
453  S(DW_EH_PE_udata2 | DW_EH_PE_textrel, "textrel udata2")
454  S(DW_EH_PE_udata4 | DW_EH_PE_textrel, "textrel udata4")
455  S(DW_EH_PE_udata8 | DW_EH_PE_textrel, "textrel udata8")
456  S(DW_EH_PE_sleb128 | DW_EH_PE_textrel, "textrel sleb128")
457  S(DW_EH_PE_sdata2 | DW_EH_PE_textrel, "textrel sdata2")
458  S(DW_EH_PE_sdata4 | DW_EH_PE_textrel, "textrel sdata4")
459  S(DW_EH_PE_sdata8 | DW_EH_PE_textrel, "textrel sdata8")
460
461  S(DW_EH_PE_absptr | DW_EH_PE_datarel, "datarel")
462  S(DW_EH_PE_uleb128 | DW_EH_PE_datarel, "datarel uleb128")
463  S(DW_EH_PE_udata2 | DW_EH_PE_datarel, "datarel udata2")
464  S(DW_EH_PE_udata4 | DW_EH_PE_datarel, "datarel udata4")
465  S(DW_EH_PE_udata8 | DW_EH_PE_datarel, "datarel udata8")
466  S(DW_EH_PE_sleb128 | DW_EH_PE_datarel, "datarel sleb128")
467  S(DW_EH_PE_sdata2 | DW_EH_PE_datarel, "datarel sdata2")
468  S(DW_EH_PE_sdata4 | DW_EH_PE_datarel, "datarel sdata4")
469  S(DW_EH_PE_sdata8 | DW_EH_PE_datarel, "datarel sdata8")
470
471  S(DW_EH_PE_absptr | DW_EH_PE_funcrel, "funcrel")
472  S(DW_EH_PE_uleb128 | DW_EH_PE_funcrel, "funcrel uleb128")
473  S(DW_EH_PE_udata2 | DW_EH_PE_funcrel, "funcrel udata2")
474  S(DW_EH_PE_udata4 | DW_EH_PE_funcrel, "funcrel udata4")
475  S(DW_EH_PE_udata8 | DW_EH_PE_funcrel, "funcrel udata8")
476  S(DW_EH_PE_sleb128 | DW_EH_PE_funcrel, "funcrel sleb128")
477  S(DW_EH_PE_sdata2 | DW_EH_PE_funcrel, "funcrel sdata2")
478  S(DW_EH_PE_sdata4 | DW_EH_PE_funcrel, "funcrel sdata4")
479  S(DW_EH_PE_sdata8 | DW_EH_PE_funcrel, "funcrel sdata8")
480
481  S(DW_EH_PE_indirect | DW_EH_PE_absptr, "indirect absolute")
482
483  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_pcrel,
484    "indirect pcrel")
485  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_pcrel,
486    "indirect pcrel uleb128")
487  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_pcrel,
488    "indirect pcrel udata2")
489  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_pcrel,
490    "indirect pcrel udata4")
491  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_pcrel,
492    "indirect pcrel udata8")
493  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_pcrel,
494    "indirect pcrel sleb128")
495  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_pcrel,
496    "indirect pcrel sdata2")
497  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_pcrel,
498    "indirect pcrel sdata4")
499  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_pcrel,
500    "indirect pcrel sdata8")
501
502  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_textrel,
503    "indirect textrel")
504  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_textrel,
505    "indirect textrel uleb128")
506  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_textrel,
507    "indirect textrel udata2")
508  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_textrel,
509    "indirect textrel udata4")
510  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_textrel,
511    "indirect textrel udata8")
512  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_textrel,
513    "indirect textrel sleb128")
514  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_textrel,
515    "indirect textrel sdata2")
516  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_textrel,
517    "indirect textrel sdata4")
518  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_textrel,
519    "indirect textrel sdata8")
520
521  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_datarel,
522    "indirect datarel")
523  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_datarel,
524    "indirect datarel uleb128")
525  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_datarel,
526    "indirect datarel udata2")
527  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_datarel,
528    "indirect datarel udata4")
529  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_datarel,
530    "indirect datarel udata8")
531  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_datarel,
532    "indirect datarel sleb128")
533  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_datarel,
534    "indirect datarel sdata2")
535  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_datarel,
536    "indirect datarel sdata4")
537  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_datarel,
538    "indirect datarel sdata8")
539
540  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_funcrel,
541    "indirect funcrel")
542  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_funcrel,
543    "indirect funcrel uleb128")
544  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_funcrel,
545    "indirect funcrel udata2")
546  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_funcrel,
547    "indirect funcrel udata4")
548  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_funcrel,
549    "indirect funcrel udata8")
550  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_funcrel,
551    "indirect funcrel sleb128")
552  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_funcrel,
553    "indirect funcrel sdata2")
554  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_funcrel,
555    "indirect funcrel sdata4")
556  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_funcrel,
557    "indirect funcrel sdata8")
558
559#if HAVE_DESIGNATED_INITIALIZERS
560  };
561
562  gcc_assert (format >= 0 && format < 0x100 && format_names[format]);
563
564  return format_names[format];
565#else
566  }
567  gcc_unreachable ();
568#endif
569}
570
571/* Output an unsigned LEB128 quantity, but only the byte values.  */
572
573void
574dw2_asm_output_data_uleb128_raw (unsigned HOST_WIDE_INT value)
575{
576  while (1)
577    {
578      int byte = (value & 0x7f);
579      value >>= 7;
580      if (value != 0)
581	/* More bytes to follow.  */
582	byte |= 0x80;
583
584      fprintf (asm_out_file, "%#x", byte);
585      if (value == 0)
586	break;
587      fputc (',', asm_out_file);
588    }
589}
590
591/* Output an unsigned LEB128 quantity.  */
592
593void
594dw2_asm_output_data_uleb128 (unsigned HOST_WIDE_INT value,
595			     const char *comment, ...)
596{
597  va_list ap;
598
599  va_start (ap, comment);
600
601#ifdef HAVE_AS_LEB128
602  fputs ("\t.uleb128 ", asm_out_file);
603  fprint_whex (asm_out_file, value);
604
605  if (flag_debug_asm && comment)
606    {
607      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
608      vfprintf (asm_out_file, comment, ap);
609    }
610#else
611  {
612    unsigned HOST_WIDE_INT work = value;
613    const char *byte_op = targetm.asm_out.byte_op;
614
615    if (byte_op)
616      fputs (byte_op, asm_out_file);
617    do
618      {
619	int byte = (work & 0x7f);
620	work >>= 7;
621	if (work != 0)
622	  /* More bytes to follow.  */
623	  byte |= 0x80;
624
625	if (byte_op)
626	  {
627	    fprintf (asm_out_file, "%#x", byte);
628	    if (work != 0)
629	      fputc (',', asm_out_file);
630	  }
631	else
632	  assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
633      }
634    while (work != 0);
635
636  if (flag_debug_asm)
637    {
638      fprintf (asm_out_file, "\t%s uleb128 " HOST_WIDE_INT_PRINT_HEX,
639	       ASM_COMMENT_START, value);
640      if (comment)
641	{
642	  fputs ("; ", asm_out_file);
643	  vfprintf (asm_out_file, comment, ap);
644	}
645    }
646  }
647#endif
648  putc ('\n', asm_out_file);
649
650  va_end (ap);
651}
652
653/* Output an signed LEB128 quantity, but only the byte values.  */
654
655void
656dw2_asm_output_data_sleb128_raw (HOST_WIDE_INT value)
657{
658  int byte, more;
659
660  while (1)
661    {
662      byte = (value & 0x7f);
663      value >>= 7;
664      more = !((value == 0 && (byte & 0x40) == 0)
665		|| (value == -1 && (byte & 0x40) != 0));
666      if (more)
667	byte |= 0x80;
668
669      fprintf (asm_out_file, "%#x", byte);
670      if (!more)
671	break;
672      fputc (',', asm_out_file);
673    }
674}
675
676/* Output a signed LEB128 quantity.  */
677
678void
679dw2_asm_output_data_sleb128 (HOST_WIDE_INT value,
680			     const char *comment, ...)
681{
682  va_list ap;
683
684  va_start (ap, comment);
685
686#ifdef HAVE_AS_LEB128
687  fprintf (asm_out_file, "\t.sleb128 " HOST_WIDE_INT_PRINT_DEC, value);
688
689  if (flag_debug_asm && comment)
690    {
691      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
692      vfprintf (asm_out_file, comment, ap);
693    }
694#else
695  {
696    HOST_WIDE_INT work = value;
697    int more, byte;
698    const char *byte_op = targetm.asm_out.byte_op;
699
700    if (byte_op)
701      fputs (byte_op, asm_out_file);
702    do
703      {
704	byte = (work & 0x7f);
705	/* arithmetic shift */
706	work >>= 7;
707	more = !((work == 0 && (byte & 0x40) == 0)
708		 || (work == -1 && (byte & 0x40) != 0));
709	if (more)
710	  byte |= 0x80;
711
712	if (byte_op)
713	  {
714	    fprintf (asm_out_file, "%#x", byte);
715	    if (more)
716	      fputc (',', asm_out_file);
717	  }
718	else
719	  assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
720      }
721    while (more);
722
723  if (flag_debug_asm)
724    {
725      fprintf (asm_out_file, "\t%s sleb128 " HOST_WIDE_INT_PRINT_DEC,
726	       ASM_COMMENT_START, value);
727      if (comment)
728	{
729	  fputs ("; ", asm_out_file);
730	  vfprintf (asm_out_file, comment, ap);
731	}
732    }
733  }
734#endif
735  fputc ('\n', asm_out_file);
736
737  va_end (ap);
738}
739
740void
741dw2_asm_output_delta_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
742			      const char *lab2 ATTRIBUTE_UNUSED,
743			      const char *comment, ...)
744{
745  va_list ap;
746
747  va_start (ap, comment);
748
749#ifdef HAVE_AS_LEB128
750  fputs ("\t.uleb128 ", asm_out_file);
751  assemble_name (asm_out_file, lab1);
752  putc ('-', asm_out_file);
753  assemble_name (asm_out_file, lab2);
754#else
755  gcc_unreachable ();
756#endif
757
758  if (flag_debug_asm && comment)
759    {
760      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
761      vfprintf (asm_out_file, comment, ap);
762    }
763  fputc ('\n', asm_out_file);
764
765  va_end (ap);
766}
767
768#if 0
769
770void
771dw2_asm_output_delta_sleb128 (const char *lab1 ATTRIBUTE_UNUSED,
772			      const char *lab2 ATTRIBUTE_UNUSED,
773			      const char *comment, ...)
774{
775  va_list ap;
776
777  va_start (ap, comment);
778
779#ifdef HAVE_AS_LEB128
780  fputs ("\t.sleb128 ", asm_out_file);
781  assemble_name (asm_out_file, lab1);
782  putc ('-', asm_out_file);
783  assemble_name (asm_out_file, lab2);
784#else
785  gcc_unreachable ();
786#endif
787
788  if (flag_debug_asm && comment)
789    {
790      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
791      vfprintf (asm_out_file, comment, ap);
792    }
793  fputc ('\n', asm_out_file);
794
795  va_end (ap);
796}
797#endif /* 0 */
798
799static GTY(()) hash_map<const char *, tree> *indirect_pool;
800
801static GTY(()) int dw2_const_labelno;
802
803#if defined(HAVE_GAS_HIDDEN)
804# define USE_LINKONCE_INDIRECT (SUPPORTS_ONE_ONLY)
805#else
806# define USE_LINKONCE_INDIRECT 0
807#endif
808
809/* Compare two std::pair<const char *, tree> by their first element.
810   Returns <0, 0, or
811   >0 to indicate whether K1 is less than, equal to, or greater than
812   K2, respectively.  */
813
814static int
815compare_strings (const void *a, const void *b)
816{
817  const char *s1 = ((const std::pair<const char *, tree> *) a)->first;
818  const char *s2 = ((const std::pair<const char *, tree> *) b)->first;
819  int ret;
820
821  if (s1 == s2)
822    return 0;
823
824  ret = strcmp (s1, s2);
825
826  /* The strings are always those from IDENTIFIER_NODEs, and,
827     therefore, we should never have two copies of the same
828     string.  */
829  gcc_assert (ret);
830
831  return ret;
832}
833
834/* Put X, a SYMBOL_REF, in memory.  Return a SYMBOL_REF to the allocated
835   memory.  Differs from force_const_mem in that a single pool is used for
836   the entire unit of translation, and the memory is not guaranteed to be
837   "near" the function in any interesting sense.  IS_PUBLIC controls whether
838   the symbol can be shared across the entire application (or DSO).  */
839
840rtx
841dw2_force_const_mem (rtx x, bool is_public)
842{
843  const char *key;
844  tree decl_id;
845
846  if (! indirect_pool)
847    indirect_pool = hash_map<const char *, tree>::create_ggc (64);
848
849  gcc_assert (GET_CODE (x) == SYMBOL_REF);
850
851  key = XSTR (x, 0);
852  tree *slot = indirect_pool->get (key);
853  if (slot)
854    decl_id = *slot;
855  else
856    {
857      tree id;
858      const char *str = targetm.strip_name_encoding (key);
859
860      if (is_public && USE_LINKONCE_INDIRECT)
861	{
862	  char *ref_name = XALLOCAVEC (char, strlen (str) + sizeof "DW.ref.");
863
864	  sprintf (ref_name, "DW.ref.%s", str);
865	  gcc_assert (!maybe_get_identifier (ref_name));
866	  decl_id = get_identifier (ref_name);
867	  TREE_PUBLIC (decl_id) = 1;
868	}
869      else
870	{
871	  char label[32];
872
873	  ASM_GENERATE_INTERNAL_LABEL (label, "LDFCM", dw2_const_labelno);
874	  ++dw2_const_labelno;
875	  gcc_assert (!maybe_get_identifier (label));
876	  decl_id = get_identifier (label);
877	}
878
879      id = maybe_get_identifier (str);
880      if (id)
881	TREE_SYMBOL_REFERENCED (id) = 1;
882
883      indirect_pool->put (key, decl_id);
884    }
885
886  return gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (decl_id));
887}
888
889/* A helper function for dw2_output_indirect_constants.  Emit one queued
890   constant to memory.  */
891
892static int
893dw2_output_indirect_constant_1 (const char *sym, tree id)
894{
895  rtx sym_ref;
896  tree decl;
897
898  decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, id, ptr_type_node);
899  SET_DECL_ASSEMBLER_NAME (decl, id);
900  DECL_ARTIFICIAL (decl) = 1;
901  DECL_IGNORED_P (decl) = 1;
902  DECL_INITIAL (decl) = decl;
903  TREE_READONLY (decl) = 1;
904  TREE_STATIC (decl) = 1;
905
906  if (TREE_PUBLIC (id))
907    {
908      TREE_PUBLIC (decl) = 1;
909      make_decl_one_only (decl, DECL_ASSEMBLER_NAME (decl));
910      if (USE_LINKONCE_INDIRECT)
911	DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
912    }
913
914  sym_ref = gen_rtx_SYMBOL_REF (Pmode, sym);
915  assemble_variable (decl, 1, 1, 1);
916  assemble_integer (sym_ref, POINTER_SIZE_UNITS, POINTER_SIZE, 1);
917
918  return 0;
919}
920
921/* Emit the constants queued through dw2_force_const_mem.  */
922
923void
924dw2_output_indirect_constants (void)
925{
926  if (!indirect_pool)
927    return;
928
929  auto_vec<std::pair<const char *, tree> > temp (indirect_pool->elements ());
930  for (hash_map<const char *, tree>::iterator iter = indirect_pool->begin ();
931       iter != indirect_pool->end (); ++iter)
932    temp.quick_push (*iter);
933
934    temp.qsort (compare_strings);
935
936    for (unsigned int i = 0; i < temp.length (); i++)
937    dw2_output_indirect_constant_1 (temp[i].first, temp[i].second);
938}
939
940/* Like dw2_asm_output_addr_rtx, but encode the pointer as directed.
941   If PUBLIC is set and the encoding is DW_EH_PE_indirect, the indirect
942   reference is shared across the entire application (or DSO).  */
943
944void
945dw2_asm_output_encoded_addr_rtx (int encoding, rtx addr, bool is_public,
946				 const char *comment, ...)
947{
948  int size;
949  va_list ap;
950
951  va_start (ap, comment);
952
953  size = size_of_encoded_value (encoding);
954
955  if (encoding == DW_EH_PE_aligned)
956    {
957      assemble_align (POINTER_SIZE);
958      assemble_integer (addr, size, POINTER_SIZE, 1);
959      va_end (ap);
960      return;
961    }
962
963  /* NULL is _always_ represented as a plain zero, as is 1 for Ada's
964     "all others".  */
965  if (addr == const0_rtx || addr == const1_rtx)
966    assemble_integer (addr, size, BITS_PER_UNIT, 1);
967  else
968    {
969    restart:
970      /* Allow the target first crack at emitting this.  Some of the
971	 special relocations require special directives instead of
972	 just ".4byte" or whatever.  */
973#ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
974      ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX (asm_out_file, encoding, size,
975					 addr, done);
976#endif
977
978      /* Indirection is used to get dynamic relocations out of a
979	 read-only section.  */
980      if (encoding & DW_EH_PE_indirect)
981	{
982	  /* It is very tempting to use force_const_mem so that we share data
983	     with the normal constant pool.  However, we've already emitted
984	     the constant pool for this function.  Moreover, we'd like to
985	     share these constants across the entire unit of translation and
986	     even, if possible, across the entire application (or DSO).  */
987	  addr = dw2_force_const_mem (addr, is_public);
988	  encoding &= ~DW_EH_PE_indirect;
989	  goto restart;
990	}
991
992      switch (encoding & 0xF0)
993	{
994	case DW_EH_PE_absptr:
995	  dw2_assemble_integer (size, addr);
996	  break;
997
998	case DW_EH_PE_pcrel:
999	  gcc_assert (GET_CODE (addr) == SYMBOL_REF);
1000#ifdef ASM_OUTPUT_DWARF_PCREL
1001	  ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, XSTR (addr, 0));
1002#else
1003	  dw2_assemble_integer (size, gen_rtx_MINUS (Pmode, addr, pc_rtx));
1004#endif
1005	  break;
1006
1007	default:
1008	  /* Other encodings should have been handled by
1009	     ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX.  */
1010	  gcc_unreachable ();
1011	}
1012
1013#ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
1014    done:;
1015#endif
1016    }
1017
1018  if (flag_debug_asm && comment)
1019    {
1020      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
1021      vfprintf (asm_out_file, comment, ap);
1022    }
1023  fputc ('\n', asm_out_file);
1024
1025  va_end (ap);
1026}
1027
1028#include "gt-dwarf2asm.h"
1029