/* Dwarf2 assembler output helper routines.
- Copyright (C) 2001 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
+ Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "flags.h"
#include "tree.h"
#include "rtl.h"
#include "output.h"
+#include "target.h"
#include "dwarf2asm.h"
#include "dwarf2.h"
#include "splay-tree.h"
#define ASM_COMMENT_START ";#"
#endif
-/* We don't have unaligned support, let's hope the normal output works for
- .debug_frame. But we know it won't work for .debug_info. */
-#if !defined(UNALIGNED_INT_ASM_OP) && defined(DWARF2_DEBUGGING_INFO)
- #error DWARF2_DEBUGGING_INFO requires UNALIGNED_INT_ASM_OP.
-#endif
-
\f
-/* Despite the fact that assemble_integer handles unaligned data,
- continue emitting things by hand when possible, since that makes
- the assembler commentary come out prettier. */
-#ifdef UNALIGNED_INT_ASM_OP
-static const char * unaligned_integer_asm_op PARAMS ((int));
-
-static inline const char *
-unaligned_integer_asm_op (size)
- int size;
+/* Output an unaligned integer with the given value and size. Prefer not
+ to print a newline, since the caller may want to add a comment. */
+
+void
+dw2_assemble_integer (int size, rtx x)
{
- const char *op;
- switch (size)
+ const char *op = integer_asm_op (size, FALSE);
+
+ if (op)
{
- case 1:
- op = ASM_BYTE_OP;
- break;
- case 2:
- op = UNALIGNED_SHORT_ASM_OP;
- break;
- case 4:
- op = UNALIGNED_INT_ASM_OP;
- break;
- case 8:
-#ifdef UNALIGNED_DOUBLE_INT_ASM_OP
- op = UNALIGNED_DOUBLE_INT_ASM_OP;
- break;
-#endif
- default:
- abort ();
+ fputs (op, asm_out_file);
+ if (CONST_INT_P (x))
+ fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX,
+ (unsigned HOST_WIDE_INT) INTVAL (x));
+ else
+ output_addr_const (asm_out_file, x);
+ }
+ else
+ assemble_integer (x, size, BITS_PER_UNIT, 1);
+}
+
+
+/* Output a value of a given size in target byte order. */
+
+void
+dw2_asm_output_data_raw (int size, unsigned HOST_WIDE_INT value)
+{
+ unsigned char bytes[8];
+ int i;
+
+ for (i = 0; i < 8; ++i)
+ {
+ bytes[i] = value & 0xff;
+ value >>= 8;
+ }
+
+ if (BYTES_BIG_ENDIAN)
+ {
+ for (i = size - 1; i > 0; --i)
+ fprintf (asm_out_file, "0x%x,", bytes[i]);
+ fprintf (asm_out_file, "0x%x", bytes[0]);
+ }
+ else
+ {
+ for (i = 0; i < size - 1; ++i)
+ fprintf (asm_out_file, "0x%x,", bytes[i]);
+ fprintf (asm_out_file, "0x%x", bytes[i]);
}
- return op;
}
-#endif /* UNALIGNED_INT_ASM_OP */
-/* Output an immediate constant in a given size. */
+/* Output an immediate constant in a given SIZE in bytes. */
void
-dw2_asm_output_data VPARAMS ((int size, unsigned HOST_WIDE_INT value,
- const char *comment, ...))
+dw2_asm_output_data (int size, unsigned HOST_WIDE_INT value,
+ const char *comment, ...)
{
- VA_OPEN (ap, comment);
- VA_FIXEDARG (ap, int, size);
- VA_FIXEDARG (ap, unsigned HOST_WIDE_INT, value);
- VA_FIXEDARG (ap, const char *, comment);
+ va_list ap;
+ const char *op = integer_asm_op (size, FALSE);
+
+ va_start (ap, comment);
if (size * 8 < HOST_BITS_PER_WIDE_INT)
- value &= ~(~(unsigned HOST_WIDE_INT)0 << (size * 8));
+ value &= ~(~(unsigned HOST_WIDE_INT) 0 << (size * 8));
-#ifdef UNALIGNED_INT_ASM_OP
- fputs (unaligned_integer_asm_op (size), asm_out_file);
- fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, value);
-#else
- assemble_integer (GEN_INT (value), size, BITS_PER_UNIT, 1);
-#endif
+ if (op)
+ fprintf (asm_out_file, "%s" HOST_WIDE_INT_PRINT_HEX, op, value);
+ else
+ assemble_integer (GEN_INT (value), size, BITS_PER_UNIT, 1);
if (flag_debug_asm && comment)
{
}
fputc ('\n', asm_out_file);
- VA_CLOSE (ap);
+ va_end (ap);
}
/* Output the difference between two symbols in a given size. */
symbol must appear after both symbols are defined. */
void
-dw2_asm_output_delta VPARAMS ((int size, const char *lab1, const char *lab2,
- const char *comment, ...))
+dw2_asm_output_delta (int size, const char *lab1, const char *lab2,
+ const char *comment, ...)
{
- VA_OPEN (ap, comment);
- VA_FIXEDARG (ap, int, size);
- VA_FIXEDARG (ap, const char *, lab1);
- VA_FIXEDARG (ap, const char *, lab2);
- VA_FIXEDARG (ap, const char *, comment);
-
-#ifdef UNALIGNED_INT_ASM_OP
- fputs (unaligned_integer_asm_op (size), asm_out_file);
- assemble_name (asm_out_file, lab1);
- fputc ('-', asm_out_file);
- assemble_name (asm_out_file, lab2);
+ va_list ap;
+
+ va_start (ap, comment);
+
+#ifdef ASM_OUTPUT_DWARF_DELTA
+ ASM_OUTPUT_DWARF_DELTA (asm_out_file, size, lab1, lab2);
#else
- assemble_integer (gen_rtx_MINUS (Pmode, gen_rtx_SYMBOL_REF (Pmode, lab1),
- gen_rtx_SYMBOL_REF (Pmode, lab2)),
- size, BITS_PER_UNIT, 1);
+ dw2_assemble_integer (size,
+ gen_rtx_MINUS (Pmode,
+ gen_rtx_SYMBOL_REF (Pmode, lab1),
+ gen_rtx_SYMBOL_REF (Pmode, lab2)));
#endif
-
if (flag_debug_asm && comment)
{
fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
}
fputc ('\n', asm_out_file);
- VA_CLOSE (ap);
+ va_end (ap);
}
-/* Output a section-relative reference to a label. In general this
- can only be done for debugging symbols. E.g. on most targets with
- the GNU linker, this is accomplished with a direct reference and
- the knowledge that the debugging section will be placed at VMA 0.
- Some targets have special relocations for this that we must use. */
+/* Output a section-relative reference to a LABEL, which was placed in
+ BASE. In general this can only be done for debugging symbols.
+ E.g. on most targets with the GNU linker, this is accomplished with
+ a direct reference and the knowledge that the debugging section
+ will be placed at VMA 0. Some targets have special relocations for
+ this that we must use. */
void
-dw2_asm_output_offset VPARAMS ((int size, const char *label,
- const char *comment, ...))
+dw2_asm_output_offset (int size, const char *label,
+ section *base ATTRIBUTE_UNUSED,
+ const char *comment, ...)
{
- VA_OPEN (ap, comment);
- VA_FIXEDARG (ap, int, size);
- VA_FIXEDARG (ap, const char *, label);
- VA_FIXEDARG (ap, const char *, comment);
+ va_list ap;
+
+ va_start (ap, comment);
#ifdef ASM_OUTPUT_DWARF_OFFSET
- ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label);
+ ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label, base);
#else
-#ifdef UNALIGNED_INT_ASM_OP
- fputs (unaligned_integer_asm_op (size), asm_out_file);
- assemble_name (asm_out_file, label);
-#else
- assemble_integer (gen_rtx_SYMBOL_REF (Pmode, label), size, BITS_PER_UNIT, 1);
-#endif
+ dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
#endif
if (flag_debug_asm && comment)
}
fputc ('\n', asm_out_file);
- VA_CLOSE (ap);
+ va_end (ap);
}
+#if 0
+
/* Output a self-relative reference to a label, possibly in a
different section or object file. */
void
-dw2_asm_output_pcrel VPARAMS ((int size, const char *label,
- const char *comment, ...))
+dw2_asm_output_pcrel (int size ATTRIBUTE_UNUSED,
+ const char *label ATTRIBUTE_UNUSED,
+ const char *comment, ...)
{
- VA_OPEN (ap, comment);
- VA_FIXEDARG (ap, int, size);
- VA_FIXEDARG (ap, const char *, label);
- VA_FIXEDARG (ap, const char *, comment);
+ va_list ap;
+
+ va_start (ap, comment);
#ifdef ASM_OUTPUT_DWARF_PCREL
ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, label);
#else
-#ifdef UNALIGNED_INT_ASM_OP
- fputs (unaligned_integer_asm_op (size), asm_out_file);
- assemble_name (asm_out_file, label);
- fputc ('-', asm_out_file);
- fputc ('.', asm_out_file);
-#else
- abort ();
-#endif
+ dw2_assemble_integer (size,
+ gen_rtx_MINUS (Pmode,
+ gen_rtx_SYMBOL_REF (Pmode, label),
+ pc_rtx));
#endif
if (flag_debug_asm && comment)
}
fputc ('\n', asm_out_file);
- VA_CLOSE (ap);
+ va_end (ap);
}
+#endif /* 0 */
/* Output an absolute reference to a label. */
void
-dw2_asm_output_addr VPARAMS ((int size, const char *label,
- const char *comment, ...))
+dw2_asm_output_addr (int size, const char *label,
+ const char *comment, ...)
{
- VA_OPEN (ap, comment);
- VA_FIXEDARG (ap, int, size);
- VA_FIXEDARG (ap, const char *, label);
- VA_FIXEDARG (ap, const char *, comment);
-
-#ifdef UNALIGNED_INT_ASM_OP
- fputs (unaligned_integer_asm_op (size), asm_out_file);
- assemble_name (asm_out_file, label);
-#else
- assemble_integer (gen_rtx_SYMBOL_REF (Pmode, label), size, BITS_PER_UNIT, 1);
-#endif
+ va_list ap;
+
+ va_start (ap, comment);
+
+ dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
if (flag_debug_asm && comment)
{
}
fputc ('\n', asm_out_file);
- VA_CLOSE (ap);
+ va_end (ap);
}
/* Similar, but use an RTX expression instead of a text label. */
void
-dw2_asm_output_addr_rtx VPARAMS ((int size, rtx addr,
- const char *comment, ...))
+dw2_asm_output_addr_rtx (int size, rtx addr,
+ const char *comment, ...)
{
- VA_OPEN (ap, comment);
- VA_FIXEDARG (ap, int, size);
- VA_FIXEDARG (ap, rtx, addr);
- VA_FIXEDARG (ap, const char *, comment);
-
-#ifdef UNALIGNED_INT_ASM_OP
- fputs (unaligned_integer_asm_op (size), asm_out_file);
- output_addr_const (asm_out_file, addr);
-#else
- assemble_integer (addr, size, BITS_PER_UNIT, 1);
-#endif
+ va_list ap;
+
+ va_start (ap, comment);
+
+ dw2_assemble_integer (size, addr);
if (flag_debug_asm && comment)
{
}
fputc ('\n', asm_out_file);
- VA_CLOSE (ap);
+ va_end (ap);
}
+/* Output the first ORIG_LEN characters of STR as a string.
+ If ORIG_LEN is equal to -1, ignore this parameter and output
+ the entire STR instead.
+ If COMMENT is not NULL and comments in the debug information
+ have been requested by the user, append the given COMMENT
+ to the generated output. */
+
void
-dw2_asm_output_nstring VPARAMS ((const char *str, size_t orig_len,
- const char *comment, ...))
+dw2_asm_output_nstring (const char *str, size_t orig_len,
+ const char *comment, ...)
{
size_t i, len;
+ va_list ap;
- VA_OPEN (ap, comment);
- VA_FIXEDARG (ap, const char *, str);
- VA_FIXEDARG (ap, size_t, len);
- VA_FIXEDARG (ap, const char *, comment);
+ va_start (ap, comment);
len = orig_len;
len += 1;
ASM_OUTPUT_ASCII (asm_out_file, str, len);
if (orig_len != (size_t) -1)
- fprintf (asm_out_file, "%s0\n", ASM_BYTE_OP);
+ assemble_integer (const0_rtx, 1, BITS_PER_UNIT, 1);
}
- VA_CLOSE (ap);
+ va_end (ap);
}
\f
/* Return the size of an unsigned LEB128 quantity. */
int
-size_of_uleb128 (value)
- unsigned HOST_WIDE_INT value;
+size_of_uleb128 (unsigned HOST_WIDE_INT value)
{
- int size = 0, byte;
+ int size = 0;
do
{
- byte = (value & 0x7f);
value >>= 7;
size += 1;
}
/* Return the size of a signed LEB128 quantity. */
int
-size_of_sleb128 (value)
- HOST_WIDE_INT value;
+size_of_sleb128 (HOST_WIDE_INT value)
{
int size = 0, byte;
}
/* Given an encoding, return the number of bytes the format occupies.
- This is only defined for fixed-size encodings, and so does not
+ This is only defined for fixed-size encodings, and so does not
include leb128. */
int
-size_of_encoded_value (encoding)
- int encoding;
+size_of_encoded_value (int encoding)
{
if (encoding == DW_EH_PE_omit)
return 0;
return 4;
case DW_EH_PE_udata8:
return 8;
+ default:
+ gcc_unreachable ();
}
- abort ();
}
/* Yield a name for a given pointer encoding. */
const char *
-eh_data_format_name (format)
- int format;
+eh_data_format_name (int format)
{
#if HAVE_DESIGNATED_INITIALIZERS
#define S(p, v) [p] = v,
S(DW_EH_PE_sdata4 | DW_EH_PE_funcrel, "funcrel sdata4")
S(DW_EH_PE_sdata8 | DW_EH_PE_funcrel, "funcrel sdata8")
+ S(DW_EH_PE_indirect | DW_EH_PE_absptr, "indirect absolute")
+
S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_pcrel,
"indirect pcrel")
S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_pcrel,
#if HAVE_DESIGNATED_INITIALIZERS
};
- if (format < 0 || format > 0xff || format_names[format] == NULL)
- abort ();
+ gcc_assert (format >= 0 && format < 0x100 && format_names[format]);
+
return format_names[format];
#else
}
- abort ();
+ gcc_unreachable ();
#endif
}
+/* Output an unsigned LEB128 quantity, but only the byte values. */
+
+void
+dw2_asm_output_data_uleb128_raw (unsigned HOST_WIDE_INT value)
+{
+ while (1)
+ {
+ int byte = (value & 0x7f);
+ value >>= 7;
+ if (value != 0)
+ /* More bytes to follow. */
+ byte |= 0x80;
+
+ fprintf (asm_out_file, "0x%x", byte);
+ if (value == 0)
+ break;
+ fputc (',', asm_out_file);
+ }
+}
+
/* Output an unsigned LEB128 quantity. */
void
-dw2_asm_output_data_uleb128 VPARAMS ((unsigned HOST_WIDE_INT value,
- const char *comment, ...))
+dw2_asm_output_data_uleb128 (unsigned HOST_WIDE_INT value,
+ const char *comment, ...)
{
- VA_OPEN (ap, comment);
- VA_FIXEDARG (ap, unsigned HOST_WIDE_INT, value);
- VA_FIXEDARG (ap, const char *, comment);
+ va_list ap;
+
+ va_start (ap, comment);
#ifdef HAVE_AS_LEB128
- fputs ("\t.uleb128 ", asm_out_file);
- fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, value);
+ fprintf (asm_out_file, "\t.uleb128 " HOST_WIDE_INT_PRINT_HEX , value);
if (flag_debug_asm && comment)
{
#else
{
unsigned HOST_WIDE_INT work = value;
+ const char *byte_op = targetm.asm_out.byte_op;
- fputs (ASM_BYTE_OP, asm_out_file);
+ if (byte_op)
+ fputs (byte_op, asm_out_file);
do
{
int byte = (work & 0x7f);
/* More bytes to follow. */
byte |= 0x80;
- fprintf (asm_out_file, "0x%x", byte);
- if (work != 0)
- fputc (',', asm_out_file);
+ if (byte_op)
+ {
+ fprintf (asm_out_file, "0x%x", byte);
+ if (work != 0)
+ fputc (',', asm_out_file);
+ }
+ else
+ assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
}
while (work != 0);
if (flag_debug_asm)
{
- fprintf (asm_out_file, "\t%s uleb128 ", ASM_COMMENT_START);
- fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, value);
+ fprintf (asm_out_file, "\t%s uleb128 " HOST_WIDE_INT_PRINT_HEX,
+ ASM_COMMENT_START, value);
if (comment)
{
fputs ("; ", asm_out_file);
#endif
fputc ('\n', asm_out_file);
- VA_CLOSE (ap);
+ va_end (ap);
+}
+
+/* Output an signed LEB128 quantity, but only the byte values. */
+
+void
+dw2_asm_output_data_sleb128_raw (HOST_WIDE_INT value)
+{
+ int byte, more;
+
+ while (1)
+ {
+ byte = (value & 0x7f);
+ value >>= 7;
+ more = !((value == 0 && (byte & 0x40) == 0)
+ || (value == -1 && (byte & 0x40) != 0));
+ if (more)
+ byte |= 0x80;
+
+ fprintf (asm_out_file, "0x%x", byte);
+ if (!more)
+ break;
+ fputc (',', asm_out_file);
+ }
}
-/* Output an signed LEB128 quantity. */
+/* Output a signed LEB128 quantity. */
void
-dw2_asm_output_data_sleb128 VPARAMS ((HOST_WIDE_INT value,
- const char *comment, ...))
+dw2_asm_output_data_sleb128 (HOST_WIDE_INT value,
+ const char *comment, ...)
{
- VA_OPEN (ap, comment);
- VA_FIXEDARG (ap, HOST_WIDE_INT, value);
- VA_FIXEDARG (ap, const char *, comment);
+ va_list ap;
+
+ va_start (ap, comment);
#ifdef HAVE_AS_LEB128
- fputs ("\t.sleb128 ", asm_out_file);
- fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, value);
+ fprintf (asm_out_file, "\t.sleb128 " HOST_WIDE_INT_PRINT_DEC, value);
if (flag_debug_asm && comment)
{
{
HOST_WIDE_INT work = value;
int more, byte;
+ const char *byte_op = targetm.asm_out.byte_op;
- fputs (ASM_BYTE_OP, asm_out_file);
+ if (byte_op)
+ fputs (byte_op, asm_out_file);
do
{
byte = (work & 0x7f);
if (more)
byte |= 0x80;
- fprintf (asm_out_file, "0x%x", byte);
- if (more)
- fputc (',', asm_out_file);
+ if (byte_op)
+ {
+ fprintf (asm_out_file, "0x%x", byte);
+ if (more)
+ fputc (',', asm_out_file);
+ }
+ else
+ assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
}
while (more);
if (flag_debug_asm)
{
- fprintf (asm_out_file, "\t%s sleb128 ", ASM_COMMENT_START);
- fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, value);
+ fprintf (asm_out_file, "\t%s sleb128 " HOST_WIDE_INT_PRINT_DEC,
+ ASM_COMMENT_START, value);
if (comment)
{
fputs ("; ", asm_out_file);
#endif
fputc ('\n', asm_out_file);
- VA_CLOSE (ap);
+ va_end (ap);
}
void
-dw2_asm_output_delta_uleb128 VPARAMS ((const char *lab1 ATTRIBUTE_UNUSED,
- const char *lab2 ATTRIBUTE_UNUSED,
- const char *comment, ...))
+dw2_asm_output_delta_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
+ const char *lab2 ATTRIBUTE_UNUSED,
+ const char *comment, ...)
{
- VA_OPEN (ap, comment);
- VA_FIXEDARG (ap, const char *, lab1);
- VA_FIXEDARG (ap, const char *, lab2);
- VA_FIXEDARG (ap, const char *, comment);
+ va_list ap;
+
+ va_start (ap, comment);
#ifdef HAVE_AS_LEB128
fputs ("\t.uleb128 ", asm_out_file);
fputc ('-', asm_out_file);
assemble_name (asm_out_file, lab2);
#else
- abort ();
+ gcc_unreachable ();
#endif
if (flag_debug_asm && comment)
}
fputc ('\n', asm_out_file);
- VA_CLOSE (ap);
+ va_end (ap);
}
+#if 0
+
void
-dw2_asm_output_delta_sleb128 VPARAMS ((const char *lab1 ATTRIBUTE_UNUSED,
- const char *lab2 ATTRIBUTE_UNUSED,
- const char *comment, ...))
+dw2_asm_output_delta_sleb128 (const char *lab1 ATTRIBUTE_UNUSED,
+ const char *lab2 ATTRIBUTE_UNUSED,
+ const char *comment, ...)
{
- VA_OPEN (ap, comment);
- VA_FIXEDARG (ap, const char *, lab1);
- VA_FIXEDARG (ap, const char *, lab2);
- VA_FIXEDARG (ap, const char *, comment);
+ va_list ap;
+
+ va_start (ap, comment);
#ifdef HAVE_AS_LEB128
fputs ("\t.sleb128 ", asm_out_file);
fputc ('-', asm_out_file);
assemble_name (asm_out_file, lab2);
#else
- abort ();
+ gcc_unreachable ();
#endif
if (flag_debug_asm && comment)
}
fputc ('\n', asm_out_file);
- VA_CLOSE (ap);
+ va_end (ap);
}
+#endif /* 0 */
\f
-static rtx dw2_force_const_mem PARAMS ((rtx));
-static int dw2_output_indirect_constant_1 PARAMS ((splay_tree_node, void *));
+static int dw2_output_indirect_constant_1 (splay_tree_node, void *);
+
+static GTY((param1_is (char *), param2_is (tree))) splay_tree indirect_pool;
-static splay_tree indirect_pool;
+static GTY(()) int dw2_const_labelno;
+
+#if defined(HAVE_GAS_HIDDEN) && defined(SUPPORTS_ONE_ONLY)
+# define USE_LINKONCE_INDIRECT 1
+#else
+# define USE_LINKONCE_INDIRECT 0
+#endif
+
+/* Comparison function for a splay tree in which the keys are strings.
+ K1 and K2 have the dynamic type "const char *". Returns <0, 0, or
+ >0 to indicate whether K1 is less than, equal to, or greater than
+ K2, respectively. */
+
+static int
+splay_tree_compare_strings (splay_tree_key k1, splay_tree_key k2)
+{
+ const char *s1 = (const char *)k1;
+ const char *s2 = (const char *)k2;
+ int ret;
+
+ if (s1 == s2)
+ return 0;
+
+ ret = strcmp (s1, s2);
+
+ /* The strings are always those from IDENTIFIER_NODEs, and,
+ therefore, we should never have two copies of the same
+ string. */
+ gcc_assert (ret);
+
+ return ret;
+}
/* Put X, a SYMBOL_REF, in memory. Return a SYMBOL_REF to the allocated
memory. Differs from force_const_mem in that a single pool is used for
the entire unit of translation, and the memory is not guaranteed to be
- "near" the function in any interesting sense. */
+ "near" the function in any interesting sense. IS_PUBLIC controls whether
+ the symbol can be shared across the entire application (or DSO). */
-static rtx
-dw2_force_const_mem (x)
- rtx x;
+rtx
+dw2_force_const_mem (rtx x, bool is_public)
{
splay_tree_node node;
- const char *const_sym;
+ const char *key;
+ tree decl_id;
if (! indirect_pool)
- indirect_pool = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
+ /* We use strcmp, rather than just comparing pointers, so that the
+ sort order will not depend on the host system. */
+ indirect_pool = splay_tree_new_ggc (splay_tree_compare_strings);
- if (GET_CODE (x) != SYMBOL_REF)
- abort ();
- node = splay_tree_lookup (indirect_pool, (splay_tree_key) XSTR (x, 0));
+ gcc_assert (GET_CODE (x) == SYMBOL_REF);
+
+ key = XSTR (x, 0);
+ node = splay_tree_lookup (indirect_pool, (splay_tree_key) key);
if (node)
- const_sym = (const char *) node->value;
+ decl_id = (tree) node->value;
else
{
- extern int const_labelno;
- char label[32];
tree id;
+ const char *str = targetm.strip_name_encoding (key);
- ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
- ++const_labelno;
- const_sym = ggc_strdup (label);
+ if (is_public && USE_LINKONCE_INDIRECT)
+ {
+ char *ref_name = XALLOCAVEC (char, strlen (str) + sizeof "DW.ref.");
- id = maybe_get_identifier (XSTR (x, 0));
+ sprintf (ref_name, "DW.ref.%s", str);
+ gcc_assert (!maybe_get_identifier (ref_name));
+ decl_id = get_identifier (ref_name);
+ TREE_PUBLIC (decl_id) = 1;
+ }
+ else
+ {
+ char label[32];
+
+ ASM_GENERATE_INTERNAL_LABEL (label, "LDFCM", dw2_const_labelno);
+ ++dw2_const_labelno;
+ gcc_assert (!maybe_get_identifier (label));
+ decl_id = get_identifier (label);
+ }
+
+ id = maybe_get_identifier (str);
if (id)
TREE_SYMBOL_REFERENCED (id) = 1;
- splay_tree_insert (indirect_pool, (splay_tree_key) XSTR (x, 0),
- (splay_tree_value) const_sym);
+ splay_tree_insert (indirect_pool, (splay_tree_key) key,
+ (splay_tree_value) decl_id);
}
- return gen_rtx_SYMBOL_REF (Pmode, const_sym);
+ return gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (decl_id));
}
/* A helper function for dw2_output_indirect_constants called through
splay_tree_foreach. Emit one queued constant to memory. */
static int
-dw2_output_indirect_constant_1 (node, data)
- splay_tree_node node;
- void* data ATTRIBUTE_UNUSED;
+dw2_output_indirect_constant_1 (splay_tree_node node,
+ void *data ATTRIBUTE_UNUSED)
{
- const char *label, *sym;
+ const char *sym;
rtx sym_ref;
+ tree id, decl;
- label = (const char *) node->value;
sym = (const char *) node->key;
- sym_ref = gen_rtx_SYMBOL_REF (Pmode, sym);
+ id = (tree) node->value;
+
+ decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, id, ptr_type_node);
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ DECL_INITIAL (decl) = decl;
- ASM_OUTPUT_LABEL (asm_out_file, label);
+ if (TREE_PUBLIC (id))
+ {
+ TREE_PUBLIC (decl) = 1;
+ make_decl_one_only (decl, DECL_ASSEMBLER_NAME (decl));
+ }
+ else
+ TREE_STATIC (decl) = 1;
+
+ sym_ref = gen_rtx_SYMBOL_REF (Pmode, sym);
+ sym = targetm.strip_name_encoding (sym);
+ if (TREE_PUBLIC (decl) && USE_LINKONCE_INDIRECT)
+ fprintf (asm_out_file, "\t.hidden %sDW.ref.%s\n", user_label_prefix, sym);
+ assemble_variable (decl, 1, 1, 1);
assemble_integer (sym_ref, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
return 0;
/* Emit the constants queued through dw2_force_const_mem. */
void
-dw2_output_indirect_constants ()
+dw2_output_indirect_constants (void)
{
- if (! indirect_pool)
- return;
-
- /* Assume that the whole reason we're emitting these symbol references
- indirectly is that they contain dynamic relocations, and are thus
- read-write. If there was no possibility of a dynamic relocation, we
- might as well have used a direct relocation. */
- data_section ();
-
- /* Everything we're emitting is a pointer. Align appropriately. */
- assemble_align (POINTER_SIZE);
-
- splay_tree_foreach (indirect_pool, dw2_output_indirect_constant_1, NULL);
+ if (indirect_pool)
+ splay_tree_foreach (indirect_pool, dw2_output_indirect_constant_1, NULL);
}
-/* Like dw2_asm_output_addr_rtx, but encode the pointer as directed. */
+/* Like dw2_asm_output_addr_rtx, but encode the pointer as directed.
+ If PUBLIC is set and the encoding is DW_EH_PE_indirect, the indirect
+ reference is shared across the entire application (or DSO). */
void
-dw2_asm_output_encoded_addr_rtx VPARAMS ((int encoding,
- rtx addr,
- const char *comment, ...))
+dw2_asm_output_encoded_addr_rtx (int encoding, rtx addr, bool is_public,
+ const char *comment, ...)
{
int size;
+ va_list ap;
- VA_OPEN (ap, comment);
- VA_FIXEDARG (ap, int, encoding);
- VA_FIXEDARG (ap, rtx, addr);
- VA_FIXEDARG (ap, const char *, comment);
+ va_start (ap, comment);
size = size_of_encoded_value (encoding);
return;
}
- /* NULL is _always_ represented as a plain zero. */
- if (addr == const0_rtx)
+ /* NULL is _always_ represented as a plain zero, as is 1 for Ada's
+ "all others". */
+ if (addr == const0_rtx || addr == const1_rtx)
assemble_integer (addr, size, BITS_PER_UNIT, 1);
else
{
restart:
/* Allow the target first crack at emitting this. Some of the
- special relocations require special directives instead of
+ special relocations require special directives instead of
just ".4byte" or whatever. */
#ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX (asm_out_file, encoding, size,
/* It is very tempting to use force_const_mem so that we share data
with the normal constant pool. However, we've already emitted
the constant pool for this function. Moreover, we'd like to
- share these constants across the entire unit of translation,
- or better, across the entire application (or DSO). */
- addr = dw2_force_const_mem (addr);
+ share these constants across the entire unit of translation and
+ even, if possible, across the entire application (or DSO). */
+ addr = dw2_force_const_mem (addr, is_public);
encoding &= ~DW_EH_PE_indirect;
goto restart;
}
switch (encoding & 0xF0)
{
case DW_EH_PE_absptr:
-#ifdef UNALIGNED_INT_ASM_OP
- fputs (unaligned_integer_asm_op (size), asm_out_file);
- output_addr_const (asm_out_file, addr);
-#else
- assemble_integer (addr, size, BITS_PER_UNIT, 1);
-#endif
+ dw2_assemble_integer (size, addr);
break;
case DW_EH_PE_pcrel:
- if (GET_CODE (addr) != SYMBOL_REF)
- abort ();
+ gcc_assert (GET_CODE (addr) == SYMBOL_REF);
#ifdef ASM_OUTPUT_DWARF_PCREL
ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, XSTR (addr, 0));
#else
-#ifdef UNALIGNED_INT_ASM_OP
- fputs (unaligned_integer_asm_op (size), asm_out_file);
- assemble_name (asm_out_file, XSTR (addr, 0));
- fputc ('-', asm_out_file);
- fputc ('.', asm_out_file);
-#else
- abort ();
-#endif
+ dw2_assemble_integer (size, gen_rtx_MINUS (Pmode, addr, pc_rtx));
#endif
break;
default:
- /* Other encodings should have been handled by
+ /* Other encodings should have been handled by
ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX. */
- abort ();
+ gcc_unreachable ();
}
#ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
}
fputc ('\n', asm_out_file);
- VA_CLOSE (ap);
+ va_end (ap);
}
+
+#include "gt-dwarf2asm.h"