1 /* Dwarf2 assembler output helper routines.
2 Copyright (C) 2001 Free Software Foundation, Inc.
4 This file is part of GNU CC.
6 GNU CC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU CC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
28 #include "dwarf2asm.h"
30 #include "splay-tree.h"
35 /* How to start an assembler comment. */
36 #ifndef ASM_COMMENT_START
37 #define ASM_COMMENT_START ";#"
40 /* Definitions of defaults for assembler-dependent names of various
41 pseudo-ops and section names. These may be overridden in the tm.h
42 file (if necessary) for a particular assembler. */
44 #ifdef OBJECT_FORMAT_ELF
45 #ifndef UNALIGNED_SHORT_ASM_OP
46 #define UNALIGNED_SHORT_ASM_OP "\t.2byte\t"
48 #ifndef UNALIGNED_INT_ASM_OP
49 #define UNALIGNED_INT_ASM_OP "\t.4byte\t"
51 #ifndef UNALIGNED_DOUBLE_INT_ASM_OP
52 #define UNALIGNED_DOUBLE_INT_ASM_OP "\t.8byte\t"
54 #endif /* OBJECT_FORMAT_ELF */
57 #define ASM_BYTE_OP "\t.byte\t"
60 /* We don't have unaligned support, let's hope the normal output works for
61 .debug_frame. But we know it won't work for .debug_info. */
62 #if !defined(UNALIGNED_INT_ASM_OP) && defined(DWARF2_DEBUGGING_INFO)
63 #error DWARF2_DEBUGGING_INFO requires UNALIGNED_INT_ASM_OP.
67 #ifdef UNALIGNED_INT_ASM_OP
68 static const char * unaligned_integer_asm_op PARAMS ((int));
70 static inline const char *
71 unaligned_integer_asm_op (size)
81 op = UNALIGNED_SHORT_ASM_OP;
84 op = UNALIGNED_INT_ASM_OP;
87 #ifdef UNALIGNED_DOUBLE_INT_ASM_OP
88 op = UNALIGNED_DOUBLE_INT_ASM_OP;
96 #endif /* UNALIGNED_INT_ASM_OP */
98 /* Output an immediate constant in a given size. */
101 dw2_asm_output_data VPARAMS ((int size, unsigned HOST_WIDE_INT value,
102 const char *comment, ...))
104 #ifndef ANSI_PROTOTYPES
106 unsigned HOST_WIDE_INT value;
111 VA_START (ap, comment);
113 #ifndef ANSI_PROTOTYPES
114 size = va_arg (ap, int);
115 value = va_arg (ap, unsigned HOST_WIDE_INT);
116 comment = va_arg (ap, const char *);
119 if (size * 8 < HOST_BITS_PER_WIDE_INT)
120 value &= ~(~(unsigned HOST_WIDE_INT)0 << (size * 8));
122 #ifdef UNALIGNED_INT_ASM_OP
123 fputs (unaligned_integer_asm_op (size), asm_out_file);
124 fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, value);
126 assemble_integer (GEN_INT (value), size, 1);
129 if (flag_debug_asm && comment)
131 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
132 vfprintf (asm_out_file, comment, ap);
134 fputc ('\n', asm_out_file);
139 /* Output the difference between two symbols in a given size. */
140 /* ??? There appear to be assemblers that do not like such
141 subtraction, but do support ASM_SET_OP. It's unfortunately
142 impossible to do here, since the ASM_SET_OP for the difference
143 symbol must appear after both symbols are defined. */
146 dw2_asm_output_delta VPARAMS ((int size, const char *lab1, const char *lab2,
147 const char *comment, ...))
149 #ifndef ANSI_PROTOTYPES
151 const char *lab1, *lab2;
156 VA_START (ap, comment);
158 #ifndef ANSI_PROTOTYPES
159 size = va_arg (ap, int);
160 lab1 = va_arg (ap, const char *);
161 lab2 = va_arg (ap, const char *);
162 comment = va_arg (ap, const char *);
165 #ifdef UNALIGNED_INT_ASM_OP
166 fputs (unaligned_integer_asm_op (size), asm_out_file);
167 assemble_name (asm_out_file, lab1);
168 fputc ('-', asm_out_file);
169 assemble_name (asm_out_file, lab2);
171 assemble_integer (gen_rtx_MINUS (smallest_mode_for_size (size, MODE_INT),
172 gen_rtx_SYMBOL_REF (Pmode, lab1),
173 gen_rtx_SYMBOL_REF (Pmode, lab2)),
177 if (flag_debug_asm && comment)
179 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
180 vfprintf (asm_out_file, comment, ap);
182 fputc ('\n', asm_out_file);
187 /* Output a section-relative reference to a label. In general this
188 can only be done for debugging symbols. E.g. on most targets with
189 the GNU linker, this is accomplished with a direct reference and
190 the knowledge that the debugging section will be placed at VMA 0.
191 Some targets have special relocations for this that we must use. */
194 dw2_asm_output_offset VPARAMS ((int size, const char *label,
195 const char *comment, ...))
197 #ifndef ANSI_PROTOTYPES
204 VA_START (ap, comment);
206 #ifndef ANSI_PROTOTYPES
207 size = va_arg (ap, int);
208 label = va_arg (ap, const char *);
209 comment = va_arg (ap, const char *);
212 #ifdef ASM_OUTPUT_DWARF_OFFSET
213 ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label);
215 #ifdef UNALIGNED_INT_ASM_OP
216 fputs (unaligned_integer_asm_op (size), asm_out_file);
217 assemble_name (asm_out_file, label);
219 assemble_integer (gen_rtx_SYMBOL_REF (Pmode, label), size, 1);
223 if (flag_debug_asm && comment)
225 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
226 vfprintf (asm_out_file, comment, ap);
228 fputc ('\n', asm_out_file);
233 /* Output a self-relative reference to a label, possibly in a
234 different section or object file. */
237 dw2_asm_output_pcrel VPARAMS ((int size, const char *label,
238 const char *comment, ...))
240 #ifndef ANSI_PROTOTYPES
247 VA_START (ap, comment);
249 #ifndef ANSI_PROTOTYPES
250 size = va_arg (ap, int);
251 label = va_arg (ap, const char *);
252 comment = va_arg (ap, const char *);
255 #ifdef ASM_OUTPUT_DWARF_PCREL
256 ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, label);
258 #ifdef UNALIGNED_INT_ASM_OP
259 fputs (unaligned_integer_asm_op (size), asm_out_file);
260 assemble_name (asm_out_file, label);
261 fputc ('-', asm_out_file);
262 fputc ('.', asm_out_file);
268 if (flag_debug_asm && comment)
270 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
271 vfprintf (asm_out_file, comment, ap);
273 fputc ('\n', asm_out_file);
278 /* Output an absolute reference to a label. */
281 dw2_asm_output_addr VPARAMS ((int size, const char *label,
282 const char *comment, ...))
284 #ifndef ANSI_PROTOTYPES
291 VA_START (ap, comment);
293 #ifndef ANSI_PROTOTYPES
294 size = va_arg (ap, int);
295 label = va_arg (ap, const char *);
296 comment = va_arg (ap, const char *);
299 #ifdef UNALIGNED_INT_ASM_OP
300 fputs (unaligned_integer_asm_op (size), asm_out_file);
301 assemble_name (asm_out_file, label);
303 assemble_integer (gen_rtx_SYMBOL_REF (Pmode, label), size, 1);
306 if (flag_debug_asm && comment)
308 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
309 vfprintf (asm_out_file, comment, ap);
311 fputc ('\n', asm_out_file);
316 /* Similar, but use an RTX expression instead of a text label. */
319 dw2_asm_output_addr_rtx VPARAMS ((int size, rtx addr,
320 const char *comment, ...))
322 #ifndef ANSI_PROTOTYPES
329 VA_START (ap, comment);
331 #ifndef ANSI_PROTOTYPES
332 size = va_arg (ap, int);
333 addr = va_arg (ap, rtx);
334 comment = va_arg (ap, const char *);
337 #ifdef UNALIGNED_INT_ASM_OP
338 fputs (unaligned_integer_asm_op (size), asm_out_file);
339 output_addr_const (asm_out_file, addr);
341 assemble_integer (addr, size, 1);
344 if (flag_debug_asm && comment)
346 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
347 vfprintf (asm_out_file, comment, ap);
349 fputc ('\n', asm_out_file);
355 dw2_asm_output_nstring VPARAMS ((const char *str, size_t orig_len,
356 const char *comment, ...))
358 #ifndef ANSI_PROTOTYPES
364 size_t i, len = orig_len;
366 VA_START (ap, comment);
368 #ifndef ANSI_PROTOTYPES
369 str = va_arg (ap, const char *);
370 len = va_arg (ap, size_t);
371 comment = va_arg (ap, const char *);
374 if (len == (size_t) -1)
377 if (flag_debug_asm && comment)
379 fputs ("\t.ascii \"", asm_out_file);
380 for (i = 0; i < len; i++)
383 if (c == '\"' || c == '\\')
384 fputc ('\\', asm_out_file);
386 fputc (c, asm_out_file);
388 fprintf (asm_out_file, "\\%o", c);
390 fprintf (asm_out_file, "\\0\"\t%s ", ASM_COMMENT_START);
391 vfprintf (asm_out_file, comment, ap);
392 fputc ('\n', asm_out_file);
396 /* If an explicit length was given, we can't assume there
397 is a null termination in the string buffer. */
398 if (orig_len == (size_t) -1)
400 ASM_OUTPUT_ASCII (asm_out_file, str, len);
401 if (orig_len != (size_t) -1)
402 fprintf (asm_out_file, "%s0\n", ASM_BYTE_OP);
409 /* Return the size of an unsigned LEB128 quantity. */
412 size_of_uleb128 (value)
413 unsigned HOST_WIDE_INT value;
419 byte = (value & 0x7f);
428 /* Return the size of a signed LEB128 quantity. */
431 size_of_sleb128 (value)
438 byte = (value & 0x7f);
442 while (!((value == 0 && (byte & 0x40) == 0)
443 || (value == -1 && (byte & 0x40) != 0)));
448 /* Output an unsigned LEB128 quantity. */
451 dw2_asm_output_data_uleb128 VPARAMS ((unsigned HOST_WIDE_INT value,
452 const char *comment, ...))
454 #ifndef ANSI_PROTOTYPES
455 unsigned HOST_WIDE_INT value;
460 VA_START (ap, comment);
462 #ifndef ANSI_PROTOTYPES
463 value = va_arg (ap, unsigned HOST_WIDE_INT);
464 comment = va_arg (ap, const char *);
467 #ifdef HAVE_AS_LEB128
468 fputs ("\t.uleb128 ", asm_out_file);
469 fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, value);
471 if (flag_debug_asm && comment)
473 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
474 vfprintf (asm_out_file, comment, ap);
478 unsigned HOST_WIDE_INT work = value;
480 fputs (ASM_BYTE_OP, asm_out_file);
483 int byte = (work & 0x7f);
486 /* More bytes to follow. */
489 fprintf (asm_out_file, "0x%x", byte);
491 fputc (',', asm_out_file);
497 fprintf (asm_out_file, "\t%s uleb128 ", ASM_COMMENT_START);
498 fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, value);
501 fputs ("; ", asm_out_file);
502 vfprintf (asm_out_file, comment, ap);
507 fputc ('\n', asm_out_file);
512 /* Output an signed LEB128 quantity. */
515 dw2_asm_output_data_sleb128 VPARAMS ((HOST_WIDE_INT value,
516 const char *comment, ...))
518 #ifndef ANSI_PROTOTYPES
524 VA_START (ap, comment);
526 #ifndef ANSI_PROTOTYPES
527 value = va_arg (ap, HOST_WIDE_INT);
528 comment = va_arg (ap, const char *);
531 #ifdef HAVE_AS_LEB128
532 fputs ("\t.sleb128 ", asm_out_file);
533 fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, value);
535 if (flag_debug_asm && comment)
537 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
538 vfprintf (asm_out_file, comment, ap);
542 HOST_WIDE_INT work = value;
545 fputs (ASM_BYTE_OP, asm_out_file);
548 byte = (work & 0x7f);
549 /* arithmetic shift */
551 more = !((work == 0 && (byte & 0x40) == 0)
552 || (work == -1 && (byte & 0x40) != 0));
556 fprintf (asm_out_file, "0x%x", byte);
558 fputc (',', asm_out_file);
564 fprintf (asm_out_file, "\t%s sleb128 ", ASM_COMMENT_START);
565 fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, value);
568 fputs ("; ", asm_out_file);
569 vfprintf (asm_out_file, comment, ap);
574 fputc ('\n', asm_out_file);
580 dw2_asm_output_delta_uleb128 VPARAMS ((const char *lab1 ATTRIBUTE_UNUSED,
581 const char *lab2 ATTRIBUTE_UNUSED,
582 const char *comment, ...))
584 #ifndef ANSI_PROTOTYPES
585 const char *lab1, *lab2;
590 VA_START (ap, comment);
592 #ifndef ANSI_PROTOTYPES
593 lab1 = va_arg (ap, const char *);
594 lab2 = va_arg (ap, const char *);
595 comment = va_arg (ap, const char *);
598 #ifdef HAVE_AS_LEB128
599 fputs ("\t.uleb128 ", asm_out_file);
600 assemble_name (asm_out_file, lab1);
601 fputc ('-', asm_out_file);
602 assemble_name (asm_out_file, lab2);
607 if (flag_debug_asm && comment)
609 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
610 vfprintf (asm_out_file, comment, ap);
612 fputc ('\n', asm_out_file);
618 dw2_asm_output_delta_sleb128 VPARAMS ((const char *lab1 ATTRIBUTE_UNUSED,
619 const char *lab2 ATTRIBUTE_UNUSED,
620 const char *comment, ...))
622 #ifndef ANSI_PROTOTYPES
623 const char *lab1, *lab2;
628 VA_START (ap, comment);
630 #ifndef ANSI_PROTOTYPES
631 lab1 = va_arg (ap, const char *);
632 lab2 = va_arg (ap, const char *);
633 comment = va_arg (ap, const char *);
636 #ifdef HAVE_AS_LEB128
637 fputs ("\t.sleb128 ", asm_out_file);
638 assemble_name (asm_out_file, lab1);
639 fputc ('-', asm_out_file);
640 assemble_name (asm_out_file, lab2);
645 if (flag_debug_asm && comment)
647 fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
648 vfprintf (asm_out_file, comment, ap);
650 fputc ('\n', asm_out_file);
655 static rtx dw2_force_const_mem PARAMS ((rtx));
656 static int dw2_output_indirect_constant_1 PARAMS ((splay_tree_node, void *));
658 static splay_tree indirect_pool;
661 dw2_force_const_mem (x)
664 splay_tree_node node;
665 const char *const_sym;
668 indirect_pool = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
670 if (GET_CODE (x) != SYMBOL_REF)
672 node = splay_tree_lookup (indirect_pool, (splay_tree_key) XSTR (x, 0));
674 const_sym = (const char *) node->value;
677 extern int const_labelno;
681 ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
683 const_sym = ggc_strdup (label);
685 id = maybe_get_identifier (XSTR (x, 0));
687 TREE_SYMBOL_REFERENCED (id) = 1;
689 splay_tree_insert (indirect_pool, (splay_tree_key) XSTR (x, 0),
690 (splay_tree_value) const_sym);
693 return gen_rtx_SYMBOL_REF (Pmode, const_sym);
697 dw2_output_indirect_constant_1 (node, data)
698 splay_tree_node node;
699 void* data ATTRIBUTE_UNUSED;
701 const char *label, *sym;
704 label = (const char *) node->value;
705 sym = (const char *) node->key;
706 sym_ref = gen_rtx_SYMBOL_REF (Pmode, sym);
708 ASM_OUTPUT_LABEL (asm_out_file, label);
709 assemble_integer (sym_ref, POINTER_SIZE / BITS_PER_UNIT, 1);
715 dw2_output_indirect_constants ()
720 /* Assume that the whole reason we're emitting these symbol references
721 indirectly is that they contain dynamic relocations, and are thus
722 read-write. If there was no possibility of a dynamic relocation, we
723 might as well have used a direct relocation. */
726 /* Everything we're emitting is a pointer. Align appropriately. */
727 assemble_align (POINTER_SIZE);
729 splay_tree_foreach (indirect_pool, dw2_output_indirect_constant_1, NULL);
733 dw2_asm_output_encoded_addr_rtx (encoding, addr)
739 switch (encoding & 0x07)
741 case DW_EH_PE_absptr:
742 size = POINTER_SIZE / BITS_PER_UNIT;
744 case DW_EH_PE_udata2:
747 case DW_EH_PE_udata4:
750 case DW_EH_PE_udata8:
757 /* NULL is _always_ represented as a plain zero. */
758 if (addr == const0_rtx)
760 assemble_integer (addr, size, 1);
766 /* Allow the target first crack at emitting this. Some of the
767 special relocations require special directives instead of
768 just ".4byte" or whatever. */
769 #ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
770 ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(asm_out_file, encoding, size, addr, done);
773 /* Indirection is used to get dynamic relocations out of a read-only
775 if (encoding & DW_EH_PE_indirect)
777 /* It is very tempting to use force_const_mem so that we share data
778 with the normal constant pool. However, we've already emitted
779 the constant pool for this function. Moreover, we'd like to share
780 these constants across the entire unit of translation, or better,
781 across the entire application (or DSO). */
782 addr = dw2_force_const_mem (addr);
783 encoding &= ~DW_EH_PE_indirect;
787 switch (encoding & 0xF0)
789 case DW_EH_PE_absptr:
790 #ifdef UNALIGNED_INT_ASM_OP
791 fputs (unaligned_integer_asm_op (size), asm_out_file);
792 output_addr_const (asm_out_file, addr);
794 assemble_integer (addr, size, 1);
799 if (GET_CODE (addr) != SYMBOL_REF)
801 #ifdef ASM_OUTPUT_DWARF_PCREL
802 ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, XSTR (addr, 0));
804 #ifdef UNALIGNED_INT_ASM_OP
805 fputs (unaligned_integer_asm_op (size), asm_out_file);
806 assemble_name (asm_out_file, XSTR (addr, 0));
807 fputc ('-', asm_out_file);
808 fputc ('.', asm_out_file);
816 /* Other encodings should have been handled by
817 ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX. */
821 #ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
824 fputc ('\n', asm_out_file);