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

source code of gcc/dwarf2asm.cc