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