190075Sobrien/* Dwarf2 assembler output helper routines.
2169689Skan   Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
390075Sobrien
490075SobrienThis file is part of GCC.
590075Sobrien
690075SobrienGCC is free software; you can redistribute it and/or modify it under
790075Sobrienthe terms of the GNU General Public License as published by the Free
890075SobrienSoftware Foundation; either version 2, or (at your option) any later
990075Sobrienversion.
1090075Sobrien
1190075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1290075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1390075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1490075Sobrienfor more details.
1590075Sobrien
1690075SobrienYou should have received a copy of the GNU General Public License
1790075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
18169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
19169689Skan02110-1301, USA.  */
2090075Sobrien
2190075Sobrien
2290075Sobrien#include "config.h"
2390075Sobrien#include "system.h"
24132718Skan#include "coretypes.h"
25132718Skan#include "tm.h"
2690075Sobrien#include "flags.h"
2790075Sobrien#include "tree.h"
2890075Sobrien#include "rtl.h"
2990075Sobrien#include "output.h"
3090075Sobrien#include "target.h"
3190075Sobrien#include "dwarf2asm.h"
3290075Sobrien#include "dwarf2.h"
3390075Sobrien#include "splay-tree.h"
3490075Sobrien#include "ggc.h"
3590075Sobrien#include "tm_p.h"
3690075Sobrien
3790075Sobrien
3890075Sobrien/* How to start an assembler comment.  */
3990075Sobrien#ifndef ASM_COMMENT_START
4090075Sobrien#define ASM_COMMENT_START ";#"
4190075Sobrien#endif
4290075Sobrien
4390075Sobrien
4490075Sobrien/* Output an unaligned integer with the given value and size.  Prefer not
4590075Sobrien   to print a newline, since the caller may want to add a comment.  */
4690075Sobrien
4790075Sobrienvoid
48132718Skandw2_assemble_integer (int size, rtx x)
4990075Sobrien{
5090075Sobrien  const char *op = integer_asm_op (size, FALSE);
5190075Sobrien
5290075Sobrien  if (op)
5390075Sobrien    {
5490075Sobrien      fputs (op, asm_out_file);
5590075Sobrien      if (GET_CODE (x) == CONST_INT)
5690075Sobrien	fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
5790075Sobrien      else
5890075Sobrien	output_addr_const (asm_out_file, x);
5990075Sobrien    }
6090075Sobrien  else
6190075Sobrien    assemble_integer (x, size, BITS_PER_UNIT, 1);
6290075Sobrien}
6390075Sobrien
64117395Skan
6590075Sobrien/* Output an immediate constant in a given size.  */
6690075Sobrien
6790075Sobrienvoid
68132718Skandw2_asm_output_data (int size, unsigned HOST_WIDE_INT value,
69132718Skan		     const char *comment, ...)
7090075Sobrien{
71132718Skan  va_list ap;
72169689Skan  const char *op = integer_asm_op (size, FALSE);
7390075Sobrien
74132718Skan  va_start (ap, comment);
75132718Skan
7690075Sobrien  if (size * 8 < HOST_BITS_PER_WIDE_INT)
7790075Sobrien    value &= ~(~(unsigned HOST_WIDE_INT) 0 << (size * 8));
7890075Sobrien
79169689Skan  if (op)
80169689Skan    fprintf (asm_out_file, "%s" HOST_WIDE_INT_PRINT_HEX, op, value);
81169689Skan  else
82169689Skan    assemble_integer (GEN_INT (value), size, BITS_PER_UNIT, 1);
8390075Sobrien
8490075Sobrien  if (flag_debug_asm && comment)
8590075Sobrien    {
8690075Sobrien      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
8790075Sobrien      vfprintf (asm_out_file, comment, ap);
8890075Sobrien    }
8990075Sobrien  fputc ('\n', asm_out_file);
9090075Sobrien
91132718Skan  va_end (ap);
9290075Sobrien}
9390075Sobrien
9490075Sobrien/* Output the difference between two symbols in a given size.  */
9590075Sobrien/* ??? There appear to be assemblers that do not like such
9690075Sobrien   subtraction, but do support ASM_SET_OP.  It's unfortunately
9790075Sobrien   impossible to do here, since the ASM_SET_OP for the difference
9890075Sobrien   symbol must appear after both symbols are defined.  */
9990075Sobrien
10090075Sobrienvoid
101132718Skandw2_asm_output_delta (int size, const char *lab1, const char *lab2,
102132718Skan		      const char *comment, ...)
10390075Sobrien{
104132718Skan  va_list ap;
10590075Sobrien
106132718Skan  va_start (ap, comment);
107132718Skan
108117395Skan#ifdef ASM_OUTPUT_DWARF_DELTA
109117395Skan  ASM_OUTPUT_DWARF_DELTA (asm_out_file, size, lab1, lab2);
110117395Skan#else
11190075Sobrien  dw2_assemble_integer (size,
11290075Sobrien			gen_rtx_MINUS (Pmode,
11390075Sobrien				       gen_rtx_SYMBOL_REF (Pmode, lab1),
11490075Sobrien				       gen_rtx_SYMBOL_REF (Pmode, lab2)));
115117395Skan#endif
11690075Sobrien  if (flag_debug_asm && comment)
11790075Sobrien    {
11890075Sobrien      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
11990075Sobrien      vfprintf (asm_out_file, comment, ap);
12090075Sobrien    }
12190075Sobrien  fputc ('\n', asm_out_file);
12290075Sobrien
123132718Skan  va_end (ap);
12490075Sobrien}
12590075Sobrien
126169689Skan/* Output a section-relative reference to a LABEL, which was placed in
127169689Skan   BASE.  In general this can only be done for debugging symbols.
128169689Skan   E.g. on most targets with the GNU linker, this is accomplished with
129169689Skan   a direct reference and the knowledge that the debugging section
130169689Skan   will be placed at VMA 0.  Some targets have special relocations for
131169689Skan   this that we must use.  */
13290075Sobrien
13390075Sobrienvoid
134132718Skandw2_asm_output_offset (int size, const char *label,
135169689Skan		       section *base ATTRIBUTE_UNUSED,
136132718Skan		       const char *comment, ...)
13790075Sobrien{
138132718Skan  va_list ap;
13990075Sobrien
140132718Skan  va_start (ap, comment);
141132718Skan
14290075Sobrien#ifdef ASM_OUTPUT_DWARF_OFFSET
143169689Skan  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label, base);
14490075Sobrien#else
14590075Sobrien  dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
14690075Sobrien#endif
14790075Sobrien
14890075Sobrien  if (flag_debug_asm && comment)
14990075Sobrien    {
15090075Sobrien      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
15190075Sobrien      vfprintf (asm_out_file, comment, ap);
15290075Sobrien    }
15390075Sobrien  fputc ('\n', asm_out_file);
15490075Sobrien
155132718Skan  va_end (ap);
15690075Sobrien}
15790075Sobrien
158169689Skan#if 0
159169689Skan
16090075Sobrien/* Output a self-relative reference to a label, possibly in a
16190075Sobrien   different section or object file.  */
16290075Sobrien
16390075Sobrienvoid
164132718Skandw2_asm_output_pcrel (int size ATTRIBUTE_UNUSED,
165132718Skan		      const char *label ATTRIBUTE_UNUSED,
166132718Skan		      const char *comment, ...)
16790075Sobrien{
168132718Skan  va_list ap;
16990075Sobrien
170132718Skan  va_start (ap, comment);
171132718Skan
17290075Sobrien#ifdef ASM_OUTPUT_DWARF_PCREL
17390075Sobrien  ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, label);
17490075Sobrien#else
17590075Sobrien  dw2_assemble_integer (size,
17690075Sobrien			gen_rtx_MINUS (Pmode,
17790075Sobrien				       gen_rtx_SYMBOL_REF (Pmode, label),
17890075Sobrien				       pc_rtx));
17990075Sobrien#endif
18090075Sobrien
18190075Sobrien  if (flag_debug_asm && comment)
18290075Sobrien    {
18390075Sobrien      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
18490075Sobrien      vfprintf (asm_out_file, comment, ap);
18590075Sobrien    }
18690075Sobrien  fputc ('\n', asm_out_file);
18790075Sobrien
188132718Skan  va_end (ap);
18990075Sobrien}
190169689Skan#endif /* 0 */
19190075Sobrien
19290075Sobrien/* Output an absolute reference to a label.  */
19390075Sobrien
19490075Sobrienvoid
195132718Skandw2_asm_output_addr (int size, const char *label,
196132718Skan		     const char *comment, ...)
19790075Sobrien{
198132718Skan  va_list ap;
19990075Sobrien
200132718Skan  va_start (ap, comment);
201132718Skan
20290075Sobrien  dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
20390075Sobrien
20490075Sobrien  if (flag_debug_asm && comment)
20590075Sobrien    {
20690075Sobrien      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
20790075Sobrien      vfprintf (asm_out_file, comment, ap);
20890075Sobrien    }
20990075Sobrien  fputc ('\n', asm_out_file);
21090075Sobrien
211132718Skan  va_end (ap);
21290075Sobrien}
21390075Sobrien
21490075Sobrien/* Similar, but use an RTX expression instead of a text label.  */
21590075Sobrien
21690075Sobrienvoid
217132718Skandw2_asm_output_addr_rtx (int size, rtx addr,
218132718Skan			 const char *comment, ...)
21990075Sobrien{
220132718Skan  va_list ap;
22190075Sobrien
222132718Skan  va_start (ap, comment);
223132718Skan
22490075Sobrien  dw2_assemble_integer (size, addr);
22590075Sobrien
22690075Sobrien  if (flag_debug_asm && comment)
22790075Sobrien    {
22890075Sobrien      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
22990075Sobrien      vfprintf (asm_out_file, comment, ap);
23090075Sobrien    }
23190075Sobrien  fputc ('\n', asm_out_file);
23290075Sobrien
233132718Skan  va_end (ap);
23490075Sobrien}
23590075Sobrien
236132718Skan/* Output the first ORIG_LEN characters of STR as a string.
237132718Skan   If ORIG_LEN is equal to -1, ignore this parameter and output
238132718Skan   the entire STR instead.
239132718Skan   If COMMENT is not NULL and comments in the debug information
240132718Skan   have been requested by the user, append the given COMMENT
241132718Skan   to the generated output.  */
242132718Skan
24390075Sobrienvoid
244132718Skandw2_asm_output_nstring (const char *str, size_t orig_len,
245132718Skan			const char *comment, ...)
24690075Sobrien{
24790075Sobrien  size_t i, len;
248132718Skan  va_list ap;
24990075Sobrien
250132718Skan  va_start (ap, comment);
25190075Sobrien
25290075Sobrien  len = orig_len;
25390075Sobrien
25490075Sobrien  if (len == (size_t) -1)
25590075Sobrien    len = strlen (str);
25690075Sobrien
25790075Sobrien  if (flag_debug_asm && comment)
25890075Sobrien    {
25990075Sobrien      fputs ("\t.ascii \"", asm_out_file);
26090075Sobrien      for (i = 0; i < len; i++)
26190075Sobrien	{
26290075Sobrien	  int c = str[i];
26390075Sobrien	  if (c == '\"' || c == '\\')
26490075Sobrien	    fputc ('\\', asm_out_file);
26590075Sobrien	  if (ISPRINT(c))
26690075Sobrien	    fputc (c, asm_out_file);
26790075Sobrien	  else
26890075Sobrien	    fprintf (asm_out_file, "\\%o", c);
26990075Sobrien	}
27090075Sobrien      fprintf (asm_out_file, "\\0\"\t%s ", ASM_COMMENT_START);
27190075Sobrien      vfprintf (asm_out_file, comment, ap);
27290075Sobrien      fputc ('\n', asm_out_file);
27390075Sobrien    }
27490075Sobrien  else
27590075Sobrien    {
27690075Sobrien      /* If an explicit length was given, we can't assume there
27790075Sobrien	 is a null termination in the string buffer.  */
27890075Sobrien      if (orig_len == (size_t) -1)
27990075Sobrien	len += 1;
28090075Sobrien      ASM_OUTPUT_ASCII (asm_out_file, str, len);
28190075Sobrien      if (orig_len != (size_t) -1)
28290075Sobrien	assemble_integer (const0_rtx, 1, BITS_PER_UNIT, 1);
28390075Sobrien    }
28490075Sobrien
285132718Skan  va_end (ap);
28690075Sobrien}
28790075Sobrien
28890075Sobrien
28990075Sobrien/* Return the size of an unsigned LEB128 quantity.  */
29090075Sobrien
29190075Sobrienint
292132718Skansize_of_uleb128 (unsigned HOST_WIDE_INT value)
29390075Sobrien{
294132718Skan  int size = 0;
29590075Sobrien
29690075Sobrien  do
29790075Sobrien    {
29890075Sobrien      value >>= 7;
29990075Sobrien      size += 1;
30090075Sobrien    }
30190075Sobrien  while (value != 0);
30290075Sobrien
30390075Sobrien  return size;
30490075Sobrien}
30590075Sobrien
30690075Sobrien/* Return the size of a signed LEB128 quantity.  */
30790075Sobrien
30890075Sobrienint
309132718Skansize_of_sleb128 (HOST_WIDE_INT value)
31090075Sobrien{
31190075Sobrien  int size = 0, byte;
31290075Sobrien
31390075Sobrien  do
31490075Sobrien    {
31590075Sobrien      byte = (value & 0x7f);
31690075Sobrien      value >>= 7;
31790075Sobrien      size += 1;
31890075Sobrien    }
31990075Sobrien  while (!((value == 0 && (byte & 0x40) == 0)
32090075Sobrien	   || (value == -1 && (byte & 0x40) != 0)));
32190075Sobrien
32290075Sobrien  return size;
32390075Sobrien}
32490075Sobrien
32590075Sobrien/* Given an encoding, return the number of bytes the format occupies.
326117395Skan   This is only defined for fixed-size encodings, and so does not
32790075Sobrien   include leb128.  */
32890075Sobrien
32990075Sobrienint
330132718Skansize_of_encoded_value (int encoding)
33190075Sobrien{
33290075Sobrien  if (encoding == DW_EH_PE_omit)
33390075Sobrien    return 0;
33490075Sobrien
33590075Sobrien  switch (encoding & 0x07)
33690075Sobrien    {
33790075Sobrien    case DW_EH_PE_absptr:
33890075Sobrien      return POINTER_SIZE / BITS_PER_UNIT;
33990075Sobrien    case DW_EH_PE_udata2:
34090075Sobrien      return 2;
34190075Sobrien    case DW_EH_PE_udata4:
34290075Sobrien      return 4;
34390075Sobrien    case DW_EH_PE_udata8:
34490075Sobrien      return 8;
345169689Skan    default:
346169689Skan      gcc_unreachable ();
34790075Sobrien    }
34890075Sobrien}
34990075Sobrien
35090075Sobrien/* Yield a name for a given pointer encoding.  */
35190075Sobrien
35290075Sobrienconst char *
353132718Skaneh_data_format_name (int format)
35490075Sobrien{
35590075Sobrien#if HAVE_DESIGNATED_INITIALIZERS
35690075Sobrien#define S(p, v)		[p] = v,
35790075Sobrien#else
35890075Sobrien#define S(p, v)		case p: return v;
35990075Sobrien#endif
36090075Sobrien
36190075Sobrien#if HAVE_DESIGNATED_INITIALIZERS
36290075Sobrien  __extension__ static const char * const format_names[256] = {
36390075Sobrien#else
36490075Sobrien  switch (format) {
36590075Sobrien#endif
36690075Sobrien
36790075Sobrien  S(DW_EH_PE_absptr, "absolute")
36890075Sobrien  S(DW_EH_PE_omit, "omit")
36990075Sobrien  S(DW_EH_PE_aligned, "aligned absolute")
37090075Sobrien
37190075Sobrien  S(DW_EH_PE_uleb128, "uleb128")
37290075Sobrien  S(DW_EH_PE_udata2, "udata2")
37390075Sobrien  S(DW_EH_PE_udata4, "udata4")
37490075Sobrien  S(DW_EH_PE_udata8, "udata8")
37590075Sobrien  S(DW_EH_PE_sleb128, "sleb128")
37690075Sobrien  S(DW_EH_PE_sdata2, "sdata2")
37790075Sobrien  S(DW_EH_PE_sdata4, "sdata4")
37890075Sobrien  S(DW_EH_PE_sdata8, "sdata8")
37990075Sobrien
38090075Sobrien  S(DW_EH_PE_absptr | DW_EH_PE_pcrel, "pcrel")
38190075Sobrien  S(DW_EH_PE_uleb128 | DW_EH_PE_pcrel, "pcrel uleb128")
38290075Sobrien  S(DW_EH_PE_udata2 | DW_EH_PE_pcrel, "pcrel udata2")
38390075Sobrien  S(DW_EH_PE_udata4 | DW_EH_PE_pcrel, "pcrel udata4")
38490075Sobrien  S(DW_EH_PE_udata8 | DW_EH_PE_pcrel, "pcrel udata8")
38590075Sobrien  S(DW_EH_PE_sleb128 | DW_EH_PE_pcrel, "pcrel sleb128")
38690075Sobrien  S(DW_EH_PE_sdata2 | DW_EH_PE_pcrel, "pcrel sdata2")
38790075Sobrien  S(DW_EH_PE_sdata4 | DW_EH_PE_pcrel, "pcrel sdata4")
38890075Sobrien  S(DW_EH_PE_sdata8 | DW_EH_PE_pcrel, "pcrel sdata8")
38990075Sobrien
39090075Sobrien  S(DW_EH_PE_absptr | DW_EH_PE_textrel, "textrel")
39190075Sobrien  S(DW_EH_PE_uleb128 | DW_EH_PE_textrel, "textrel uleb128")
39290075Sobrien  S(DW_EH_PE_udata2 | DW_EH_PE_textrel, "textrel udata2")
39390075Sobrien  S(DW_EH_PE_udata4 | DW_EH_PE_textrel, "textrel udata4")
39490075Sobrien  S(DW_EH_PE_udata8 | DW_EH_PE_textrel, "textrel udata8")
39590075Sobrien  S(DW_EH_PE_sleb128 | DW_EH_PE_textrel, "textrel sleb128")
39690075Sobrien  S(DW_EH_PE_sdata2 | DW_EH_PE_textrel, "textrel sdata2")
39790075Sobrien  S(DW_EH_PE_sdata4 | DW_EH_PE_textrel, "textrel sdata4")
39890075Sobrien  S(DW_EH_PE_sdata8 | DW_EH_PE_textrel, "textrel sdata8")
39990075Sobrien
40090075Sobrien  S(DW_EH_PE_absptr | DW_EH_PE_datarel, "datarel")
40190075Sobrien  S(DW_EH_PE_uleb128 | DW_EH_PE_datarel, "datarel uleb128")
40290075Sobrien  S(DW_EH_PE_udata2 | DW_EH_PE_datarel, "datarel udata2")
40390075Sobrien  S(DW_EH_PE_udata4 | DW_EH_PE_datarel, "datarel udata4")
40490075Sobrien  S(DW_EH_PE_udata8 | DW_EH_PE_datarel, "datarel udata8")
40590075Sobrien  S(DW_EH_PE_sleb128 | DW_EH_PE_datarel, "datarel sleb128")
40690075Sobrien  S(DW_EH_PE_sdata2 | DW_EH_PE_datarel, "datarel sdata2")
40790075Sobrien  S(DW_EH_PE_sdata4 | DW_EH_PE_datarel, "datarel sdata4")
40890075Sobrien  S(DW_EH_PE_sdata8 | DW_EH_PE_datarel, "datarel sdata8")
40990075Sobrien
41090075Sobrien  S(DW_EH_PE_absptr | DW_EH_PE_funcrel, "funcrel")
41190075Sobrien  S(DW_EH_PE_uleb128 | DW_EH_PE_funcrel, "funcrel uleb128")
41290075Sobrien  S(DW_EH_PE_udata2 | DW_EH_PE_funcrel, "funcrel udata2")
41390075Sobrien  S(DW_EH_PE_udata4 | DW_EH_PE_funcrel, "funcrel udata4")
41490075Sobrien  S(DW_EH_PE_udata8 | DW_EH_PE_funcrel, "funcrel udata8")
41590075Sobrien  S(DW_EH_PE_sleb128 | DW_EH_PE_funcrel, "funcrel sleb128")
41690075Sobrien  S(DW_EH_PE_sdata2 | DW_EH_PE_funcrel, "funcrel sdata2")
41790075Sobrien  S(DW_EH_PE_sdata4 | DW_EH_PE_funcrel, "funcrel sdata4")
41890075Sobrien  S(DW_EH_PE_sdata8 | DW_EH_PE_funcrel, "funcrel sdata8")
41990075Sobrien
42090075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_pcrel,
42190075Sobrien    "indirect pcrel")
42290075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_pcrel,
42390075Sobrien    "indirect pcrel uleb128")
42490075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_pcrel,
42590075Sobrien    "indirect pcrel udata2")
42690075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_pcrel,
42790075Sobrien    "indirect pcrel udata4")
42890075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_pcrel,
42990075Sobrien    "indirect pcrel udata8")
43090075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_pcrel,
43190075Sobrien    "indirect pcrel sleb128")
43290075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_pcrel,
43390075Sobrien    "indirect pcrel sdata2")
43490075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_pcrel,
43590075Sobrien    "indirect pcrel sdata4")
43690075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_pcrel,
43790075Sobrien    "indirect pcrel sdata8")
43890075Sobrien
43990075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_textrel,
44090075Sobrien    "indirect textrel")
44190075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_textrel,
44290075Sobrien    "indirect textrel uleb128")
44390075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_textrel,
44490075Sobrien    "indirect textrel udata2")
44590075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_textrel,
44690075Sobrien    "indirect textrel udata4")
44790075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_textrel,
44890075Sobrien    "indirect textrel udata8")
44990075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_textrel,
45090075Sobrien    "indirect textrel sleb128")
45190075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_textrel,
45290075Sobrien    "indirect textrel sdata2")
45390075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_textrel,
45490075Sobrien    "indirect textrel sdata4")
45590075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_textrel,
45690075Sobrien    "indirect textrel sdata8")
45790075Sobrien
45890075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_datarel,
45990075Sobrien    "indirect datarel")
46090075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_datarel,
46190075Sobrien    "indirect datarel uleb128")
46290075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_datarel,
46390075Sobrien    "indirect datarel udata2")
46490075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_datarel,
46590075Sobrien    "indirect datarel udata4")
46690075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_datarel,
46790075Sobrien    "indirect datarel udata8")
46890075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_datarel,
46990075Sobrien    "indirect datarel sleb128")
47090075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_datarel,
47190075Sobrien    "indirect datarel sdata2")
47290075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_datarel,
47390075Sobrien    "indirect datarel sdata4")
47490075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_datarel,
47590075Sobrien    "indirect datarel sdata8")
47690075Sobrien
47790075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_funcrel,
47890075Sobrien    "indirect funcrel")
47990075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_funcrel,
48090075Sobrien    "indirect funcrel uleb128")
48190075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_funcrel,
48290075Sobrien    "indirect funcrel udata2")
48390075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_funcrel,
48490075Sobrien    "indirect funcrel udata4")
48590075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_funcrel,
48690075Sobrien    "indirect funcrel udata8")
48790075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_funcrel,
48890075Sobrien    "indirect funcrel sleb128")
48990075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_funcrel,
49090075Sobrien    "indirect funcrel sdata2")
49190075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_funcrel,
49290075Sobrien    "indirect funcrel sdata4")
49390075Sobrien  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_funcrel,
49490075Sobrien    "indirect funcrel sdata8")
49590075Sobrien
49690075Sobrien#if HAVE_DESIGNATED_INITIALIZERS
49790075Sobrien  };
49890075Sobrien
499169689Skan  gcc_assert (format >= 0 && format < 0x100 && format_names[format]);
500169689Skan
50190075Sobrien  return format_names[format];
50290075Sobrien#else
50390075Sobrien  }
504169689Skan  gcc_unreachable ();
50590075Sobrien#endif
50690075Sobrien}
50790075Sobrien
50890075Sobrien/* Output an unsigned LEB128 quantity.  */
50990075Sobrien
51090075Sobrienvoid
511132718Skandw2_asm_output_data_uleb128 (unsigned HOST_WIDE_INT value,
512132718Skan			     const char *comment, ...)
51390075Sobrien{
514132718Skan  va_list ap;
51590075Sobrien
516132718Skan  va_start (ap, comment);
517132718Skan
51890075Sobrien#ifdef HAVE_AS_LEB128
519132718Skan  fprintf (asm_out_file, "\t.uleb128 " HOST_WIDE_INT_PRINT_HEX , value);
52090075Sobrien
52190075Sobrien  if (flag_debug_asm && comment)
52290075Sobrien    {
52390075Sobrien      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
52490075Sobrien      vfprintf (asm_out_file, comment, ap);
52590075Sobrien    }
52690075Sobrien#else
52790075Sobrien  {
52890075Sobrien    unsigned HOST_WIDE_INT work = value;
52990075Sobrien    const char *byte_op = targetm.asm_out.byte_op;
53090075Sobrien
53190075Sobrien    if (byte_op)
53290075Sobrien      fputs (byte_op, asm_out_file);
53390075Sobrien    do
53490075Sobrien      {
53590075Sobrien	int byte = (work & 0x7f);
53690075Sobrien	work >>= 7;
53790075Sobrien	if (work != 0)
53890075Sobrien	  /* More bytes to follow.  */
53990075Sobrien	  byte |= 0x80;
54090075Sobrien
54190075Sobrien	if (byte_op)
54290075Sobrien	  {
54390075Sobrien	    fprintf (asm_out_file, "0x%x", byte);
54490075Sobrien	    if (work != 0)
54590075Sobrien	      fputc (',', asm_out_file);
54690075Sobrien	  }
54790075Sobrien	else
54890075Sobrien	  assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
54990075Sobrien      }
55090075Sobrien    while (work != 0);
55190075Sobrien
55290075Sobrien  if (flag_debug_asm)
55390075Sobrien    {
554132718Skan      fprintf (asm_out_file, "\t%s uleb128 " HOST_WIDE_INT_PRINT_HEX,
555132718Skan	       ASM_COMMENT_START, value);
55690075Sobrien      if (comment)
55790075Sobrien	{
55890075Sobrien	  fputs ("; ", asm_out_file);
55990075Sobrien	  vfprintf (asm_out_file, comment, ap);
56090075Sobrien	}
56190075Sobrien    }
56290075Sobrien  }
56390075Sobrien#endif
56490075Sobrien  fputc ('\n', asm_out_file);
56590075Sobrien
566132718Skan  va_end (ap);
56790075Sobrien}
56890075Sobrien
569117395Skan/* Output a signed LEB128 quantity.  */
57090075Sobrien
57190075Sobrienvoid
572132718Skandw2_asm_output_data_sleb128 (HOST_WIDE_INT value,
573132718Skan			     const char *comment, ...)
57490075Sobrien{
575132718Skan  va_list ap;
57690075Sobrien
577132718Skan  va_start (ap, comment);
578132718Skan
57990075Sobrien#ifdef HAVE_AS_LEB128
580132718Skan  fprintf (asm_out_file, "\t.sleb128 " HOST_WIDE_INT_PRINT_DEC, value);
58190075Sobrien
58290075Sobrien  if (flag_debug_asm && comment)
58390075Sobrien    {
58490075Sobrien      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
58590075Sobrien      vfprintf (asm_out_file, comment, ap);
58690075Sobrien    }
58790075Sobrien#else
58890075Sobrien  {
58990075Sobrien    HOST_WIDE_INT work = value;
59090075Sobrien    int more, byte;
59190075Sobrien    const char *byte_op = targetm.asm_out.byte_op;
59290075Sobrien
59390075Sobrien    if (byte_op)
59490075Sobrien      fputs (byte_op, asm_out_file);
59590075Sobrien    do
59690075Sobrien      {
59790075Sobrien	byte = (work & 0x7f);
59890075Sobrien	/* arithmetic shift */
59990075Sobrien	work >>= 7;
60090075Sobrien	more = !((work == 0 && (byte & 0x40) == 0)
60190075Sobrien		 || (work == -1 && (byte & 0x40) != 0));
60290075Sobrien	if (more)
60390075Sobrien	  byte |= 0x80;
60490075Sobrien
60590075Sobrien	if (byte_op)
60690075Sobrien	  {
60790075Sobrien	    fprintf (asm_out_file, "0x%x", byte);
60890075Sobrien	    if (more)
60990075Sobrien	      fputc (',', asm_out_file);
61090075Sobrien	  }
61190075Sobrien	else
61290075Sobrien	  assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
61390075Sobrien      }
61490075Sobrien    while (more);
61590075Sobrien
61690075Sobrien  if (flag_debug_asm)
61790075Sobrien    {
618132718Skan      fprintf (asm_out_file, "\t%s sleb128 " HOST_WIDE_INT_PRINT_DEC,
619132718Skan	       ASM_COMMENT_START, value);
62090075Sobrien      if (comment)
62190075Sobrien	{
62290075Sobrien	  fputs ("; ", asm_out_file);
62390075Sobrien	  vfprintf (asm_out_file, comment, ap);
62490075Sobrien	}
62590075Sobrien    }
62690075Sobrien  }
62790075Sobrien#endif
62890075Sobrien  fputc ('\n', asm_out_file);
62990075Sobrien
630132718Skan  va_end (ap);
63190075Sobrien}
63290075Sobrien
63390075Sobrienvoid
634132718Skandw2_asm_output_delta_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
635132718Skan			      const char *lab2 ATTRIBUTE_UNUSED,
636132718Skan			      const char *comment, ...)
63790075Sobrien{
638132718Skan  va_list ap;
63990075Sobrien
640132718Skan  va_start (ap, comment);
641132718Skan
64290075Sobrien#ifdef HAVE_AS_LEB128
64390075Sobrien  fputs ("\t.uleb128 ", asm_out_file);
64490075Sobrien  assemble_name (asm_out_file, lab1);
64590075Sobrien  fputc ('-', asm_out_file);
64690075Sobrien  assemble_name (asm_out_file, lab2);
64790075Sobrien#else
648169689Skan  gcc_unreachable ();
64990075Sobrien#endif
65090075Sobrien
65190075Sobrien  if (flag_debug_asm && comment)
65290075Sobrien    {
65390075Sobrien      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
65490075Sobrien      vfprintf (asm_out_file, comment, ap);
65590075Sobrien    }
65690075Sobrien  fputc ('\n', asm_out_file);
65790075Sobrien
658132718Skan  va_end (ap);
65990075Sobrien}
66090075Sobrien
661169689Skan#if 0
662169689Skan
66390075Sobrienvoid
664132718Skandw2_asm_output_delta_sleb128 (const char *lab1 ATTRIBUTE_UNUSED,
665132718Skan			      const char *lab2 ATTRIBUTE_UNUSED,
666132718Skan			      const char *comment, ...)
66790075Sobrien{
668132718Skan  va_list ap;
66990075Sobrien
670132718Skan  va_start (ap, comment);
671132718Skan
67290075Sobrien#ifdef HAVE_AS_LEB128
67390075Sobrien  fputs ("\t.sleb128 ", asm_out_file);
67490075Sobrien  assemble_name (asm_out_file, lab1);
67590075Sobrien  fputc ('-', asm_out_file);
67690075Sobrien  assemble_name (asm_out_file, lab2);
67790075Sobrien#else
678169689Skan  gcc_unreachable ();
67990075Sobrien#endif
68090075Sobrien
68190075Sobrien  if (flag_debug_asm && comment)
68290075Sobrien    {
68390075Sobrien      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
68490075Sobrien      vfprintf (asm_out_file, comment, ap);
68590075Sobrien    }
68690075Sobrien  fputc ('\n', asm_out_file);
68790075Sobrien
688132718Skan  va_end (ap);
68990075Sobrien}
690169689Skan#endif /* 0 */
69190075Sobrien
692169689Skanstatic rtx dw2_force_const_mem (rtx, bool);
693132718Skanstatic int dw2_output_indirect_constant_1 (splay_tree_node, void *);
69490075Sobrien
695132718Skanstatic GTY((param1_is (char *), param2_is (tree))) splay_tree indirect_pool;
69690075Sobrien
697132718Skanstatic GTY(()) int dw2_const_labelno;
698132718Skan
69990075Sobrien#if defined(HAVE_GAS_HIDDEN) && defined(SUPPORTS_ONE_ONLY)
70090075Sobrien# define USE_LINKONCE_INDIRECT 1
70190075Sobrien#else
70290075Sobrien# define USE_LINKONCE_INDIRECT 0
70390075Sobrien#endif
70490075Sobrien
70590075Sobrien/* Put X, a SYMBOL_REF, in memory.  Return a SYMBOL_REF to the allocated
70690075Sobrien   memory.  Differs from force_const_mem in that a single pool is used for
70790075Sobrien   the entire unit of translation, and the memory is not guaranteed to be
708169689Skan   "near" the function in any interesting sense.  PUBLIC controls whether
709169689Skan   the symbol can be shared across the entire application (or DSO).  */
71090075Sobrien
71190075Sobrienstatic rtx
712169689Skandw2_force_const_mem (rtx x, bool public)
71390075Sobrien{
71490075Sobrien  splay_tree_node node;
71590075Sobrien  const char *str;
71690075Sobrien  tree decl;
71790075Sobrien
71890075Sobrien  if (! indirect_pool)
719132718Skan    indirect_pool = splay_tree_new_ggc (splay_tree_compare_pointers);
72090075Sobrien
721169689Skan  gcc_assert (GET_CODE (x) == SYMBOL_REF);
72290075Sobrien
723169689Skan  str = targetm.strip_name_encoding (XSTR (x, 0));
72490075Sobrien  node = splay_tree_lookup (indirect_pool, (splay_tree_key) str);
72590075Sobrien  if (node)
72690075Sobrien    decl = (tree) node->value;
72790075Sobrien  else
72890075Sobrien    {
72990075Sobrien      tree id;
73090075Sobrien
731169689Skan      if (public && USE_LINKONCE_INDIRECT)
73290075Sobrien	{
73390075Sobrien	  char *ref_name = alloca (strlen (str) + sizeof "DW.ref.");
73490075Sobrien
73590075Sobrien	  sprintf (ref_name, "DW.ref.%s", str);
73690075Sobrien	  id = get_identifier (ref_name);
73790075Sobrien	  decl = build_decl (VAR_DECL, id, ptr_type_node);
73890075Sobrien	  DECL_ARTIFICIAL (decl) = 1;
739169689Skan	  DECL_IGNORED_P (decl) = 1;
74090075Sobrien	  TREE_PUBLIC (decl) = 1;
74190075Sobrien	  DECL_INITIAL (decl) = decl;
74290075Sobrien	  make_decl_one_only (decl);
74390075Sobrien	}
74490075Sobrien      else
74590075Sobrien	{
74690075Sobrien	  char label[32];
74790075Sobrien
748132718Skan	  ASM_GENERATE_INTERNAL_LABEL (label, "LDFCM", dw2_const_labelno);
749132718Skan	  ++dw2_const_labelno;
75090075Sobrien	  id = get_identifier (label);
75190075Sobrien	  decl = build_decl (VAR_DECL, id, ptr_type_node);
75290075Sobrien	  DECL_ARTIFICIAL (decl) = 1;
753169689Skan	  DECL_IGNORED_P (decl) = 1;
75490075Sobrien	  TREE_STATIC (decl) = 1;
75590075Sobrien	  DECL_INITIAL (decl) = decl;
75690075Sobrien	}
75790075Sobrien
75890075Sobrien      id = maybe_get_identifier (str);
75990075Sobrien      if (id)
76090075Sobrien	TREE_SYMBOL_REFERENCED (id) = 1;
76190075Sobrien
76290075Sobrien      splay_tree_insert (indirect_pool, (splay_tree_key) str,
76390075Sobrien			 (splay_tree_value) decl);
76490075Sobrien    }
76590075Sobrien
76690075Sobrien  return XEXP (DECL_RTL (decl), 0);
76790075Sobrien}
76890075Sobrien
76990075Sobrien/* A helper function for dw2_output_indirect_constants called through
77090075Sobrien   splay_tree_foreach.  Emit one queued constant to memory.  */
77190075Sobrien
77290075Sobrienstatic int
773132718Skandw2_output_indirect_constant_1 (splay_tree_node node,
774132718Skan				void *data ATTRIBUTE_UNUSED)
77590075Sobrien{
77690075Sobrien  const char *sym;
77790075Sobrien  rtx sym_ref;
778169689Skan  tree decl;
77990075Sobrien
78090075Sobrien  sym = (const char *) node->key;
781169689Skan  decl = (tree) node->value;
78290075Sobrien  sym_ref = gen_rtx_SYMBOL_REF (Pmode, sym);
783169689Skan  if (TREE_PUBLIC (decl) && USE_LINKONCE_INDIRECT)
784132718Skan    fprintf (asm_out_file, "\t.hidden %sDW.ref.%s\n", user_label_prefix, sym);
785169689Skan  assemble_variable (decl, 1, 1, 1);
78690075Sobrien  assemble_integer (sym_ref, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
78790075Sobrien
78890075Sobrien  return 0;
78990075Sobrien}
79090075Sobrien
79190075Sobrien/* Emit the constants queued through dw2_force_const_mem.  */
79290075Sobrien
79390075Sobrienvoid
794132718Skandw2_output_indirect_constants (void)
79590075Sobrien{
79690075Sobrien  if (indirect_pool)
79790075Sobrien    splay_tree_foreach (indirect_pool, dw2_output_indirect_constant_1, NULL);
79890075Sobrien}
79990075Sobrien
800169689Skan/* Like dw2_asm_output_addr_rtx, but encode the pointer as directed.
801169689Skan   If PUBLIC is set and the encoding is DW_EH_PE_indirect, the indirect
802169689Skan   reference is shared across the entire application (or DSO).  */
80390075Sobrien
80490075Sobrienvoid
805169689Skandw2_asm_output_encoded_addr_rtx (int encoding, rtx addr, bool public,
806132718Skan				 const char *comment, ...)
80790075Sobrien{
80890075Sobrien  int size;
809132718Skan  va_list ap;
81090075Sobrien
811132718Skan  va_start (ap, comment);
81290075Sobrien
81390075Sobrien  size = size_of_encoded_value (encoding);
81490075Sobrien
81590075Sobrien  if (encoding == DW_EH_PE_aligned)
81690075Sobrien    {
81790075Sobrien      assemble_align (POINTER_SIZE);
81890075Sobrien      assemble_integer (addr, size, POINTER_SIZE, 1);
81990075Sobrien      return;
82090075Sobrien    }
82190075Sobrien
82290075Sobrien  /* NULL is _always_ represented as a plain zero, as is 1 for Ada's
82390075Sobrien     "all others".  */
82490075Sobrien  if (addr == const0_rtx || addr == const1_rtx)
82590075Sobrien    assemble_integer (addr, size, BITS_PER_UNIT, 1);
82690075Sobrien  else
82790075Sobrien    {
82890075Sobrien    restart:
82990075Sobrien      /* Allow the target first crack at emitting this.  Some of the
830117395Skan	 special relocations require special directives instead of
83190075Sobrien	 just ".4byte" or whatever.  */
83290075Sobrien#ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
83390075Sobrien      ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX (asm_out_file, encoding, size,
83490075Sobrien					 addr, done);
83590075Sobrien#endif
83690075Sobrien
83790075Sobrien      /* Indirection is used to get dynamic relocations out of a
83890075Sobrien	 read-only section.  */
83990075Sobrien      if (encoding & DW_EH_PE_indirect)
84090075Sobrien	{
84190075Sobrien	  /* It is very tempting to use force_const_mem so that we share data
84290075Sobrien	     with the normal constant pool.  However, we've already emitted
84390075Sobrien	     the constant pool for this function.  Moreover, we'd like to
844169689Skan	     share these constants across the entire unit of translation and
845169689Skan	     even, if possible, across the entire application (or DSO).  */
846169689Skan	  addr = dw2_force_const_mem (addr, public);
84790075Sobrien	  encoding &= ~DW_EH_PE_indirect;
84890075Sobrien	  goto restart;
84990075Sobrien	}
85090075Sobrien
85190075Sobrien      switch (encoding & 0xF0)
85290075Sobrien	{
85390075Sobrien	case DW_EH_PE_absptr:
85490075Sobrien	  dw2_assemble_integer (size, addr);
85590075Sobrien	  break;
85690075Sobrien
85790075Sobrien	case DW_EH_PE_pcrel:
858169689Skan	  gcc_assert (GET_CODE (addr) == SYMBOL_REF);
85990075Sobrien#ifdef ASM_OUTPUT_DWARF_PCREL
86090075Sobrien	  ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, XSTR (addr, 0));
86190075Sobrien#else
86290075Sobrien	  dw2_assemble_integer (size, gen_rtx_MINUS (Pmode, addr, pc_rtx));
86390075Sobrien#endif
86490075Sobrien	  break;
86590075Sobrien
86690075Sobrien	default:
867117395Skan	  /* Other encodings should have been handled by
86890075Sobrien	     ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX.  */
869169689Skan	  gcc_unreachable ();
87090075Sobrien	}
87190075Sobrien
87290075Sobrien#ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
87390075Sobrien    done:;
87490075Sobrien#endif
87590075Sobrien    }
87690075Sobrien
87790075Sobrien  if (flag_debug_asm && comment)
87890075Sobrien    {
87990075Sobrien      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
88090075Sobrien      vfprintf (asm_out_file, comment, ap);
88190075Sobrien    }
88290075Sobrien  fputc ('\n', asm_out_file);
88390075Sobrien
884132718Skan  va_end (ap);
88590075Sobrien}
886132718Skan
887132718Skan#include "gt-dwarf2asm.h"
888