dwarf2asm.c 26.1 KB
Newer Older
1
/* Dwarf2 assembler output helper routines.
2
   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
3
   Free Software Foundation, Inc.
4

5
This file is part of GCC.
6

7 8
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
9
Software Foundation; either version 3, or (at your option) any later
10
version.
11

12 13 14 15
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.
16 17

You should have received a copy of the GNU General Public License
18 19
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
20 21 22 23


#include "config.h"
#include "system.h"
24 25
#include "coretypes.h"
#include "tm.h"
26
#include "flags.h"
27
#include "tree.h"
28 29
#include "rtl.h"
#include "output.h"
30
#include "target.h"
31
#include "dwarf2asm.h"
32
#include "dwarf2.h"
33 34
#include "splay-tree.h"
#include "ggc.h"
35 36 37 38 39 40 41 42 43
#include "tm_p.h"


/* How to start an assembler comment.  */
#ifndef ASM_COMMENT_START
#define ASM_COMMENT_START ";#"
#endif


44 45 46 47
/* Output an unaligned integer with the given value and size.  Prefer not
   to print a newline, since the caller may want to add a comment.  */

void
48
dw2_assemble_integer (int size, rtx x)
49
{
50 51 52
  const char *op = integer_asm_op (size, FALSE);

  if (op)
53
    {
54
      fputs (op, asm_out_file);
Shujing Zhao committed
55
      if (CONST_INT_P (x))
56 57
	fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX,
		 (unsigned HOST_WIDE_INT) INTVAL (x));
58 59
      else
	output_addr_const (asm_out_file, x);
60
    }
61 62
  else
    assemble_integer (x, size, BITS_PER_UNIT, 1);
63
}
Kazu Hirata committed
64

65

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
/* Output a value of a given size in target byte order.  */

void
dw2_asm_output_data_raw (int size, unsigned HOST_WIDE_INT value)
{
  unsigned char bytes[8];
  int i;

  for (i = 0; i < 8; ++i)
    {
      bytes[i] = value & 0xff;
      value >>= 8;
    }

  if (BYTES_BIG_ENDIAN)
    {
      for (i = size - 1; i > 0; --i)
83 84
	fprintf (asm_out_file, "%#x,", bytes[i]);
      fprintf (asm_out_file, "%#x", bytes[0]);
85 86 87 88
    }
  else
    {
      for (i = 0; i < size - 1; ++i)
89 90
	fprintf (asm_out_file, "%#x,", bytes[i]);
      fprintf (asm_out_file, "%#x", bytes[i]);
91 92 93
    }
}

Diego Novillo committed
94
/* Output an immediate constant in a given SIZE in bytes.  */
95

96
void
97 98
dw2_asm_output_data (int size, unsigned HOST_WIDE_INT value,
		     const char *comment, ...)
99
{
100
  va_list ap;
101
  const char *op = integer_asm_op (size, FALSE);
102

103
  va_start (ap, comment);
104

105
  if (size * 8 < HOST_BITS_PER_WIDE_INT)
Kazu Hirata committed
106
    value &= ~(~(unsigned HOST_WIDE_INT) 0 << (size * 8));
107

108 109 110 111
  if (op)
    fprintf (asm_out_file, "%s" HOST_WIDE_INT_PRINT_HEX, op, value);
  else
    assemble_integer (GEN_INT (value), size, BITS_PER_UNIT, 1);
112 113 114 115 116 117 118 119

  if (flag_debug_asm && comment)
    {
      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
      vfprintf (asm_out_file, comment, ap);
    }
  fputc ('\n', asm_out_file);

120
  va_end (ap);
121 122
}

123 124 125 126 127 128
/* Output the difference between two symbols in a given size.  */
/* ??? There appear to be assemblers that do not like such
   subtraction, but do support ASM_SET_OP.  It's unfortunately
   impossible to do here, since the ASM_SET_OP for the difference
   symbol must appear after both symbols are defined.  */

129
void
130 131
dw2_asm_output_delta (int size, const char *lab1, const char *lab2,
		      const char *comment, ...)
132
{
133
  va_list ap;
134

135
  va_start (ap, comment);
136

137 138 139
#ifdef ASM_OUTPUT_DWARF_DELTA
  ASM_OUTPUT_DWARF_DELTA (asm_out_file, size, lab1, lab2);
#else
140 141 142 143
  dw2_assemble_integer (size,
			gen_rtx_MINUS (Pmode,
				       gen_rtx_SYMBOL_REF (Pmode, lab1),
				       gen_rtx_SYMBOL_REF (Pmode, lab2)));
144
#endif
145 146 147 148 149 150 151
  if (flag_debug_asm && comment)
    {
      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
      vfprintf (asm_out_file, comment, ap);
    }
  fputc ('\n', asm_out_file);

152
  va_end (ap);
153 154
}

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
/* Output the difference between two symbols in instruction units
   in a given size.  */

void
dw2_asm_output_vms_delta (int size ATTRIBUTE_UNUSED,
			  const char *lab1, const char *lab2,
			  const char *comment, ...)
{
  va_list ap;

  va_start (ap, comment);

#ifndef ASM_OUTPUT_DWARF_VMS_DELTA
  /* VMS Delta is only special on ia64-vms, but this funtion also gets
     called on alpha-vms so it has to do something sane.  */
  dw2_asm_output_delta (size, lab1, lab2, comment);
#else
  ASM_OUTPUT_DWARF_VMS_DELTA (asm_out_file, size, lab1, lab2);
  if (flag_debug_asm && comment)
    {
      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
      vfprintf (asm_out_file, comment, ap);
    }
  fputc ('\n', asm_out_file);
#endif

  va_end (ap);
}

184 185 186 187 188 189
/* Output a section-relative reference to a LABEL, which was placed in
   BASE.  In general this can only be done for debugging symbols.
   E.g. on most targets with the GNU linker, this is accomplished with
   a direct reference and the knowledge that the debugging section
   will be placed at VMA 0.  Some targets have special relocations for
   this that we must use.  */
190

191
void
192 193
dw2_asm_output_offset (int size, const char *label,
		       section *base ATTRIBUTE_UNUSED,
194
		       const char *comment, ...)
195
{
196
  va_list ap;
197

198
  va_start (ap, comment);
199

200
#ifdef ASM_OUTPUT_DWARF_OFFSET
201
  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label, base);
202
#else
203
  dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
204
#endif
205 206 207 208 209 210 211 212

  if (flag_debug_asm && comment)
    {
      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
      vfprintf (asm_out_file, comment, ap);
    }
  fputc ('\n', asm_out_file);

213
  va_end (ap);
214 215
}

216 217
#if 0

218 219 220
/* Output a self-relative reference to a label, possibly in a
   different section or object file.  */

221
void
222 223 224
dw2_asm_output_pcrel (int size ATTRIBUTE_UNUSED,
		      const char *label ATTRIBUTE_UNUSED,
		      const char *comment, ...)
225
{
226
  va_list ap;
227

228
  va_start (ap, comment);
229

230 231 232
#ifdef ASM_OUTPUT_DWARF_PCREL
  ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, label);
#else
233 234 235 236
  dw2_assemble_integer (size,
			gen_rtx_MINUS (Pmode,
				       gen_rtx_SYMBOL_REF (Pmode, label),
				       pc_rtx));
237 238 239 240 241 242 243 244 245
#endif

  if (flag_debug_asm && comment)
    {
      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
      vfprintf (asm_out_file, comment, ap);
    }
  fputc ('\n', asm_out_file);

246
  va_end (ap);
247
}
248
#endif /* 0 */
249 250 251 252

/* Output an absolute reference to a label.  */

void
253 254
dw2_asm_output_addr (int size, const char *label,
		     const char *comment, ...)
255
{
256
  va_list ap;
257

258
  va_start (ap, comment);
259

260
  dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
261 262 263 264 265 266 267 268

  if (flag_debug_asm && comment)
    {
      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
      vfprintf (asm_out_file, comment, ap);
    }
  fputc ('\n', asm_out_file);

269
  va_end (ap);
270 271
}

272 273
/* Similar, but use an RTX expression instead of a text label.  */

274
void
275 276
dw2_asm_output_addr_rtx (int size, rtx addr,
			 const char *comment, ...)
277
{
278
  va_list ap;
279

280
  va_start (ap, comment);
281

282
  dw2_assemble_integer (size, addr);
283 284 285 286 287 288 289 290

  if (flag_debug_asm && comment)
    {
      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
      vfprintf (asm_out_file, comment, ap);
    }
  fputc ('\n', asm_out_file);

291
  va_end (ap);
292 293
}

294 295 296 297 298 299
/* Output the first ORIG_LEN characters of STR as a string.
   If ORIG_LEN is equal to -1, ignore this parameter and output
   the entire STR instead.
   If COMMENT is not NULL and comments in the debug information
   have been requested by the user, append the given COMMENT
   to the generated output.  */
H.J. Lu committed
300

301
void
302 303
dw2_asm_output_nstring (const char *str, size_t orig_len,
			const char *comment, ...)
304
{
305
  size_t i, len;
306
  va_list ap;
307

308
  va_start (ap, comment);
309

310
  len = orig_len;
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339

  if (len == (size_t) -1)
    len = strlen (str);

  if (flag_debug_asm && comment)
    {
      fputs ("\t.ascii \"", asm_out_file);
      for (i = 0; i < len; i++)
	{
	  int c = str[i];
	  if (c == '\"' || c == '\\')
	    fputc ('\\', asm_out_file);
	  if (ISPRINT(c))
	    fputc (c, asm_out_file);
	  else
	    fprintf (asm_out_file, "\\%o", c);
	}
      fprintf (asm_out_file, "\\0\"\t%s ", ASM_COMMENT_START);
      vfprintf (asm_out_file, comment, ap);
      fputc ('\n', asm_out_file);
    }
  else
    {
      /* If an explicit length was given, we can't assume there
	 is a null termination in the string buffer.  */
      if (orig_len == (size_t) -1)
	len += 1;
      ASM_OUTPUT_ASCII (asm_out_file, str, len);
      if (orig_len != (size_t) -1)
340
	assemble_integer (const0_rtx, 1, BITS_PER_UNIT, 1);
341 342
    }

343
  va_end (ap);
344 345 346 347 348 349
}


/* Return the size of an unsigned LEB128 quantity.  */

int
350
size_of_uleb128 (unsigned HOST_WIDE_INT value)
351
{
352
  int size = 0;
353 354 355 356 357 358 359 360 361 362 363 364 365 366

  do
    {
      value >>= 7;
      size += 1;
    }
  while (value != 0);

  return size;
}

/* Return the size of a signed LEB128 quantity.  */

int
367
size_of_sleb128 (HOST_WIDE_INT value)
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
{
  int size = 0, byte;

  do
    {
      byte = (value & 0x7f);
      value >>= 7;
      size += 1;
    }
  while (!((value == 0 && (byte & 0x40) == 0)
	   || (value == -1 && (byte & 0x40) != 0)));

  return size;
}

383
/* Given an encoding, return the number of bytes the format occupies.
Kazu Hirata committed
384
   This is only defined for fixed-size encodings, and so does not
385 386 387
   include leb128.  */

int
388
size_of_encoded_value (int encoding)
389 390 391 392 393 394 395 396 397 398 399 400 401 402
{
  if (encoding == DW_EH_PE_omit)
    return 0;

  switch (encoding & 0x07)
    {
    case DW_EH_PE_absptr:
      return POINTER_SIZE / BITS_PER_UNIT;
    case DW_EH_PE_udata2:
      return 2;
    case DW_EH_PE_udata4:
      return 4;
    case DW_EH_PE_udata8:
      return 8;
403 404
    default:
      gcc_unreachable ();
405 406 407
    }
}

408 409 410
/* Yield a name for a given pointer encoding.  */

const char *
411
eh_data_format_name (int format)
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
{
#if HAVE_DESIGNATED_INITIALIZERS
#define S(p, v)		[p] = v,
#else
#define S(p, v)		case p: return v;
#endif

#if HAVE_DESIGNATED_INITIALIZERS
  __extension__ static const char * const format_names[256] = {
#else
  switch (format) {
#endif

  S(DW_EH_PE_absptr, "absolute")
  S(DW_EH_PE_omit, "omit")
427
  S(DW_EH_PE_aligned, "aligned absolute")
428 429 430 431 432 433 434 435 436 437

  S(DW_EH_PE_uleb128, "uleb128")
  S(DW_EH_PE_udata2, "udata2")
  S(DW_EH_PE_udata4, "udata4")
  S(DW_EH_PE_udata8, "udata8")
  S(DW_EH_PE_sleb128, "sleb128")
  S(DW_EH_PE_sdata2, "sdata2")
  S(DW_EH_PE_sdata4, "sdata4")
  S(DW_EH_PE_sdata8, "sdata8")

438
  S(DW_EH_PE_absptr | DW_EH_PE_pcrel, "pcrel")
439 440 441 442 443 444 445 446 447
  S(DW_EH_PE_uleb128 | DW_EH_PE_pcrel, "pcrel uleb128")
  S(DW_EH_PE_udata2 | DW_EH_PE_pcrel, "pcrel udata2")
  S(DW_EH_PE_udata4 | DW_EH_PE_pcrel, "pcrel udata4")
  S(DW_EH_PE_udata8 | DW_EH_PE_pcrel, "pcrel udata8")
  S(DW_EH_PE_sleb128 | DW_EH_PE_pcrel, "pcrel sleb128")
  S(DW_EH_PE_sdata2 | DW_EH_PE_pcrel, "pcrel sdata2")
  S(DW_EH_PE_sdata4 | DW_EH_PE_pcrel, "pcrel sdata4")
  S(DW_EH_PE_sdata8 | DW_EH_PE_pcrel, "pcrel sdata8")

448
  S(DW_EH_PE_absptr | DW_EH_PE_textrel, "textrel")
449 450 451 452 453 454 455 456 457
  S(DW_EH_PE_uleb128 | DW_EH_PE_textrel, "textrel uleb128")
  S(DW_EH_PE_udata2 | DW_EH_PE_textrel, "textrel udata2")
  S(DW_EH_PE_udata4 | DW_EH_PE_textrel, "textrel udata4")
  S(DW_EH_PE_udata8 | DW_EH_PE_textrel, "textrel udata8")
  S(DW_EH_PE_sleb128 | DW_EH_PE_textrel, "textrel sleb128")
  S(DW_EH_PE_sdata2 | DW_EH_PE_textrel, "textrel sdata2")
  S(DW_EH_PE_sdata4 | DW_EH_PE_textrel, "textrel sdata4")
  S(DW_EH_PE_sdata8 | DW_EH_PE_textrel, "textrel sdata8")

458
  S(DW_EH_PE_absptr | DW_EH_PE_datarel, "datarel")
459 460 461 462 463 464 465 466 467
  S(DW_EH_PE_uleb128 | DW_EH_PE_datarel, "datarel uleb128")
  S(DW_EH_PE_udata2 | DW_EH_PE_datarel, "datarel udata2")
  S(DW_EH_PE_udata4 | DW_EH_PE_datarel, "datarel udata4")
  S(DW_EH_PE_udata8 | DW_EH_PE_datarel, "datarel udata8")
  S(DW_EH_PE_sleb128 | DW_EH_PE_datarel, "datarel sleb128")
  S(DW_EH_PE_sdata2 | DW_EH_PE_datarel, "datarel sdata2")
  S(DW_EH_PE_sdata4 | DW_EH_PE_datarel, "datarel sdata4")
  S(DW_EH_PE_sdata8 | DW_EH_PE_datarel, "datarel sdata8")

468
  S(DW_EH_PE_absptr | DW_EH_PE_funcrel, "funcrel")
469 470 471 472 473 474 475 476 477
  S(DW_EH_PE_uleb128 | DW_EH_PE_funcrel, "funcrel uleb128")
  S(DW_EH_PE_udata2 | DW_EH_PE_funcrel, "funcrel udata2")
  S(DW_EH_PE_udata4 | DW_EH_PE_funcrel, "funcrel udata4")
  S(DW_EH_PE_udata8 | DW_EH_PE_funcrel, "funcrel udata8")
  S(DW_EH_PE_sleb128 | DW_EH_PE_funcrel, "funcrel sleb128")
  S(DW_EH_PE_sdata2 | DW_EH_PE_funcrel, "funcrel sdata2")
  S(DW_EH_PE_sdata4 | DW_EH_PE_funcrel, "funcrel sdata4")
  S(DW_EH_PE_sdata8 | DW_EH_PE_funcrel, "funcrel sdata8")

478 479
  S(DW_EH_PE_indirect | DW_EH_PE_absptr, "indirect absolute")

480 481
  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_pcrel,
    "indirect pcrel")
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_pcrel,
    "indirect pcrel uleb128")
  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_pcrel,
    "indirect pcrel udata2")
  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_pcrel,
    "indirect pcrel udata4")
  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_pcrel,
    "indirect pcrel udata8")
  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_pcrel,
    "indirect pcrel sleb128")
  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_pcrel,
    "indirect pcrel sdata2")
  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_pcrel,
    "indirect pcrel sdata4")
  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_pcrel,
    "indirect pcrel sdata8")

499 500
  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_textrel,
    "indirect textrel")
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_textrel,
    "indirect textrel uleb128")
  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_textrel,
    "indirect textrel udata2")
  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_textrel,
    "indirect textrel udata4")
  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_textrel,
    "indirect textrel udata8")
  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_textrel,
    "indirect textrel sleb128")
  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_textrel,
    "indirect textrel sdata2")
  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_textrel,
    "indirect textrel sdata4")
  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_textrel,
    "indirect textrel sdata8")

518 519
  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_datarel,
    "indirect datarel")
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_datarel,
    "indirect datarel uleb128")
  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_datarel,
    "indirect datarel udata2")
  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_datarel,
    "indirect datarel udata4")
  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_datarel,
    "indirect datarel udata8")
  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_datarel,
    "indirect datarel sleb128")
  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_datarel,
    "indirect datarel sdata2")
  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_datarel,
    "indirect datarel sdata4")
  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_datarel,
    "indirect datarel sdata8")

537 538
  S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_funcrel,
    "indirect funcrel")
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
  S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_funcrel,
    "indirect funcrel uleb128")
  S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_funcrel,
    "indirect funcrel udata2")
  S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_funcrel,
    "indirect funcrel udata4")
  S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_funcrel,
    "indirect funcrel udata8")
  S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_funcrel,
    "indirect funcrel sleb128")
  S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_funcrel,
    "indirect funcrel sdata2")
  S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_funcrel,
    "indirect funcrel sdata4")
  S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_funcrel,
    "indirect funcrel sdata8")

#if HAVE_DESIGNATED_INITIALIZERS
  };

559
  gcc_assert (format >= 0 && format < 0x100 && format_names[format]);
H.J. Lu committed
560

561 562 563
  return format_names[format];
#else
  }
564
  gcc_unreachable ();
565 566 567
#endif
}

568 569 570 571 572 573 574 575 576 577 578 579 580
/* Output an unsigned LEB128 quantity, but only the byte values.  */

void
dw2_asm_output_data_uleb128_raw (unsigned HOST_WIDE_INT value)
{
  while (1)
    {
      int byte = (value & 0x7f);
      value >>= 7;
      if (value != 0)
	/* More bytes to follow.  */
	byte |= 0x80;

581
      fprintf (asm_out_file, "%#x", byte);
582 583 584 585 586 587
      if (value == 0)
	break;
      fputc (',', asm_out_file);
    }
}

588 589 590
/* Output an unsigned LEB128 quantity.  */

void
591 592
dw2_asm_output_data_uleb128 (unsigned HOST_WIDE_INT value,
			     const char *comment, ...)
593
{
594
  va_list ap;
595

596
  va_start (ap, comment);
597 598

#ifdef HAVE_AS_LEB128
599
  fprintf (asm_out_file, "\t.uleb128 " HOST_WIDE_INT_PRINT_HEX , value);
600 601 602 603 604 605 606 607 608

  if (flag_debug_asm && comment)
    {
      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
      vfprintf (asm_out_file, comment, ap);
    }
#else
  {
    unsigned HOST_WIDE_INT work = value;
609
    const char *byte_op = targetm.asm_out.byte_op;
610

611 612
    if (byte_op)
      fputs (byte_op, asm_out_file);
613 614 615 616 617 618 619 620
    do
      {
	int byte = (work & 0x7f);
	work >>= 7;
	if (work != 0)
	  /* More bytes to follow.  */
	  byte |= 0x80;

621 622
	if (byte_op)
	  {
623
	    fprintf (asm_out_file, "%#x", byte);
624 625 626 627 628
	    if (work != 0)
	      fputc (',', asm_out_file);
	  }
	else
	  assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
629 630 631 632 633
      }
    while (work != 0);

  if (flag_debug_asm)
    {
634 635
      fprintf (asm_out_file, "\t%s uleb128 " HOST_WIDE_INT_PRINT_HEX,
	       ASM_COMMENT_START, value);
636 637 638 639 640 641 642 643 644 645
      if (comment)
	{
	  fputs ("; ", asm_out_file);
	  vfprintf (asm_out_file, comment, ap);
	}
    }
  }
#endif
  fputc ('\n', asm_out_file);

646
  va_end (ap);
647 648
}

649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
/* Output an signed LEB128 quantity, but only the byte values.  */

void
dw2_asm_output_data_sleb128_raw (HOST_WIDE_INT value)
{
  int byte, more;

  while (1)
    {
      byte = (value & 0x7f);
      value >>= 7;
      more = !((value == 0 && (byte & 0x40) == 0)
		|| (value == -1 && (byte & 0x40) != 0));
      if (more)
	byte |= 0x80;

665
      fprintf (asm_out_file, "%#x", byte);
666 667 668 669 670 671
      if (!more)
	break;
      fputc (',', asm_out_file);
    }
}

672
/* Output a signed LEB128 quantity.  */
673 674

void
675 676
dw2_asm_output_data_sleb128 (HOST_WIDE_INT value,
			     const char *comment, ...)
677
{
678
  va_list ap;
679

680
  va_start (ap, comment);
681 682

#ifdef HAVE_AS_LEB128
683
  fprintf (asm_out_file, "\t.sleb128 " HOST_WIDE_INT_PRINT_DEC, value);
684 685 686 687 688 689 690 691 692 693

  if (flag_debug_asm && comment)
    {
      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
      vfprintf (asm_out_file, comment, ap);
    }
#else
  {
    HOST_WIDE_INT work = value;
    int more, byte;
694
    const char *byte_op = targetm.asm_out.byte_op;
695

696 697
    if (byte_op)
      fputs (byte_op, asm_out_file);
698 699 700 701 702 703 704 705 706 707
    do
      {
	byte = (work & 0x7f);
	/* arithmetic shift */
	work >>= 7;
	more = !((work == 0 && (byte & 0x40) == 0)
		 || (work == -1 && (byte & 0x40) != 0));
	if (more)
	  byte |= 0x80;

708 709
	if (byte_op)
	  {
710
	    fprintf (asm_out_file, "%#x", byte);
711 712 713 714 715
	    if (more)
	      fputc (',', asm_out_file);
	  }
	else
	  assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
716 717 718 719 720
      }
    while (more);

  if (flag_debug_asm)
    {
721 722
      fprintf (asm_out_file, "\t%s sleb128 " HOST_WIDE_INT_PRINT_DEC,
	       ASM_COMMENT_START, value);
723 724 725 726 727 728 729 730 731 732
      if (comment)
	{
	  fputs ("; ", asm_out_file);
	  vfprintf (asm_out_file, comment, ap);
	}
    }
  }
#endif
  fputc ('\n', asm_out_file);

733
  va_end (ap);
734 735 736
}

void
737 738 739
dw2_asm_output_delta_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
			      const char *lab2 ATTRIBUTE_UNUSED,
			      const char *comment, ...)
740
{
741 742 743
  va_list ap;

  va_start (ap, comment);
744 745

#ifdef HAVE_AS_LEB128
746
  fputs ("\t.uleb128 ", asm_out_file);
747 748 749 750
  assemble_name (asm_out_file, lab1);
  fputc ('-', asm_out_file);
  assemble_name (asm_out_file, lab2);
#else
751
  gcc_unreachable ();
752 753 754 755 756 757 758 759 760
#endif

  if (flag_debug_asm && comment)
    {
      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
      vfprintf (asm_out_file, comment, ap);
    }
  fputc ('\n', asm_out_file);

761
  va_end (ap);
762 763
}

764 765
#if 0

766
void
767 768 769
dw2_asm_output_delta_sleb128 (const char *lab1 ATTRIBUTE_UNUSED,
			      const char *lab2 ATTRIBUTE_UNUSED,
			      const char *comment, ...)
770
{
771
  va_list ap;
772

773
  va_start (ap, comment);
774 775

#ifdef HAVE_AS_LEB128
776
  fputs ("\t.sleb128 ", asm_out_file);
777 778 779 780
  assemble_name (asm_out_file, lab1);
  fputc ('-', asm_out_file);
  assemble_name (asm_out_file, lab2);
#else
781
  gcc_unreachable ();
782 783 784 785 786 787 788 789 790
#endif

  if (flag_debug_asm && comment)
    {
      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
      vfprintf (asm_out_file, comment, ap);
    }
  fputc ('\n', asm_out_file);

791
  va_end (ap);
792
}
793
#endif /* 0 */
794

795
static int dw2_output_indirect_constant_1 (splay_tree_node, void *);
796

797 798 799
static GTY((param1_is (char *), param2_is (tree))) splay_tree indirect_pool;

static GTY(()) int dw2_const_labelno;
800

801 802
#if defined(HAVE_GAS_HIDDEN)
# define USE_LINKONCE_INDIRECT (SUPPORTS_ONE_ONLY)
803 804 805 806
#else
# define USE_LINKONCE_INDIRECT 0
#endif

807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
/* Comparison function for a splay tree in which the keys are strings.
   K1 and K2 have the dynamic type "const char *".  Returns <0, 0, or
   >0 to indicate whether K1 is less than, equal to, or greater than
   K2, respectively.  */

static int
splay_tree_compare_strings (splay_tree_key k1, splay_tree_key k2)
{
  const char *s1 = (const char *)k1;
  const char *s2 = (const char *)k2;
  int ret;

  if (s1 == s2)
    return 0;

  ret = strcmp (s1, s2);

  /* The strings are always those from IDENTIFIER_NODEs, and,
     therefore, we should never have two copies of the same
     string.  */
  gcc_assert (ret);

  return ret;
}

832 833 834
/* Put X, a SYMBOL_REF, in memory.  Return a SYMBOL_REF to the allocated
   memory.  Differs from force_const_mem in that a single pool is used for
   the entire unit of translation, and the memory is not guaranteed to be
835
   "near" the function in any interesting sense.  IS_PUBLIC controls whether
836
   the symbol can be shared across the entire application (or DSO).  */
837

838
rtx
839
dw2_force_const_mem (rtx x, bool is_public)
840 841
{
  splay_tree_node node;
842
  const char *key;
843
  tree decl_id;
844 845

  if (! indirect_pool)
846 847
    /* We use strcmp, rather than just comparing pointers, so that the
       sort order will not depend on the host system.  */
848 849 850
    indirect_pool = splay_tree_new_ggc (splay_tree_compare_strings,
					ggc_alloc_splay_tree_str_tree_node_splay_tree_s,
					ggc_alloc_splay_tree_str_tree_node_splay_tree_node_s);
851

852
  gcc_assert (GET_CODE (x) == SYMBOL_REF);
853

854 855
  key = XSTR (x, 0);
  node = splay_tree_lookup (indirect_pool, (splay_tree_key) key);
856
  if (node)
857
    decl_id = (tree) node->value;
858 859 860
  else
    {
      tree id;
861
      const char *str = targetm.strip_name_encoding (key);
862

863
      if (is_public && USE_LINKONCE_INDIRECT)
864
	{
865
	  char *ref_name = XALLOCAVEC (char, strlen (str) + sizeof "DW.ref.");
866

867
	  sprintf (ref_name, "DW.ref.%s", str);
868 869 870
	  gcc_assert (!maybe_get_identifier (ref_name));
	  decl_id = get_identifier (ref_name);
	  TREE_PUBLIC (decl_id) = 1;
871 872 873 874 875
	}
      else
	{
	  char label[32];

876 877
	  ASM_GENERATE_INTERNAL_LABEL (label, "LDFCM", dw2_const_labelno);
	  ++dw2_const_labelno;
878 879
	  gcc_assert (!maybe_get_identifier (label));
	  decl_id = get_identifier (label);
880
	}
881

882
      id = maybe_get_identifier (str);
883 884 885
      if (id)
	TREE_SYMBOL_REFERENCED (id) = 1;

886
      splay_tree_insert (indirect_pool, (splay_tree_key) key,
887
			 (splay_tree_value) decl_id);
888 889
    }

890
  return gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (decl_id));
891 892
}

893 894 895
/* A helper function for dw2_output_indirect_constants called through
   splay_tree_foreach.  Emit one queued constant to memory.  */

896
static int
897 898
dw2_output_indirect_constant_1 (splay_tree_node node,
				void *data ATTRIBUTE_UNUSED)
899
{
900
  const char *sym;
901
  rtx sym_ref;
902
  tree id, decl;
903 904

  sym = (const char *) node->key;
905 906
  id = (tree) node->value;

907
  decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, id, ptr_type_node);
908 909 910
  DECL_ARTIFICIAL (decl) = 1;
  DECL_IGNORED_P (decl) = 1;
  DECL_INITIAL (decl) = decl;
911
  TREE_READONLY (decl) = 1;
912 913 914 915

  if (TREE_PUBLIC (id))
    {
      TREE_PUBLIC (decl) = 1;
916
      make_decl_one_only (decl, DECL_ASSEMBLER_NAME (decl));
917 918 919 920
    }
  else
    TREE_STATIC (decl) = 1;

921
  sym_ref = gen_rtx_SYMBOL_REF (Pmode, sym);
922
  sym = targetm.strip_name_encoding (sym);
923
  if (TREE_PUBLIC (decl) && USE_LINKONCE_INDIRECT)
924
    fprintf (asm_out_file, "\t.hidden %sDW.ref.%s\n", user_label_prefix, sym);
925
  assemble_variable (decl, 1, 1, 1);
926
  assemble_integer (sym_ref, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
927 928 929 930

  return 0;
}

931 932
/* Emit the constants queued through dw2_force_const_mem.  */

933
void
934
dw2_output_indirect_constants (void)
935
{
936 937
  if (indirect_pool)
    splay_tree_foreach (indirect_pool, dw2_output_indirect_constant_1, NULL);
938 939
}

940 941 942
/* Like dw2_asm_output_addr_rtx, but encode the pointer as directed.
   If PUBLIC is set and the encoding is DW_EH_PE_indirect, the indirect
   reference is shared across the entire application (or DSO).  */
943

944
void
945
dw2_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 956 957
  if (encoding == DW_EH_PE_aligned)
    {
      assemble_align (POINTER_SIZE);
958 959
      assemble_integer (addr, size, POINTER_SIZE, 1);
      return;
960 961
    }

962 963 964
  /* NULL is _always_ represented as a plain zero, as is 1 for Ada's
     "all others".  */
  if (addr == const0_rtx || addr == const1_rtx)
965
    assemble_integer (addr, size, BITS_PER_UNIT, 1);
966
  else
967
    {
968 969
    restart:
      /* Allow the target first crack at emitting this.  Some of the
Kazu Hirata committed
970
	 special relocations require special directives instead of
971
	 just ".4byte" or whatever.  */
972
#ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
973 974
      ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX (asm_out_file, encoding, size,
					 addr, done);
975 976
#endif

977 978 979 980 981 982 983
      /* Indirection is used to get dynamic relocations out of a
	 read-only section.  */
      if (encoding & DW_EH_PE_indirect)
	{
	  /* It is very tempting to use force_const_mem so that we share data
	     with the normal constant pool.  However, we've already emitted
	     the constant pool for this function.  Moreover, we'd like to
984 985
	     share these constants across the entire unit of translation and
	     even, if possible, across the entire application (or DSO).  */
986
	  addr = dw2_force_const_mem (addr, is_public);
987 988 989
	  encoding &= ~DW_EH_PE_indirect;
	  goto restart;
	}
990

991 992 993
      switch (encoding & 0xF0)
	{
	case DW_EH_PE_absptr:
994
	  dw2_assemble_integer (size, addr);
995
	  break;
996

997
	case DW_EH_PE_pcrel:
998
	  gcc_assert (GET_CODE (addr) == SYMBOL_REF);
999
#ifdef ASM_OUTPUT_DWARF_PCREL
1000
	  ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, XSTR (addr, 0));
1001
#else
1002
	  dw2_assemble_integer (size, gen_rtx_MINUS (Pmode, addr, pc_rtx));
1003
#endif
1004
	  break;
1005

1006
	default:
Kazu Hirata committed
1007
	  /* Other encodings should have been handled by
1008
	     ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX.  */
1009
	  gcc_unreachable ();
1010
	}
1011 1012

#ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
1013
    done:;
1014
#endif
1015 1016 1017 1018 1019 1020 1021
    }

  if (flag_debug_asm && comment)
    {
      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
      vfprintf (asm_out_file, comment, ap);
    }
1022
  fputc ('\n', asm_out_file);
1023

1024
  va_end (ap);
1025
}
1026 1027

#include "gt-dwarf2asm.h"