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