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