OSDN Git Service

2010-01-27 Matthias Klose <doko@ubuntu.com>
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2asm.c
index 5b5056c..3657d0b 100644 (file)
@@ -1,11 +1,12 @@
 /* Dwarf2 assembler output helper routines.
 /* Dwarf2 assembler output helper routines.
-   Copyright (C) 2001, 2002, 2003 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
 
 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
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -14,9 +15,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
 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 "config.h"
@@ -52,8 +52,9 @@ dw2_assemble_integer (int size, rtx x)
   if (op)
     {
       fputs (op, asm_out_file);
   if (op)
     {
       fputs (op, asm_out_file);
-      if (GET_CODE (x) == CONST_INT)
-       fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
+      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
        output_addr_const (asm_out_file, x);
     }
@@ -62,20 +63,52 @@ dw2_assemble_integer (int size, rtx x)
 }
 
 
 }
 
 
-/* Output an immediate constant in a given size.  */
+/* 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]);
+    }
+}
+
+/* Output an immediate constant in a given SIZE in bytes.  */
 
 void
 dw2_asm_output_data (int size, unsigned HOST_WIDE_INT value,
                     const char *comment, ...)
 {
   va_list ap;
 
 void
 dw2_asm_output_data (int size, unsigned HOST_WIDE_INT value,
                     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));
 
 
   va_start (ap, comment);
 
   if (size * 8 < HOST_BITS_PER_WIDE_INT)
     value &= ~(~(unsigned HOST_WIDE_INT) 0 << (size * 8));
 
-  dw2_assemble_integer (size, GEN_INT (value));
+  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)
     {
 
   if (flag_debug_asm && comment)
     {
@@ -119,14 +152,16 @@ dw2_asm_output_delta (int size, const char *lab1, const char *lab2,
   va_end (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 (int size, const char *label,
 
 void
 dw2_asm_output_offset (int size, const char *label,
+                      section *base ATTRIBUTE_UNUSED,
                       const char *comment, ...)
 {
   va_list ap;
                       const char *comment, ...)
 {
   va_list ap;
@@ -134,7 +169,7 @@ dw2_asm_output_offset (int size, const char *label,
   va_start (ap, comment);
 
 #ifdef ASM_OUTPUT_DWARF_OFFSET
   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
   dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
 #endif
 #else
   dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
 #endif
@@ -149,6 +184,8 @@ dw2_asm_output_offset (int size, const char *label,
   va_end (ap);
 }
 
   va_end (ap);
 }
 
+#if 0
+
 /* Output a self-relative reference to a label, possibly in a
    different section or object file.  */
 
 /* Output a self-relative reference to a label, possibly in a
    different section or object file.  */
 
@@ -179,6 +216,7 @@ dw2_asm_output_pcrel (int size ATTRIBUTE_UNUSED,
 
   va_end (ap);
 }
 
   va_end (ap);
 }
+#endif /* 0 */
 
 /* Output an absolute reference to a label.  */
 
 
 /* Output an absolute reference to a label.  */
 
@@ -230,7 +268,7 @@ dw2_asm_output_addr_rtx (int size, rtx addr,
    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.  */
    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 (const char *str, size_t orig_len,
                        const char *comment, ...)
 void
 dw2_asm_output_nstring (const char *str, size_t orig_len,
                        const char *comment, ...)
@@ -333,8 +371,9 @@ size_of_encoded_value (int encoding)
       return 4;
     case DW_EH_PE_udata8:
       return 8;
       return 4;
     case DW_EH_PE_udata8:
       return 8;
+    default:
+      gcc_unreachable ();
     }
     }
-  abort ();
 }
 
 /* Yield a name for a given pointer encoding.  */
 }
 
 /* Yield a name for a given pointer encoding.  */
@@ -407,6 +446,8 @@ eh_data_format_name (int format)
   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_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,
   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,
@@ -486,15 +527,35 @@ eh_data_format_name (int format)
 #if HAVE_DESIGNATED_INITIALIZERS
   };
 
 #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
   }
   return format_names[format];
 #else
   }
-  abort ();
+  gcc_unreachable ();
 #endif
 }
 
 #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
 /* Output an unsigned LEB128 quantity.  */
 
 void
@@ -556,6 +617,29 @@ dw2_asm_output_data_uleb128 (unsigned HOST_WIDE_INT value,
   va_end (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 a signed LEB128 quantity.  */
 
 void
 /* Output a signed LEB128 quantity.  */
 
 void
@@ -635,7 +719,7 @@ dw2_asm_output_delta_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
   fputc ('-', asm_out_file);
   assemble_name (asm_out_file, lab2);
 #else
   fputc ('-', asm_out_file);
   assemble_name (asm_out_file, lab2);
 #else
-  abort ();
+  gcc_unreachable ();
 #endif
 
   if (flag_debug_asm && comment)
 #endif
 
   if (flag_debug_asm && comment)
@@ -648,6 +732,8 @@ dw2_asm_output_delta_uleb128 (const char *lab1 ATTRIBUTE_UNUSED,
   va_end (ap);
 }
 
   va_end (ap);
 }
 
+#if 0
+
 void
 dw2_asm_output_delta_sleb128 (const char *lab1 ATTRIBUTE_UNUSED,
                              const char *lab2 ATTRIBUTE_UNUSED,
 void
 dw2_asm_output_delta_sleb128 (const char *lab1 ATTRIBUTE_UNUSED,
                              const char *lab2 ATTRIBUTE_UNUSED,
@@ -663,7 +749,7 @@ dw2_asm_output_delta_sleb128 (const char *lab1 ATTRIBUTE_UNUSED,
   fputc ('-', asm_out_file);
   assemble_name (asm_out_file, lab2);
 #else
   fputc ('-', asm_out_file);
   assemble_name (asm_out_file, lab2);
 #else
-  abort ();
+  gcc_unreachable ();
 #endif
 
   if (flag_debug_asm && comment)
 #endif
 
   if (flag_debug_asm && comment)
@@ -675,8 +761,8 @@ dw2_asm_output_delta_sleb128 (const char *lab1 ATTRIBUTE_UNUSED,
 
   va_end (ap);
 }
 
   va_end (ap);
 }
+#endif /* 0 */
 \f
 \f
-static rtx dw2_force_const_mem (rtx);
 static int dw2_output_indirect_constant_1 (splay_tree_node, void *);
 
 static GTY((param1_is (char *), param2_is (tree))) splay_tree indirect_pool;
 static int dw2_output_indirect_constant_1 (splay_tree_node, void *);
 
 static GTY((param1_is (char *), param2_is (tree))) splay_tree indirect_pool;
@@ -689,43 +775,68 @@ static GTY(()) int dw2_const_labelno;
 # define USE_LINKONCE_INDIRECT 0
 #endif
 
 # 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
 /* 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 (rtx x)
+rtx
+dw2_force_const_mem (rtx x, bool is_public)
 {
   splay_tree_node node;
 {
   splay_tree_node node;
-  const char *str;
-  tree decl;
+  const char *key;
+  tree decl_id;
 
   if (! indirect_pool)
 
   if (! indirect_pool)
-    indirect_pool = splay_tree_new_ggc (splay_tree_compare_pointers);
+    /* 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 ();
+  gcc_assert (GET_CODE (x) == SYMBOL_REF);
 
 
-  str = (* targetm.strip_name_encoding) (XSTR (x, 0));
-  node = splay_tree_lookup (indirect_pool, (splay_tree_key) str);
+  key = XSTR (x, 0);
+  node = splay_tree_lookup (indirect_pool, (splay_tree_key) key);
   if (node)
   if (node)
-    decl = (tree) node->value;
+    decl_id = (tree) node->value;
   else
     {
       tree id;
   else
     {
       tree id;
+      const char *str = targetm.strip_name_encoding (key);
 
 
-      if (USE_LINKONCE_INDIRECT)
+      if (is_public && USE_LINKONCE_INDIRECT)
        {
        {
-         char *ref_name = alloca (strlen (str) + sizeof "DW.ref.");
+         char *ref_name = XALLOCAVEC (char, strlen (str) + sizeof "DW.ref.");
 
          sprintf (ref_name, "DW.ref.%s", str);
 
          sprintf (ref_name, "DW.ref.%s", str);
-         id = get_identifier (ref_name);
-         decl = build_decl (VAR_DECL, id, ptr_type_node);
-         DECL_ARTIFICIAL (decl) = 1;
-         TREE_PUBLIC (decl) = 1;
-         DECL_INITIAL (decl) = decl;
-         make_decl_one_only (decl);
+         gcc_assert (!maybe_get_identifier (ref_name));
+         decl_id = get_identifier (ref_name);
+         TREE_PUBLIC (decl_id) = 1;
        }
       else
        {
        }
       else
        {
@@ -733,22 +844,19 @@ dw2_force_const_mem (rtx x)
 
          ASM_GENERATE_INTERNAL_LABEL (label, "LDFCM", dw2_const_labelno);
          ++dw2_const_labelno;
 
          ASM_GENERATE_INTERNAL_LABEL (label, "LDFCM", dw2_const_labelno);
          ++dw2_const_labelno;
-         id = get_identifier (label);
-         decl = build_decl (VAR_DECL, id, ptr_type_node);
-         DECL_ARTIFICIAL (decl) = 1;
-         TREE_STATIC (decl) = 1;
-         DECL_INITIAL (decl) = decl;
+         gcc_assert (!maybe_get_identifier (label));
+         decl_id = get_identifier (label);
        }
 
       id = maybe_get_identifier (str);
       if (id)
        TREE_SYMBOL_REFERENCED (id) = 1;
 
        }
 
       id = maybe_get_identifier (str);
       if (id)
        TREE_SYMBOL_REFERENCED (id) = 1;
 
-      splay_tree_insert (indirect_pool, (splay_tree_key) str,
-                        (splay_tree_value) decl);
+      splay_tree_insert (indirect_pool, (splay_tree_key) key,
+                        (splay_tree_value) decl_id);
     }
 
     }
 
-  return XEXP (DECL_RTL (decl), 0);
+  return gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (decl_id));
 }
 
 /* A helper function for dw2_output_indirect_constants called through
 }
 
 /* A helper function for dw2_output_indirect_constants called through
@@ -760,12 +868,29 @@ dw2_output_indirect_constant_1 (splay_tree_node node,
 {
   const char *sym;
   rtx sym_ref;
 {
   const char *sym;
   rtx sym_ref;
+  tree id, decl;
 
   sym = (const char *) node->key;
 
   sym = (const char *) node->key;
+  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;
+
+  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_ref = gen_rtx_SYMBOL_REF (Pmode, sym);
-  if (USE_LINKONCE_INDIRECT)
+  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);
     fprintf (asm_out_file, "\t.hidden %sDW.ref.%s\n", user_label_prefix, sym);
-  assemble_variable ((tree) node->value, 1, 1, 1);
+  assemble_variable (decl, 1, 1, 1);
   assemble_integer (sym_ref, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
 
   return 0;
   assemble_integer (sym_ref, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
 
   return 0;
@@ -780,10 +905,12 @@ dw2_output_indirect_constants (void)
     splay_tree_foreach (indirect_pool, dw2_output_indirect_constant_1, NULL);
 }
 
     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
 
 void
-dw2_asm_output_encoded_addr_rtx (int encoding, rtx addr,
+dw2_asm_output_encoded_addr_rtx (int encoding, rtx addr, bool is_public,
                                 const char *comment, ...)
 {
   int size;
                                 const char *comment, ...)
 {
   int size;
@@ -822,9 +949,9 @@ dw2_asm_output_encoded_addr_rtx (int encoding, rtx addr,
          /* 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
          /* 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;
        }
          encoding &= ~DW_EH_PE_indirect;
          goto restart;
        }
@@ -836,8 +963,7 @@ dw2_asm_output_encoded_addr_rtx (int encoding, rtx addr,
          break;
 
        case DW_EH_PE_pcrel:
          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 ASM_OUTPUT_DWARF_PCREL
          ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, XSTR (addr, 0));
 #else
@@ -848,7 +974,7 @@ dw2_asm_output_encoded_addr_rtx (int encoding, rtx addr,
        default:
          /* Other encodings should have been handled by
             ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX.  */
        default:
          /* Other encodings should have been handled by
             ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX.  */
-         abort ();
+         gcc_unreachable ();
        }
 
 #ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
        }
 
 #ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX