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