xref: /netbsd/external/gpl3/gcc/dist/gcc/dwarf2asm.cc (revision f0fbc68b)
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
44    to print a newline, since the caller may want to add a comment.  */
45 
46 void
dw2_assemble_integer(int size,rtx x)47 dw2_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 (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 	  if (op)
77 	    {
78 	      fputs (op, asm_out_file);
79 	      output_addr_const (asm_out_file, x);
80 	      fputs (", ", 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 ('\n', 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 (op, 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 
112 void
dw2_asm_output_data_raw(int size,unsigned HOST_WIDE_INT value)113 dw2_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 (asm_out_file, "%#x,", bytes[i]);
128       fprintf (asm_out_file, "%#x", bytes[0]);
129     }
130   else
131     {
132       for (i = 0; i < size - 1; ++i)
133 	fprintf (asm_out_file, "%#x,", bytes[i]);
134       fprintf (asm_out_file, "%#x", bytes[i]);
135     }
136 }
137 
138 /* Output an immediate constant in a given SIZE in bytes.  */
139 
140 void
dw2_asm_output_data(int size,unsigned HOST_WIDE_INT value,const char * comment,...)141 dw2_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 (op, 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 ("\t" ASM_COMMENT_START " ", asm_out_file);
163       vfprintf (asm_out_file, comment, ap);
164     }
165   putc ('\n', 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 
176 void
dw2_asm_output_delta(int size,const char * lab1,const char * lab2,const char * comment,...)177 dw2_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 (asm_out_file, "\t%s ", ASM_COMMENT_START);
195       vfprintf (asm_out_file, comment, ap);
196     }
197   fputc ('\n', 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 
206 void
dw2_asm_output_vms_delta(int size ATTRIBUTE_UNUSED,const char * lab1,const char * lab2,const char * comment,...)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
dw2_asm_output_offset(int size,const char * label,section * base ATTRIBUTE_UNUSED,const char * comment,...)235 dw2_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 (asm_out_file, "\t%s ", ASM_COMMENT_START);
252       vfprintf (asm_out_file, comment, ap);
253     }
254   fputc ('\n', asm_out_file);
255 
256   va_end (ap);
257 }
258 
259 void
dw2_asm_output_offset(int size,const char * label,HOST_WIDE_INT offset,section * base ATTRIBUTE_UNUSED,const char * comment,...)260 dw2_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 (asm_out_file, "\t%s ", ASM_COMMENT_START);
279       vfprintf (asm_out_file, comment, ap);
280     }
281   fputc ('\n', 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 
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
dw2_asm_output_addr(int size,const char * label,const char * comment,...)323 dw2_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 (asm_out_file, "\t%s ", ASM_COMMENT_START);
335       vfprintf (asm_out_file, comment, ap);
336     }
337   fputc ('\n', asm_out_file);
338 
339   va_end (ap);
340 }
341 
342 /* Similar, but use an RTX expression instead of a text label.  */
343 
344 void
dw2_asm_output_addr_rtx(int size,rtx addr,const char * comment,...)345 dw2_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, addr);
353 
354   if (flag_debug_asm && comment)
355     {
356       fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
357       vfprintf (asm_out_file, comment, ap);
358     }
359   fputc ('\n', 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 
371 void
dw2_asm_output_nstring(const char * str,size_t orig_len,const char * comment,...)372 dw2_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 (str);
384 
385   if (flag_debug_asm && comment)
386     {
387       if (XCOFF_DEBUGGING_INFO)
388 	fputs ("\t.byte \"", asm_out_file);
389       else
390 	fputs ("\t.ascii \"", 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 ? '\"' : '\\', asm_out_file);
397 	  else if (c == '\\')
398 	    fputc ('\\', asm_out_file);
399 	  if (ISPRINT (c))
400 	    fputc (c, asm_out_file);
401 	  else
402 	    fprintf (asm_out_file, "\\%o", c);
403 	}
404       fprintf (asm_out_file, "\\0\"\t%s ", ASM_COMMENT_START);
405       vfprintf (asm_out_file, comment, ap);
406       fputc ('\n', 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 
425 int
size_of_uleb128(unsigned HOST_WIDE_INT value)426 size_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 
442 int
size_of_sleb128(HOST_WIDE_INT value)443 size_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 
463 int
size_of_encoded_value(int encoding)464 size_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 
486 const char *
eh_data_format_name(int format)487 eh_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 
646 void
dw2_asm_output_data_uleb128_raw(unsigned HOST_WIDE_INT value)647 dw2_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 (asm_out_file, "%#x", byte);
658       if (value == 0)
659 	break;
660       fputc (',', asm_out_file);
661     }
662 }
663 
664 /* Output an unsigned LEB128 quantity.  */
665 
666 void
dw2_asm_output_data_uleb128(unsigned HOST_WIDE_INT value,const char * comment,...)667 dw2_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 ("\t.uleb128 ", asm_out_file);
677       fprint_whex (asm_out_file, value);
678 
679       if (flag_debug_asm && comment)
680 	{
681 	  fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
682 	  vfprintf (asm_out_file, comment, 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 (byte_op, 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 (asm_out_file, "%#x", byte);
703 	      if (work != 0)
704 		fputc (',', 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 (asm_out_file, "\t%s uleb128 " HOST_WIDE_INT_PRINT_HEX,
714 		   ASM_COMMENT_START, value);
715 	  if (comment)
716 	    {
717 	      fputs ("; ", asm_out_file);
718 	      vfprintf (asm_out_file, comment, ap);
719 	    }
720 	}
721     }
722 
723   putc ('\n', asm_out_file);
724 
725   va_end (ap);
726 }
727 
728 /* Output an signed LEB128 quantity, but only the byte values.  */
729 
730 void
dw2_asm_output_data_sleb128_raw(HOST_WIDE_INT value)731 dw2_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 (asm_out_file, "%#x", byte);
745       if (!more)
746 	break;
747       fputc (',', asm_out_file);
748     }
749 }
750 
751 /* Output a signed LEB128 quantity.  */
752 
753 void
dw2_asm_output_data_sleb128(HOST_WIDE_INT value,const char * comment,...)754 dw2_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 (asm_out_file, "\t.sleb128 " HOST_WIDE_INT_PRINT_DEC, value);
764 
765       if (flag_debug_asm && comment)
766 	{
767 	  fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
768 	  vfprintf (asm_out_file, comment, 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 (byte_op, 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 (asm_out_file, "%#x", byte);
792 	      if (more)
793 		fputc (',', 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 (asm_out_file, "\t%s sleb128 " HOST_WIDE_INT_PRINT_DEC,
803 		   ASM_COMMENT_START, value);
804 	  if (comment)
805 	    {
806 	      fputs ("; ", asm_out_file);
807 	      vfprintf (asm_out_file, comment, ap);
808 	    }
809 	}
810     }
811 
812   fputc ('\n', 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 
821 void
dw2_asm_output_symname_uleb128(const char * lab1 ATTRIBUTE_UNUSED,const char * comment,...)822 dw2_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 ("\t.uleb128 ", 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 (asm_out_file, "\t%s ", ASM_COMMENT_START);
839       vfprintf (asm_out_file, comment, ap);
840     }
841   fputc ('\n', asm_out_file);
842 
843   va_end (ap);
844 }
845 
846 void
dw2_asm_output_delta_uleb128(const char * lab1 ATTRIBUTE_UNUSED,const char * lab2 ATTRIBUTE_UNUSED,const char * comment,...)847 dw2_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 ("\t.uleb128 ", asm_out_file);
858   assemble_name (asm_out_file, lab1);
859   putc ('-', 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 (lab2, '-') != NULL)
864     {
865       putc ('(', asm_out_file);
866       assemble_name (asm_out_file, lab2);
867       putc (')', asm_out_file);
868     }
869   else
870     assemble_name (asm_out_file, lab2);
871 
872   if (flag_debug_asm && comment)
873     {
874       fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
875       vfprintf (asm_out_file, comment, ap);
876     }
877   fputc ('\n', asm_out_file);
878 
879   va_end (ap);
880 }
881 
882 #if 0
883 
884 void
885 dw2_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 
911 static GTY(()) hash_map<const char *, tree> *indirect_pool;
912 
913 static 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 
926 static int
compare_strings(const void * a,const void * b)927 compare_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, 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 
952 rtx
dw2_force_const_mem(rtx x,bool is_public)953 dw2_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 (64);
960 
961   gcc_assert (GET_CODE (x) == SYMBOL_REF);
962 
963   key = XSTR (x, 0);
964   tree *slot = indirect_pool->get (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 (ref_name, "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 (key, 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 
1004 static int
dw2_output_indirect_constant_1(const char * sym,tree id)1005 dw2_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 
1050 void
dw2_output_indirect_constants(void)1051 dw2_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 (*iter);
1060 
1061   temp.qsort (compare_strings);
1062 
1063   for (unsigned int i = 0; i < temp.length (); i++)
1064     dw2_output_indirect_constant_1 (temp[i].first, 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 
1071 void
dw2_asm_output_encoded_addr_rtx(int encoding,rtx addr,bool is_public,const char * comment,...)1072 dw2_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 (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, 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 (asm_out_file, "\t%s ", ASM_COMMENT_START);
1155       vfprintf (asm_out_file, comment, ap);
1156     }
1157   fputc ('\n', asm_out_file);
1158 
1159   va_end (ap);
1160 }
1161 
1162 #include "gt-dwarf2asm.h"
1163