OSDN Git Service

* builtins.c (dummy_object): Use build_int_cst instead of convert.
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index 8192a7a..2d8a6bf 100644 (file)
@@ -1,6 +1,6 @@
 /* Output variables, constants and external declarations, for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -17,8 +17,8 @@ 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.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 
 /* This file handles generation of all the assembler code
@@ -60,6 +60,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #endif
 
 /* The (assembler) name of the first globally-visible object output.  */
+extern GTY(()) const char *first_global_object_name;
+extern GTY(()) const char *weak_global_object_name;
+
 const char *first_global_object_name;
 const char *weak_global_object_name;
 
@@ -124,9 +127,6 @@ static unsigned min_align (unsigned, unsigned);
 static void output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int);
 static void globalize_decl (tree);
 static void maybe_assemble_visibility (tree);
-static int in_named_entry_eq (const void *, const void *);
-static hashval_t in_named_entry_hash (const void *);
-static void initialize_cold_section_name (void);
 #ifdef BSS_SECTION_ASM_OP
 #ifdef ASM_OUTPUT_BSS
 static void asm_output_bss (FILE *, tree, const char *,
@@ -138,13 +138,48 @@ static void asm_output_aligned_bss (FILE *, tree, const char *,
      ATTRIBUTE_UNUSED;
 #endif
 #endif /* BSS_SECTION_ASM_OP */
-static bool asm_emit_uninitialised (tree, const char*,
-                                   unsigned HOST_WIDE_INT,
-                                   unsigned HOST_WIDE_INT);
 static void mark_weak (tree);
+static void output_constant_pool (const char *, tree);
 \f
-static GTY(()) enum in_section in_section = no_section;
-enum in_section last_text_section;
+/* Well-known sections, each one associated with some sort of *_ASM_OP.  */
+section *text_section;
+section *data_section;
+section *readonly_data_section;
+section *sdata_section;
+section *ctors_section;
+section *dtors_section;
+section *bss_section;
+section *sbss_section;
+
+/* Various forms of common section.  All are guaranteed to be nonnull.  */
+section *tls_comm_section;
+section *comm_section;
+section *lcomm_section;
+
+/* A SECTION_NOSWITCH section used for declaring global BSS variables.
+   May be null.  */
+section *bss_noswitch_section;
+
+/* The section that holds the main exception table, when known.  The section
+   is set either by the target's init_sections hook or by the first call to
+   switch_to_exception_section.  */
+section *exception_section;
+
+/* The section that holds the DWARF2 frame unwind information, when known.
+   The section is set either by the target's init_sections hook or by the
+   first call to switch_to_eh_frame_section.  */
+section *eh_frame_section;
+
+/* asm_out_file's current section.  This is NULL if no section has yet
+   been selected or if we lose track of what the current section is.  */
+section *in_section;
+
+/* True if code for the current function is currently being directed
+   at the cold section.  */
+bool in_cold_section_p;
+
+/* A linked list of all the unnamed sections.  */
+static GTY(()) section *unnamed_sections;
 
 /* Return a nonzero value if DECL has a section attribute.  */
 #ifndef IN_NAMED_SECTION
@@ -153,293 +188,268 @@ enum in_section last_text_section;
    && DECL_SECTION_NAME (DECL) != NULL_TREE)
 #endif
 
-/* Text of section name when in_section == in_named.  */
-static GTY(()) const char *in_named_name;
-const char *last_text_section_name;
+/* Hash table of named sections.  */
+static GTY((param_is (section))) htab_t section_htab;
 
-/* Hash table of flags that have been used for a particular named section.  */
+/* A table of object_blocks, indexed by section.  */
+static GTY((param_is (struct object_block))) htab_t object_block_htab;
 
-struct in_named_entry GTY(())
-{
-  const char *name;
-  unsigned int flags;
-  bool declared;
-};
+/* The next number to use for internal anchor labels.  */
+static GTY(()) int anchor_labelno;
 
-static GTY((param_is (struct in_named_entry))) htab_t in_named_htab;
+/* A pool of constants that can be shared between functions.  */
+static GTY(()) struct rtx_constant_pool *shared_constant_pool;
 
-/* Define functions like text_section for any extra sections.  */
-#ifdef EXTRA_SECTION_FUNCTIONS
-EXTRA_SECTION_FUNCTIONS
-#endif
+/* Helper routines for maintaining section_htab.  */
 
-static void
-initialize_cold_section_name (void)
+static int
+section_entry_eq (const void *p1, const void *p2)
 {
-  const char *name;
-  const char *stripped_name;
-  char *buffer;
+  const section *old = p1;
+  const char *new = p2;
 
-  gcc_assert (cfun && current_function_decl);
-  if (cfun->unlikely_text_section_name)
-    return;
+  return strcmp (old->named.name, new) == 0;
+}
 
-  if (flag_function_sections && DECL_SECTION_NAME (current_function_decl))
-    {
-      name = alloca (TREE_STRING_LENGTH (DECL_SECTION_NAME
-                                        (current_function_decl)));
-      strcpy ((char *) name, TREE_STRING_POINTER (DECL_SECTION_NAME 
-                                        (current_function_decl)));
-      stripped_name = targetm.strip_name_encoding (name);
-      buffer = ACONCAT ((stripped_name, "_unlikely", NULL));
-      cfun->unlikely_text_section_name = ggc_strdup (buffer);
-    }
-  else
-    cfun->unlikely_text_section_name =  UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
+static hashval_t
+section_entry_hash (const void *p)
+{
+  const section *old = p;
+  return htab_hash_string (old->named.name);
 }
 
-/* Tell assembler to switch to text section.  */
+/* Return a hash value for section SECT.  */
 
-void
-text_section (void)
+static hashval_t
+hash_section (section *sect)
 {
-  if (in_section != in_text)
-    {
-      in_section = in_text;
-      last_text_section = in_text;
-      fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
-    }
+  if (sect->common.flags & SECTION_NAMED)
+    return htab_hash_string (sect->named.name);
+  return sect->common.flags;
 }
 
-/* Tell assembler to switch to unlikely-to-be-executed text section.  */
+/* Helper routines for maintaining object_block_htab.  */
 
-void
-unlikely_text_section (void)
+static int
+object_block_entry_eq (const void *p1, const void *p2)
 {
-  if (cfun)
-    {
-      if (!cfun->unlikely_text_section_name)
-       initialize_cold_section_name ();
+  const struct object_block *old = p1;
+  const section *new = p2;
 
-      if (flag_function_sections
-         || ((in_section != in_unlikely_executed_text)
-             &&  (in_section != in_named 
-                  || (strcmp (in_named_name, cfun->unlikely_text_section_name) 
-                      != 0))))
-       {
-         named_section (NULL_TREE, cfun->unlikely_text_section_name, 0);
-         in_section = in_unlikely_executed_text;
-         last_text_section = in_unlikely_executed_text;
-       }
-    }
-  else
-    {
-      named_section (NULL_TREE, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
-      in_section = in_unlikely_executed_text;
-      last_text_section = in_unlikely_executed_text;
-    }
+  return old->sect == new;
 }
 
-/* Tell assembler to switch to data section.  */
-
-void
-data_section (void)
+static hashval_t
+object_block_entry_hash (const void *p)
 {
-  if (in_section != in_data)
-    {
-      in_section = in_data;
-      fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
-    }
+  const struct object_block *old = p;
+  return hash_section (old->sect);
 }
 
-/* Tell assembler to switch to read-only data section.  This is normally
-   the text section.  */
+/* Return a new unnamed section with the given fields.  */
 
-void
-readonly_data_section (void)
+section *
+get_unnamed_section (unsigned int flags, void (*callback) (const void *),
+                    const void *data)
 {
-#ifdef READONLY_DATA_SECTION
-  READONLY_DATA_SECTION ();  /* Note this can call data_section.  */
-#else
-#ifdef READONLY_DATA_SECTION_ASM_OP
-  if (in_section != in_readonly_data)
-    {
-      in_section = in_readonly_data;
-      fputs (READONLY_DATA_SECTION_ASM_OP, asm_out_file);
-      fputc ('\n', asm_out_file);
-    }
-#else
-  text_section ();
-#endif
-#endif
+  section *sect;
+
+  sect = ggc_alloc (sizeof (struct unnamed_section));
+  sect->unnamed.common.flags = flags | SECTION_UNNAMED;
+  sect->unnamed.callback = callback;
+  sect->unnamed.data = data;
+  sect->unnamed.next = unnamed_sections;
+
+  unnamed_sections = sect;
+  return sect;
 }
 
-/* Determine if we're in the text section.  */
+/* Return a SECTION_NOSWITCH section with the given fields.  */
 
-int
-in_text_section (void)
+static section *
+get_noswitch_section (unsigned int flags, noswitch_section_callback callback)
 {
-  return in_section == in_text;
+  section *sect;
+
+  sect = ggc_alloc (sizeof (struct unnamed_section));
+  sect->noswitch.common.flags = flags | SECTION_NOSWITCH;
+  sect->noswitch.callback = callback;
+
+  return sect;
 }
 
-/* Determine if we're in the unlikely-to-be-executed text section.  */
+/* Return the named section structure associated with NAME.  Create
+   a new section with the given fields if no such structure exists.  */
 
-int
-in_unlikely_text_section (void)
+section *
+get_section (const char *name, unsigned int flags, tree decl)
 {
-  bool ret_val;
+  section *sect, **slot;
 
-  if (cfun)
+  slot = (section **)
+    htab_find_slot_with_hash (section_htab, name,
+                             htab_hash_string (name), INSERT);
+  flags |= SECTION_NAMED;
+  if (*slot == NULL)
     {
-      ret_val = ((in_section == in_unlikely_executed_text)
-                || (in_section == in_named
-                    && cfun->unlikely_text_section_name
-                    && strcmp (in_named_name, 
-                               cfun->unlikely_text_section_name) == 0));
+      sect = ggc_alloc (sizeof (struct named_section));
+      sect->named.common.flags = flags;
+      sect->named.name = ggc_strdup (name);
+      sect->named.decl = decl;
+      *slot = sect;
     }
   else
     {
-      ret_val = ((in_section == in_unlikely_executed_text)
-                || (in_section == in_named
-                    && strcmp (in_named_name,
-                               UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0));
+      sect = *slot;
+      if ((sect->common.flags & ~SECTION_DECLARED) != flags
+         && ((sect->common.flags | flags) & SECTION_OVERRIDE) == 0)
+       {
+         /* Sanity check user variables for flag changes.  */
+         if (decl == 0)
+           decl = sect->named.decl;
+         gcc_assert (decl);
+         error ("%+D causes a section type conflict", decl);
+       }
     }
-
-  return ret_val;
+  return sect;
 }
 
-/* Determine if we're in the data section.  */
+/* Return true if the current compilation mode benefits from having
+   objects grouped into blocks.  */
 
-int
-in_data_section (void)
+static bool
+use_object_blocks_p (void)
 {
-  return in_section == in_data;
+  return flag_section_anchors;
 }
 
-/* Helper routines for maintaining in_named_htab.  */
+/* Return the object_block structure for section SECT.  Create a new
+   structure if we haven't created one already.  Return null if SECT
+   itself is null.  */
 
-static int
-in_named_entry_eq (const void *p1, const void *p2)
+static struct object_block *
+get_block_for_section (section *sect)
 {
-  const struct in_named_entry *old = p1;
-  const char *new = p2;
+  struct object_block *block;
+  void **slot;
 
-  return strcmp (old->name, new) == 0;
-}
+  if (sect == NULL)
+    return NULL;
 
-static hashval_t
-in_named_entry_hash (const void *p)
-{
-  const struct in_named_entry *old = p;
-  return htab_hash_string (old->name);
+  slot = htab_find_slot_with_hash (object_block_htab, sect,
+                                  hash_section (sect), INSERT);
+  block = (struct object_block *) *slot;
+  if (block == NULL)
+    {
+      block = (struct object_block *)
+       ggc_alloc_cleared (sizeof (struct object_block));
+      block->sect = sect;
+      *slot = block;
+    }
+  return block;
 }
 
-/* If SECTION has been seen before as a named section, return the flags
-   that were used.  Otherwise, return 0.  Note, that 0 is a perfectly valid
-   set of flags for a section to have, so 0 does not mean that the section
-   has not been seen.  */
+/* Create a symbol with label LABEL and place it at byte offset
+   OFFSET in BLOCK.  OFFSET can be negative if the symbol's offset
+   is not yet known.  LABEL must be a garbage-collected string.  */
 
-static unsigned int
-get_named_section_flags (const char *section)
+static rtx
+create_block_symbol (const char *label, struct object_block *block,
+                    HOST_WIDE_INT offset)
 {
-  struct in_named_entry **slot;
+  rtx symbol;
+  unsigned int size;
 
-  slot = (struct in_named_entry **)
-    htab_find_slot_with_hash (in_named_htab, section,
-                             htab_hash_string (section), NO_INSERT);
+  /* Create the extended SYMBOL_REF.  */
+  size = RTX_HDR_SIZE + sizeof (struct block_symbol);
+  symbol = ggc_alloc_zone (size, &rtl_zone);
 
-  return slot ? (*slot)->flags : 0;
-}
+  /* Initialize the normal SYMBOL_REF fields.  */
+  memset (symbol, 0, size);
+  PUT_CODE (symbol, SYMBOL_REF);
+  PUT_MODE (symbol, Pmode);
+  XSTR (symbol, 0) = label;
+  SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_HAS_BLOCK_INFO;
 
-/* Returns true if the section has been declared before.   Sets internal
-   flag on this section in in_named_hash so subsequent calls on this
-   section will return false.  */
+  /* Initialize the block_symbol stuff.  */
+  SYMBOL_REF_BLOCK (symbol) = block;
+  SYMBOL_REF_BLOCK_OFFSET (symbol) = offset;
 
-bool
-named_section_first_declaration (const char *name)
+  return symbol;
+}
+
+static void
+initialize_cold_section_name (void)
 {
-  struct in_named_entry **slot;
+  const char *stripped_name;
+  char *name, *buffer;
+  tree dsn;
 
-  slot = (struct in_named_entry **)
-    htab_find_slot_with_hash (in_named_htab, name,
-                             htab_hash_string (name), NO_INSERT);
-  if (! (*slot)->declared)
+  gcc_assert (cfun && current_function_decl);
+  if (cfun->unlikely_text_section_name)
+    return;
+
+  dsn = DECL_SECTION_NAME (current_function_decl);
+  if (flag_function_sections && dsn)
     {
-      (*slot)->declared = true;
-      return true;
+      name = alloca (TREE_STRING_LENGTH (dsn) + 1);
+      memcpy (name, TREE_STRING_POINTER (dsn), TREE_STRING_LENGTH (dsn) + 1);
+
+      stripped_name = targetm.strip_name_encoding (name);
+
+      buffer = ACONCAT ((stripped_name, "_unlikely", NULL));
+      cfun->unlikely_text_section_name = ggc_strdup (buffer);
     }
   else
-    {
-      return false;
-    }
+    cfun->unlikely_text_section_name =  UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
 }
 
+/* Tell assembler to switch to unlikely-to-be-executed text section.  */
 
-/* Record FLAGS for SECTION.  If SECTION was previously recorded with a
-   different set of flags, return false.  */
-
-bool
-set_named_section_flags (const char *section, unsigned int flags)
+section *
+unlikely_text_section (void)
 {
-  struct in_named_entry **slot, *entry;
-
-  slot = (struct in_named_entry **)
-    htab_find_slot_with_hash (in_named_htab, section,
-                             htab_hash_string (section), INSERT);
-  entry = *slot;
-
-  if (!entry)
+  if (cfun)
     {
-      entry = ggc_alloc (sizeof (*entry));
-      *slot = entry;
-      entry->name = ggc_strdup (section);
-      entry->flags = flags;
-      entry->declared = false;
-    }
-  else if (entry->flags != flags)
-    return false;
+      if (!cfun->unlikely_text_section_name)
+       initialize_cold_section_name ();
 
-  return true;
+      return get_named_section (NULL, cfun->unlikely_text_section_name, 0);
+    }
+  else
+    return get_named_section (NULL, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
 }
 
-/* Tell assembler to change to section NAME with attributes FLAGS.  If
-   DECL is non-NULL, it is the VAR_DECL or FUNCTION_DECL with which
-   this section is associated.  */
+/* When called within a function context, return true if the function
+   has been assigned a cold text section and if SECT is that section.
+   When called outside a function context, return true if SECT is the
+   default cold section.  */
 
-void
-named_section_real (const char *name, unsigned int flags, tree decl)
+bool
+unlikely_text_section_p (section *sect)
 {
-  if (in_section != in_named || strcmp (name, in_named_name) != 0)
-    {
-      bool unchanged = set_named_section_flags (name, flags);
-
-      gcc_assert (unchanged);
-
-      targetm.asm_out.named_section (name, flags, decl);
+  const char *name;
 
-      if (flags & SECTION_FORGET)
-       in_section = no_section;
-      else
-       {
-         in_named_name = ggc_strdup (name);
-         in_section = in_named;
-       }
-    }
+  if (cfun)
+    name = cfun->unlikely_text_section_name;
+  else
+    name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
 
-  if (in_text_section () || in_unlikely_text_section ())
-    {
-      last_text_section = in_section;
-      last_text_section_name = name;
-    }
+  return (name
+         && sect
+         && SECTION_STYLE (sect) == SECTION_NAMED
+         && strcmp (name, sect->named.name) == 0);
 }
 
-/* Tell assembler to change to section NAME for DECL.
-   If DECL is NULL, just switch to section NAME.
-   If NAME is NULL, get the name from DECL.
-   If RELOC is 1, the initializer for DECL contains relocs.  */
+/* Return a section with a particular name and with whatever SECTION_*
+   flags section_type_flags deems appropriate.  The name of the section
+   is taken from NAME if nonnull, otherwise it is taken from DECL's
+   DECL_SECTION_NAME.  DECL is the decl associated with the section
+   (see the section comment for details) and RELOC is as for
+   section_type_flags.  */
 
-void
-named_section (tree decl, const char *name, int reloc)
+section *
+get_named_section (tree decl, const char *name, int reloc)
 {
   unsigned int flags;
 
@@ -447,26 +457,9 @@ named_section (tree decl, const char *name, int reloc)
   if (name == NULL)
     name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
 
-  if (strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0
-      && cfun
-      && ! cfun->unlikely_text_section_name)
-    cfun->unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
-
   flags = targetm.section_type_flags (decl, name, reloc);
 
-  /* Sanity check user variables for flag changes.  Non-user
-     section flag changes will die in named_section_flags.
-     However, don't complain if SECTION_OVERRIDE is set.
-     We trust that the setter knows that it is safe to ignore
-     the default flags for this decl.  */
-  if (decl && ! set_named_section_flags (name, flags))
-    {
-      flags = get_named_section_flags (name);
-      if ((flags & SECTION_OVERRIDE) == 0)
-       error ("%J%D causes a section type conflict", decl, decl);
-    }
-
-  named_section_real (name, flags, decl);
+  return get_section (name, flags, decl);
 }
 
 /* If required, set DECL_SECTION_NAME to a unique name.  */
@@ -484,18 +477,6 @@ resolve_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED,
 
 #ifdef BSS_SECTION_ASM_OP
 
-/* Tell the assembler to switch to the bss section.  */
-
-void
-bss_section (void)
-{
-  if (in_section != in_bss)
-    {
-      fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP);
-      in_section = in_bss;
-    }
-}
-
 #ifdef ASM_OUTPUT_BSS
 
 /* Utility function for ASM_OUTPUT_BSS for targets to use if
@@ -510,7 +491,7 @@ asm_output_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
                unsigned HOST_WIDE_INT rounded)
 {
   targetm.asm_out.globalize_label (file, name);
-  bss_section ();
+  switch_to_section (bss_section);
 #ifdef ASM_DECLARE_OBJECT_NAME
   last_assemble_variable_decl = decl;
   ASM_DECLARE_OBJECT_NAME (file, name, decl);
@@ -535,7 +516,7 @@ asm_output_aligned_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
                        const char *name, unsigned HOST_WIDE_INT size,
                        int align)
 {
-  bss_section ();
+  switch_to_section (bss_section);
   ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
 #ifdef ASM_DECLARE_OBJECT_NAME
   last_assemble_variable_decl = decl;
@@ -551,58 +532,70 @@ asm_output_aligned_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
 
 #endif /* BSS_SECTION_ASM_OP */
 
-/* Switch to the section for function DECL.
+#ifndef USE_SELECT_SECTION_FOR_FUNCTIONS
+/* Return the hot section for function DECL.  Return text_section for
+   null DECLs.  */
+
+static section *
+hot_function_section (tree decl)
+{
+  if (decl != NULL_TREE
+      && DECL_SECTION_NAME (decl) != NULL_TREE
+      && targetm.have_named_sections)
+    return get_named_section (decl, NULL, 0);
+  else
+    return text_section;
+}
+#endif
+
+/* Return the section for function DECL.
 
-   If DECL is NULL_TREE, switch to the text section.  We can be passed
+   If DECL is NULL_TREE, return the text section.  We can be passed
    NULL_TREE under some circumstances by dbxout.c at least.  */
 
-void
+section *
 function_section (tree decl)
 {
   int reloc = 0;
-    
+
   if (first_function_block_is_cold)
     reloc = 1;
-  
+
 #ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
-  targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
-#else
   if (decl != NULL_TREE
-      && DECL_SECTION_NAME (decl) != NULL_TREE
-      && targetm.have_named_sections)
-    named_section (decl, (char *) 0, 0);
+      && DECL_SECTION_NAME (decl) != NULL_TREE)
+    return reloc ? unlikely_text_section ()
+                : get_named_section (decl, NULL, 0);
   else
-    text_section ();
+    return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+#else
+  return reloc ? unlikely_text_section () : hot_function_section (decl);
 #endif
 }
 
-void
-current_function_section (tree decl)
+section *
+current_function_section (void)
 {
 #ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
-  int reloc = 0; 
-
-  if (in_unlikely_text_section () 
-      || last_text_section == in_unlikely_executed_text)
-    reloc = 1;
-  targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
-#else
-  if (last_text_section == in_unlikely_executed_text)
-    unlikely_text_section ();
-  else if (last_text_section == in_text)
-    text_section ();
-  else if (last_text_section == in_named
-          && targetm.have_named_sections)
-    named_section (NULL_TREE, last_text_section_name, 0);
+  if (current_function_decl != NULL_TREE
+      && DECL_SECTION_NAME (current_function_decl) != NULL_TREE)
+    return in_cold_section_p ? unlikely_text_section ()
+                            : get_named_section (current_function_decl,
+                                                 NULL, 0);
   else
-    function_section (decl);
+    return targetm.asm_out.select_section (current_function_decl,
+                                          in_cold_section_p,
+                                          DECL_ALIGN (current_function_decl));
+#else
+  return (in_cold_section_p
+         ? unlikely_text_section ()
+         : hot_function_section (current_function_decl));
 #endif
 }
 
-/* Switch to read-only data section associated with function DECL.  */
+/* Return the read-only data section associated with function DECL.  */
 
-void
+section *
 default_function_rodata_section (tree decl)
 {
   if (decl != NULL_TREE && DECL_SECTION_NAME (decl))
@@ -613,11 +606,10 @@ default_function_rodata_section (tree decl)
         {
          size_t len = strlen (name) + 3;
          char* rname = alloca (len);
-         
+
          strcpy (rname, ".rodata");
-         strcat (rname, name + 5); 
-          named_section_real (rname, SECTION_LINKONCE, decl);
-         return;
+         strcat (rname, name + 5);
+         return get_section (rname, SECTION_LINKONCE, decl);
        }
       /* For .gnu.linkonce.t.foo we want to use .gnu.linkonce.r.foo.  */
       else if (DECL_ONE_ONLY (decl)
@@ -628,8 +620,7 @@ default_function_rodata_section (tree decl)
 
          memcpy (rname, name, len);
          rname[14] = 'r';
-         named_section_real (rname, SECTION_LINKONCE, decl);
-         return;
+         return get_section (rname, SECTION_LINKONCE, decl);
        }
       /* For .text.foo we want to use .rodata.foo.  */
       else if (flag_function_sections && flag_data_sections
@@ -640,39 +631,26 @@ default_function_rodata_section (tree decl)
 
          memcpy (rname, ".rodata", 7);
          memcpy (rname + 7, name + 5, len - 5);
-         named_section_flags (rname, 0);
-         return;
+         return get_section (rname, 0, decl);
        }
     }
 
-  readonly_data_section ();
+  return readonly_data_section;
 }
 
-/* Switch to read-only data section associated with function DECL
+/* Return the read-only data section associated with function DECL
    for targets where that section should be always the single
    readonly data section.  */
 
-void
+section *
 default_no_function_rodata_section (tree decl ATTRIBUTE_UNUSED)
 {
-  readonly_data_section ();
-}
-
-/* Switch to section for variable DECL.  RELOC is the same as the
-   argument to SELECT_SECTION.  */
-
-void
-variable_section (tree decl, int reloc)
-{
-  if (IN_NAMED_SECTION (decl))
-    named_section (decl, NULL, reloc);
-  else
-    targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+  return readonly_data_section;
 }
 
-/* Tell assembler to switch to the section for string merging.  */
+/* Return the section to use for string merging.  */
 
-void
+static section *
 mergeable_string_section (tree decl ATTRIBUTE_UNUSED,
                          unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,
                          unsigned int flags ATTRIBUTE_UNUSED)
@@ -715,37 +693,17 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED,
              sprintf (name, ".rodata.str%d.%d", modesize / 8,
                       (int) (align / 8));
              flags |= (modesize / 8) | SECTION_MERGE | SECTION_STRINGS;
-             if (!i && modesize < align)
-               {
-                 /* A "" string with requested alignment greater than
-                    character size might cause a problem:
-                    if some other string required even bigger
-                    alignment than "", then linker might think the
-                    "" is just part of padding after some other string
-                    and not put it into the hash table initially.
-                    But this means "" could have smaller alignment
-                    than requested.  */
-#ifdef ASM_OUTPUT_SECTION_START
-                 named_section_flags (name, flags);
-                 ASM_OUTPUT_SECTION_START (asm_out_file);
-#else
-                 readonly_data_section ();
-#endif
-                 return;
-               }
-
-             named_section_flags (name, flags);
-             return;
+             return get_section (name, flags, NULL);
            }
        }
     }
 
-  readonly_data_section ();
+  return readonly_data_section;
 }
 
-/* Tell assembler to switch to the section for constant merging.  */
+/* Return the section to use for constant merging.  */
 
-void
+section *
 mergeable_constant_section (enum machine_mode mode ATTRIBUTE_UNUSED,
                            unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,
                            unsigned int flags ATTRIBUTE_UNUSED)
@@ -764,11 +722,9 @@ mergeable_constant_section (enum machine_mode mode ATTRIBUTE_UNUSED,
 
       sprintf (name, ".rodata.cst%d", (int) (align / 8));
       flags |= (align / 8) | SECTION_MERGE;
-      named_section_flags (name, flags);
-      return;
+      return get_section (name, flags, NULL);
     }
-
-  readonly_data_section ();
+  return readonly_data_section;
 }
 \f
 /* Given NAME, a putative register name, discard any customary prefixes.  */
@@ -840,7 +796,8 @@ decode_reg_name (const char *asmspec)
          = ADDITIONAL_REGISTER_NAMES;
 
        for (i = 0; i < (int) ARRAY_SIZE (table); i++)
-         if (! strcmp (asmspec, table[i].name))
+         if (table[i].name[0]
+             && ! strcmp (asmspec, table[i].name))
            return table[i].number;
       }
 #endif /* ADDITIONAL_REGISTER_NAMES */
@@ -857,6 +814,129 @@ decode_reg_name (const char *asmspec)
   return -1;
 }
 \f
+/* Return true if DECL's initializer is suitable for a BSS section.  */
+
+static bool
+bss_initializer_p (tree decl)
+{
+  return (DECL_INITIAL (decl) == NULL
+         || DECL_INITIAL (decl) == error_mark_node
+         || (flag_zero_initialized_in_bss
+             /* Leave constant zeroes in .rodata so they
+                can be shared.  */
+             && !TREE_READONLY (decl)
+             && initializer_zerop (DECL_INITIAL (decl))));
+}
+
+/* Return the section into which the given VAR_DECL or CONST_DECL
+   should be placed.  PREFER_NOSWITCH_P is true if a noswitch
+   section should be used wherever possible.  */
+
+static section *
+get_variable_section (tree decl, bool prefer_noswitch_p)
+{
+  int reloc;
+
+  /* If the decl has been given an explicit section name, then it
+     isn't common, and shouldn't be handled as such.  */
+  if (DECL_COMMON (decl) && DECL_SECTION_NAME (decl) == NULL)
+    {
+      if (DECL_THREAD_LOCAL_P (decl))
+       return tls_comm_section;
+      if (TREE_PUBLIC (decl) && bss_initializer_p (decl))
+       return comm_section;
+    }
+
+  if (DECL_INITIAL (decl) == error_mark_node)
+    reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
+  else if (DECL_INITIAL (decl))
+    reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
+  else
+    reloc = 0;
+
+  resolve_unique_section (decl, reloc, flag_data_sections);
+  if (IN_NAMED_SECTION (decl))
+    return get_named_section (decl, NULL, reloc);
+
+  if (!DECL_THREAD_LOCAL_P (decl)
+      && !(prefer_noswitch_p && targetm.have_switchable_bss_sections)
+      && bss_initializer_p (decl))
+    {
+      if (!TREE_PUBLIC (decl))
+       return lcomm_section;
+      if (bss_noswitch_section)
+       return bss_noswitch_section;
+    }
+
+  return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+}
+
+/* Return the block into which object_block DECL should be placed.  */
+
+static struct object_block *
+get_block_for_decl (tree decl)
+{
+  section *sect;
+
+  if (TREE_CODE (decl) == VAR_DECL)
+    {
+      /* The object must be defined in this translation unit.  */
+      if (DECL_EXTERNAL (decl))
+       return NULL;
+
+      /* There's no point using object blocks for something that is
+        isolated by definition.  */
+      if (DECL_ONE_ONLY (decl))
+       return NULL;
+    }
+
+  /* We can only calculate block offsets if the decl has a known
+     constant size.  */
+  if (DECL_SIZE_UNIT (decl) == NULL)
+    return NULL;
+  if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
+    return NULL;
+
+  /* Find out which section should contain DECL.  We cannot put it into
+     an object block if it requires a standalone definition.  */
+  sect = get_variable_section (decl, true);
+  if (SECTION_STYLE (sect) == SECTION_NOSWITCH)
+    return NULL;
+
+  return get_block_for_section (sect);
+}
+
+/* Make sure block symbol SYMBOL is in block BLOCK.  */
+
+static void
+change_symbol_block (rtx symbol, struct object_block *block)
+{
+  if (block != SYMBOL_REF_BLOCK (symbol))
+    {
+      gcc_assert (SYMBOL_REF_BLOCK_OFFSET (symbol) < 0);
+      SYMBOL_REF_BLOCK (symbol) = block;
+    }
+}
+
+/* Return true if it is possible to put DECL in an object_block.  */
+
+static bool
+use_blocks_for_decl_p (tree decl)
+{
+  /* Only data DECLs can be placed into object blocks.  */
+  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL)
+    return false;
+
+  /* Detect decls created by dw2_force_const_mem.  Such decls are
+     special because DECL_INITIAL doesn't specify the decl's true value.
+     dw2_output_indirect_constants will instead call assemble_variable
+     with dont_output_data set to 1 and then print the contents itself.  */
+  if (DECL_INITIAL (decl) == decl)
+    return false;
+
+  return true;
+}
+
 /* Create the DECL_RTL for a VAR_DECL or FUNCTION_DECL.  DECL should
    have static storage duration.  In other words, it should not be an
    automatic variable, including PARM_DECLs.
@@ -883,7 +963,7 @@ make_decl_rtl (tree decl)
              || TREE_PUBLIC (decl)
              || DECL_EXTERNAL (decl)
              || DECL_REGISTER (decl));
-  
+
   /* And that we were not given a type or a label.  */
   gcc_assert (TREE_CODE (decl) != TYPE_DECL
              && TREE_CODE (decl) != LABEL_DECL);
@@ -893,9 +973,9 @@ make_decl_rtl (tree decl)
   if (DECL_RTL_SET_P (decl))
     {
       /* If the old RTL had the wrong mode, fix the mode.  */
-      if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))
-       SET_DECL_RTL (decl, adjust_address_nv (DECL_RTL (decl),
-                                              DECL_MODE (decl), 0));
+      x = DECL_RTL (decl);
+      if (GET_MODE (x) != DECL_MODE (decl))
+       SET_DECL_RTL (decl, adjust_address_nv (x, DECL_MODE (decl), 0));
 
       if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
        return;
@@ -910,6 +990,13 @@ make_decl_rtl (tree decl)
         decl attribute overrides another.  */
       targetm.encode_section_info (decl, DECL_RTL (decl), false);
 
+      /* If the symbol has a SYMBOL_REF_BLOCK field, update it based
+        on the new decl information.  */
+      if (MEM_P (x)
+         && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+         && SYMBOL_REF_HAS_BLOCK_INFO_P (XEXP (x, 0)))
+       change_symbol_block (XEXP (x, 0), get_block_for_decl (decl));
+
       /* Make this function static known to the mudflap runtime.  */
       if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
        mudflap_enqueue_decl (decl);
@@ -919,20 +1006,26 @@ make_decl_rtl (tree decl)
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
 
-  if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
+  if (name[0] != '*' && TREE_CODE (decl) != FUNCTION_DECL
+      && DECL_REGISTER (decl))
     {
-      reg_number = decode_reg_name (name);
+      error ("register name not specified for %q+D", decl);
+    }
+  else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
+    {
+      const char *asmspec = name+1;
+      reg_number = decode_reg_name (asmspec);
       /* First detect errors in declaring global registers.  */
       if (reg_number == -1)
-       error ("%Jregister name not specified for %qD", decl, decl);
+       error ("register name not specified for %q+D", decl);
       else if (reg_number < 0)
-       error ("%Jinvalid register name for %qD", decl, decl);
+       error ("invalid register name for %q+D", decl);
       else if (TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
-       error ("%Jdata type of %qD isn%'t suitable for a register",
-              decl, decl);
+       error ("data type of %q+D isn%'t suitable for a register",
+              decl);
       else if (! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl))))
-       error ("%Jregister specified for %qD isn%'t suitable for data type",
-               decl, decl);
+       error ("register specified for %q+D isn%'t suitable for data type",
+               decl);
       /* Now handle properly declared static register variables.  */
       else
        {
@@ -944,8 +1037,9 @@ make_decl_rtl (tree decl)
              error ("global register variable has initial value");
            }
          if (TREE_THIS_VOLATILE (decl))
-           warning (0, "volatile register variables don%'t "
-                    "work as you might wish");
+           warning (OPT_Wvolatile_register_var,
+                    "optimization may eliminate reads and/or "
+                    "writes to register variables");
 
          /* If the user specified one of the eliminables registers here,
             e.g., FRAME_POINTER_REGNUM, we don't want to get this variable
@@ -982,7 +1076,7 @@ make_decl_rtl (tree decl)
       {
        reg_number = decode_reg_name (name);
        if (reg_number >= 0 || reg_number == -3)
-         error ("%Jregister name given for non-register variable %qD", decl, decl);
+         error ("register name given for non-register variable %q+D", decl);
       }
 #endif
   }
@@ -999,9 +1093,12 @@ make_decl_rtl (tree decl)
   if (TREE_CODE (decl) == VAR_DECL && DECL_WEAK (decl))
     DECL_COMMON (decl) = 0;
 
-  x = gen_rtx_SYMBOL_REF (Pmode, name);
+  if (use_object_blocks_p () && use_blocks_for_decl_p (decl))
+    x = create_block_symbol (name, get_block_for_decl (decl), -1);
+  else
+    x = gen_rtx_SYMBOL_REF (Pmode, name);
   SYMBOL_REF_WEAK (x) = DECL_WEAK (decl);
-  SYMBOL_REF_DECL (x) = decl;
+  SET_SYMBOL_REF_DECL (x, decl);
 
   x = gen_rtx_MEM (DECL_MODE (decl), x);
   if (TREE_CODE (decl) != FUNCTION_DECL)
@@ -1080,28 +1177,17 @@ default_named_section_asm_out_destructor (rtx symbol, int priority)
       section = buf;
     }
 
-  named_section_flags (section, SECTION_WRITE);
+  switch_to_section (get_section (section, SECTION_WRITE, NULL));
   assemble_align (POINTER_SIZE);
   assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
 }
 
 #ifdef DTORS_SECTION_ASM_OP
 void
-dtors_section (void)
-{
-  if (in_section != in_dtors)
-    {
-      in_section = in_dtors;
-      fputs (DTORS_SECTION_ASM_OP, asm_out_file);
-      fputc ('\n', asm_out_file);
-    }
-}
-
-void
 default_dtor_section_asm_out_destructor (rtx symbol,
                                         int priority ATTRIBUTE_UNUSED)
 {
-  dtors_section ();
+  switch_to_section (dtors_section);
   assemble_align (POINTER_SIZE);
   assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
 }
@@ -1141,28 +1227,17 @@ default_named_section_asm_out_constructor (rtx symbol, int priority)
       section = buf;
     }
 
-  named_section_flags (section, SECTION_WRITE);
+  switch_to_section (get_section (section, SECTION_WRITE, NULL));
   assemble_align (POINTER_SIZE);
   assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
 }
 
 #ifdef CTORS_SECTION_ASM_OP
 void
-ctors_section (void)
-{
-  if (in_section != in_ctors)
-    {
-      in_section = in_ctors;
-      fputs (CTORS_SECTION_ASM_OP, asm_out_file);
-      fputc ('\n', asm_out_file);
-    }
-}
-
-void
 default_ctor_section_asm_out_constructor (rtx symbol,
                                          int priority ATTRIBUTE_UNUSED)
 {
-  ctors_section ();
+  switch_to_section (ctors_section);
   assemble_align (POINTER_SIZE);
   assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
 }
@@ -1188,7 +1263,8 @@ notice_global_symbol (tree decl)
   const char **type = &first_global_object_name;
 
   if (first_global_object_name
-      || !TREE_PUBLIC (decl) || DECL_EXTERNAL (decl)
+      || !TREE_PUBLIC (decl)
+      || DECL_EXTERNAL (decl)
       || !DECL_NAME (decl)
       || (TREE_CODE (decl) != FUNCTION_DECL
          && (TREE_CODE (decl) != VAR_DECL
@@ -1206,11 +1282,11 @@ notice_global_symbol (tree decl)
   if (!*type)
     {
       const char *p;
-      char *name;
+      const char *name;
       rtx decl_rtl = DECL_RTL (decl);
 
       p = targetm.strip_name_encoding (XSTR (XEXP (decl_rtl, 0), 0));
-      name = xstrdup (p);
+      name = ggc_strdup (p);
 
       *type = name;
     }
@@ -1229,17 +1305,17 @@ assemble_start_function (tree decl, const char *fnname)
   bool hot_label_written = false;
 
   cfun->unlikely_text_section_name = NULL;
+
   first_function_block_is_cold = false;
   if (flag_reorder_blocks_and_partition)
     {
-      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "HOTB", const_labelno);
+      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTB", const_labelno);
       cfun->hot_section_label = ggc_strdup (tmp_label);
-      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "COLDB", const_labelno);
+      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDB", const_labelno);
       cfun->cold_section_label = ggc_strdup (tmp_label);
-      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "HOTE", const_labelno);
+      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTE", const_labelno);
       cfun->hot_section_end_label = ggc_strdup (tmp_label);
-      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "COLDE", const_labelno);
+      ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDE", const_labelno);
       cfun->cold_section_end_label = ggc_strdup (tmp_label);
       const_labelno++;
     }
@@ -1267,15 +1343,17 @@ assemble_start_function (tree decl, const char *fnname)
 
   if (flag_reorder_blocks_and_partition)
     {
-      unlikely_text_section ();
+      switch_to_section (unlikely_text_section ());
       assemble_align (FUNCTION_BOUNDARY);
       ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_label);
-      if (BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
+
+      /* When the function starts with a cold section, we need to explicitly
+        align the hot section and write out the hot section label.
+        But if the current function is a thunk, we do not have a CFG.  */
+      if (!current_function_is_thunk
+         && BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
        {
-         /* Since the function starts with a cold section, we need to
-            explicitly align the hot section and write out the hot
-            section label.  */
-         text_section ();
+         switch_to_section (text_section);
          assemble_align (FUNCTION_BOUNDARY);
          ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
          hot_label_written = true;
@@ -1289,35 +1367,20 @@ assemble_start_function (tree decl, const char *fnname)
         doing partitioning, if the entire function was decided by
         choose_function_section (predict.c) to be cold.  */
 
-      int i;
-      int len;
-      char *s;
-
       initialize_cold_section_name ();
 
-      /* The following is necessary, because 'strcmp
-       (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), blah)' always
-       fails, presumably because TREE_STRING_POINTER is declared to
-       be an array of size 1 of char.  */
-
-      len = TREE_STRING_LENGTH (DECL_SECTION_NAME (decl));
-      s = (char *) xmalloc (len + 1);
-
-      for (i = 0; i < len; i ++)
-       s[i] = (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)))[i];
-      s[len] = '\0';
-      
-      if (cfun->unlikely_text_section_name 
-         && (strcmp (s, cfun->unlikely_text_section_name) == 0))
+      if (cfun->unlikely_text_section_name
+         && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+                    cfun->unlikely_text_section_name) == 0)
        first_function_block_is_cold = true;
     }
 
-  last_text_section = no_section;
+  in_cold_section_p = first_function_block_is_cold;
 
   /* Switch to the correct text section for the start of the function.  */
 
-  function_section (decl);
-  if (flag_reorder_blocks_and_partition 
+  switch_to_section (function_section (decl));
+  if (flag_reorder_blocks_and_partition
       && !hot_label_written)
     ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
 
@@ -1371,40 +1434,40 @@ assemble_start_function (tree decl, const char *fnname)
   /* Standard thing is just output label for the function.  */
   ASM_OUTPUT_LABEL (asm_out_file, fnname);
 #endif /* ASM_DECLARE_FUNCTION_NAME */
-
-  insert_section_boundary_note ();
 }
 
 /* Output assembler code associated with defining the size of the
    function.  DECL describes the function.  NAME is the function's name.  */
 
 void
-assemble_end_function (tree decl, const char *fnname)
+assemble_end_function (tree decl, const char *fnname ATTRIBUTE_UNUSED)
 {
 #ifdef ASM_DECLARE_FUNCTION_SIZE
+  /* We could have switched section in the middle of the function.  */
+  if (flag_reorder_blocks_and_partition)
+    switch_to_section (function_section (decl));
   ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
 #endif
   if (! CONSTANT_POOL_BEFORE_FUNCTION)
     {
       output_constant_pool (fnname, decl);
-      function_section (decl); /* need to switch back */
+      switch_to_section (function_section (decl)); /* need to switch back */
     }
   /* Output labels for end of hot/cold text sections (to be used by
      debug info.)  */
   if (flag_reorder_blocks_and_partition)
     {
-      enum in_section save_text_section;
+      section *save_text_section;
 
       save_text_section = in_section;
-      unlikely_text_section ();
+      switch_to_section (unlikely_text_section ());
       ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_end_label);
       if (first_function_block_is_cold)
-       text_section ();
+       switch_to_section (text_section);
       else
-       function_section (decl);
+       switch_to_section (function_section (decl));
       ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_end_label);
-      if (save_text_section == in_unlikely_executed_text)
-       unlikely_text_section ();
+      switch_to_section (save_text_section);
     }
 }
 \f
@@ -1420,8 +1483,7 @@ assemble_zeros (unsigned HOST_WIDE_INT size)
 #ifdef ASM_NO_SKIP_IN_TEXT
   /* The `space' pseudo in the text section outputs nop insns rather than 0s,
      so we must output 0s explicitly in the text section.  */
-  if ((ASM_NO_SKIP_IN_TEXT && in_text_section ())
-      || (ASM_NO_SKIP_IN_TEXT && in_unlikely_text_section ()))
+  if (ASM_NO_SKIP_IN_TEXT && (in_section->common.flags & SECTION_CODE) != 0)
     {
       unsigned HOST_WIDE_INT i;
       for (i = 0; i < size; i++)
@@ -1468,124 +1530,142 @@ assemble_string (const char *p, int size)
 }
 
 \f
-#if defined  ASM_OUTPUT_ALIGNED_DECL_LOCAL
-#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size, DECL_ALIGN (decl))
-#else
-#if defined  ASM_OUTPUT_ALIGNED_LOCAL
-#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl))
+/* A noswitch_section_callback for lcomm_section.  */
+
+static bool
+emit_local (tree decl ATTRIBUTE_UNUSED,
+           const char *name ATTRIBUTE_UNUSED,
+           unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+           unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
+{
+#if defined ASM_OUTPUT_ALIGNED_DECL_LOCAL
+  ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name,
+                                size, DECL_ALIGN (decl));
+  return true;
+#elif defined ASM_OUTPUT_ALIGNED_LOCAL
+  ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl));
+  return true;
 #else
-#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
-  ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded)
-#endif
+  ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
+  return false;
 #endif
+}
+
+/* A noswitch_section_callback for bss_noswitch_section.  */
 
+#if defined ASM_OUTPUT_ALIGNED_BSS || defined ASM_OUTPUT_BSS
+static bool
+emit_bss (tree decl ATTRIBUTE_UNUSED,
+         const char *name ATTRIBUTE_UNUSED,
+         unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+         unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
+{
 #if defined ASM_OUTPUT_ALIGNED_BSS
-#define ASM_EMIT_BSS(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl))
-#else
-#if defined ASM_OUTPUT_BSS
-#define ASM_EMIT_BSS(decl, name, size, rounded) \
-  ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded)
+  ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl));
+  return true;
 #else
-#undef  ASM_EMIT_BSS
+  ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded);
+  return false;
 #endif
+}
 #endif
 
+/* A noswitch_section_callback for comm_section.  */
+
+static bool
+emit_common (tree decl ATTRIBUTE_UNUSED,
+            const char *name ATTRIBUTE_UNUSED,
+            unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+            unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
+{
 #if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
-#define ASM_EMIT_COMMON(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size, DECL_ALIGN (decl))
-#else
-#if defined ASM_OUTPUT_ALIGNED_COMMON
-#define ASM_EMIT_COMMON(decl, name, size, rounded) \
-  ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl))
+  ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name,
+                                 size, DECL_ALIGN (decl));
+  return true;
+#elif defined ASM_OUTPUT_ALIGNED_COMMON
+  ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl));
+  return true;
 #else
-#define ASM_EMIT_COMMON(decl, name, size, rounded) \
-  ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded)
-#endif
+  ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
+  return false;
 #endif
+}
+
+/* A noswitch_section_callback for tls_comm_section.  */
 
 static bool
-asm_emit_uninitialised (tree decl, const char *name,
-                       unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
-                       unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
+emit_tls_common (tree decl ATTRIBUTE_UNUSED,
+                const char *name ATTRIBUTE_UNUSED,
+                unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
+                unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
 {
-  enum
-  {
-    asm_dest_common,
-    asm_dest_bss,
-    asm_dest_local
-  }
-  destination = asm_dest_local;
-
-  /* ??? We should handle .bss via select_section mechanisms rather than
-     via special target hooks.  That would eliminate this special case.  */
-  if (TREE_PUBLIC (decl))
-    {
-      if (!DECL_COMMON (decl))
-#ifdef ASM_EMIT_BSS
-       destination = asm_dest_bss;
+#ifdef ASM_OUTPUT_TLS_COMMON
+  ASM_OUTPUT_TLS_COMMON (asm_out_file, decl, name, size);
+  return true;
 #else
-       return false;
+  sorry ("thread-local COMMON data not implemented");
+  return true;
 #endif
-      else
-       destination = asm_dest_common;
-    }
+}
 
-  if (destination != asm_dest_common)
-    {
-      resolve_unique_section (decl, 0, flag_data_sections);
-      /* Custom sections don't belong here.  */
-      if (DECL_SECTION_NAME (decl))
-        return false;
-    }
+/* Assemble DECL given that it belongs in SECTION_NOSWITCH section SECT.
+   NAME is the name of DECL's SYMBOL_REF.  */
 
-  if (destination == asm_dest_bss)
-    globalize_decl (decl);
+static void
+assemble_noswitch_variable (tree decl, const char *name, section *sect)
+{
+  unsigned HOST_WIDE_INT size, rounded;
 
-  if (flag_shared_data)
-    {
-      switch (destination)
-       {
-#ifdef ASM_OUTPUT_SHARED_BSS
-       case asm_dest_bss:
-         ASM_OUTPUT_SHARED_BSS (asm_out_file, decl, name, size, rounded);
-         return;
-#endif
-#ifdef ASM_OUTPUT_SHARED_COMMON
-       case asm_dest_common:
-         ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded);
-         return;
-#endif
-#ifdef ASM_OUTPUT_SHARED_LOCAL
-       case asm_dest_local:
-         ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
-         return;
-#endif
-       default:
-         break;
-       }
-    }
+  size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+  rounded = size;
+
+  /* Don't allocate zero bytes of common,
+     since that means "undefined external" in the linker.  */
+  if (size == 0)
+    rounded = 1;
+
+  /* Round size up to multiple of BIGGEST_ALIGNMENT bits
+     so that each uninitialized object starts on such a boundary.  */
+  rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
+  rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
+            * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
+
+  if (!sect->noswitch.callback (decl, name, size, rounded)
+      && (unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
+    warning (0, "requested alignment for %q+D is greater than "
+            "implemented alignment of %wu", decl, rounded);
+}
+
+/* A subroutine of assemble_variable.  Output the label and contents of
+   DECL, whose address is a SYMBOL_REF with name NAME.  DONT_OUTPUT_DATA
+   is as for assemble_variable.  */
 
-  switch (destination)
+static void
+assemble_variable_contents (tree decl, const char *name,
+                           bool dont_output_data)
+{
+  /* Do any machine/system dependent processing of the object.  */
+#ifdef ASM_DECLARE_OBJECT_NAME
+  last_assemble_variable_decl = decl;
+  ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
+#else
+  /* Standard thing is just output label for the object.  */
+  ASM_OUTPUT_LABEL (asm_out_file, name);
+#endif /* ASM_DECLARE_OBJECT_NAME */
+
+  if (!dont_output_data)
     {
-#ifdef ASM_EMIT_BSS
-    case asm_dest_bss:
-      ASM_EMIT_BSS (decl, name, size, rounded);
-      break;
-#endif
-    case asm_dest_common:
-      ASM_EMIT_COMMON (decl, name, size, rounded);
-      break;
-    case asm_dest_local:
-      ASM_EMIT_LOCAL (decl, name, size, rounded);
-      break;
-    default:
-      gcc_unreachable ();
+      if (DECL_INITIAL (decl)
+         && DECL_INITIAL (decl) != error_mark_node
+         && !initializer_zerop (DECL_INITIAL (decl)))
+       /* Output the actual data.  */
+       output_constant (DECL_INITIAL (decl),
+                        tree_low_cst (DECL_SIZE_UNIT (decl), 1),
+                        DECL_ALIGN (decl));
+      else
+       /* Leave space for it.  */
+       assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
     }
-
-  return true;
 }
 
 /* Assemble everything that is needed for a variable or function declaration.
@@ -1604,8 +1684,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 {
   const char *name;
   unsigned int align;
-  int reloc = 0;
-  rtx decl_rtl;
+  rtx decl_rtl, symbol;
+  section *sect;
 
   if (lang_hooks.decls.prepare_assemble_variable)
     lang_hooks.decls.prepare_assemble_variable (decl);
@@ -1643,7 +1723,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 
   if (!dont_output_data && DECL_SIZE (decl) == 0)
     {
-      error ("%Jstorage size of %qD isn%'t known", decl, decl);
+      error ("storage size of %q+D isn%'t known", decl);
       TREE_ASM_WRITTEN (decl) = 1;
       return;
     }
@@ -1671,11 +1751,14 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   if (! dont_output_data
       && ! host_integerp (DECL_SIZE_UNIT (decl), 1))
     {
-      error ("%Jsize of variable %qD is too large", decl, decl);
+      error ("size of variable %q+D is too large", decl);
       return;
     }
 
-  name = XSTR (XEXP (decl_rtl, 0), 0);
+  gcc_assert (MEM_P (decl_rtl));
+  gcc_assert (GET_CODE (XEXP (decl_rtl, 0)) == SYMBOL_REF);
+  symbol = XEXP (decl_rtl, 0);
+  name = XSTR (symbol, 0);
   if (TREE_PUBLIC (decl) && DECL_NAME (decl))
     notice_global_symbol (decl);
 
@@ -1694,8 +1777,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
      In particular, a.out format supports a maximum alignment of 4.  */
   if (align > MAX_OFILE_ALIGNMENT)
     {
-      warning (0, "%Jalignment of %qD is greater than maximum object "
-               "file alignment.  Using %d", decl, decl,
+      warning (0, "alignment of %q+D is greater than maximum object "
+               "file alignment.  Using %d", decl,
               MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
       align = MAX_OFILE_ALIGNMENT;
     }
@@ -1723,101 +1806,37 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   if (DECL_PRESERVE_P (decl))
     targetm.asm_out.mark_decl_preserved (name);
 
-  /* Handle uninitialized definitions.  */
-
-  /* If the decl has been given an explicit section name, then it
-     isn't common, and shouldn't be handled as such.  */
-  if (DECL_SECTION_NAME (decl) || dont_output_data)
-    ;
-  /* We don't implement common thread-local data at present.  */
-  else if (DECL_THREAD_LOCAL (decl))
-    {
-      if (DECL_COMMON (decl))
-       sorry ("thread-local COMMON data not implemented");
-    }
-  else if (DECL_INITIAL (decl) == 0
-          || DECL_INITIAL (decl) == error_mark_node
-          || (flag_zero_initialized_in_bss
-              /* Leave constant zeroes in .rodata so they can be shared.  */
-              && !TREE_READONLY (decl)
-              && initializer_zerop (DECL_INITIAL (decl))))
-    {
-      unsigned HOST_WIDE_INT size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
-      unsigned HOST_WIDE_INT rounded = size;
-
-      /* Don't allocate zero bytes of common,
-        since that means "undefined external" in the linker.  */
-      if (size == 0)
-       rounded = 1;
-
-      /* Round size up to multiple of BIGGEST_ALIGNMENT bits
-        so that each uninitialized object starts on such a boundary.  */
-      rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
-      rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
-                * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
-
-#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
-      if ((unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
-       warning (0, "%Jrequested alignment for %qD is greater than "
-                 "implemented alignment of %d", decl, decl, rounded);
-#endif
-
-      /* If the target cannot output uninitialized but not common global data
-        in .bss, then we have to use .data, so fall through.  */
-      if (asm_emit_uninitialised (decl, name, size, rounded))
-       return;
-    }
-
-  /* Handle initialized definitions.
-     Also handle uninitialized global definitions if -fno-common and the
-     target doesn't support ASM_OUTPUT_BSS.  */
-
   /* First make the assembler name(s) global if appropriate.  */
-  if (TREE_PUBLIC (decl) && DECL_NAME (decl))
+  sect = get_variable_section (decl, false);
+  if (TREE_PUBLIC (decl)
+      && DECL_NAME (decl)
+      && (sect->common.flags & SECTION_COMMON) == 0)
     globalize_decl (decl);
 
   /* Output any data that we will need to use the address of.  */
-  if (DECL_INITIAL (decl) == error_mark_node)
-    reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
-  else if (DECL_INITIAL (decl))
-    {
-      reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
-      output_addressed_constants (DECL_INITIAL (decl));
-    }
-
-  /* Switch to the appropriate section.  */
-  resolve_unique_section (decl, reloc, flag_data_sections);
-  variable_section (decl, reloc);
+  if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node)
+    output_addressed_constants (DECL_INITIAL (decl));
 
   /* dbxout.c needs to know this.  */
-  if (in_text_section () || in_unlikely_text_section ())
+  if (sect && (sect->common.flags & SECTION_CODE) != 0)
     DECL_IN_TEXT_SECTION (decl) = 1;
 
-  /* Output the alignment of this data.  */
-  if (align > BITS_PER_UNIT)
-    ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
-
-  /* Do any machine/system dependent processing of the object.  */
-#ifdef ASM_DECLARE_OBJECT_NAME
-  last_assemble_variable_decl = decl;
-  ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
-#else
-  /* Standard thing is just output label for the object.  */
-  ASM_OUTPUT_LABEL (asm_out_file, name);
-#endif /* ASM_DECLARE_OBJECT_NAME */
-
-  if (!dont_output_data)
+  /* If the decl is part of an object_block, make sure that the decl
+     has been positioned within its block, but do not write out its
+     definition yet.  output_object_blocks will do that later.  */
+  if (SYMBOL_REF_HAS_BLOCK_INFO_P (symbol) && SYMBOL_REF_BLOCK (symbol))
     {
-      if (DECL_INITIAL (decl)
-         && DECL_INITIAL (decl) != error_mark_node
-         && !initializer_zerop (DECL_INITIAL (decl)))
-       /* Output the actual data.  */
-       output_constant (DECL_INITIAL (decl),
-                        tree_low_cst (DECL_SIZE_UNIT (decl), 1),
-                        align);
-      else
-       /* Leave space for it.  */
-       assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
+      gcc_assert (!dont_output_data);
+      place_block_symbol (symbol);
+    }
+  else if (SECTION_STYLE (sect) == SECTION_NOSWITCH)
+    assemble_noswitch_variable (decl, name, sect);
+  else
+    {
+      switch_to_section (sect);
+      if (align > BITS_PER_UNIT)
+       ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
+      assemble_variable_contents (decl, name, dont_output_data);
     }
 }
 
@@ -1996,6 +2015,31 @@ mark_decl_referenced (tree decl)
      which do not need to be marked.  */
 }
 
+
+/* Follow the IDENTIFIER_TRANSPARENT_ALIAS chain starting at *ALIAS
+   until we find an identifier that is not itself a transparent alias.
+   Modify the alias passed to it by reference (and all aliases on the
+   way to the ultimate target), such that they do not have to be
+   followed again, and return the ultimate target of the alias
+   chain.  */
+
+static inline tree
+ultimate_transparent_alias_target (tree *alias)
+{
+  tree target = *alias;
+
+  if (IDENTIFIER_TRANSPARENT_ALIAS (target))
+    {
+      gcc_assert (TREE_CHAIN (target));
+      target = ultimate_transparent_alias_target (&TREE_CHAIN (target));
+      gcc_assert (! IDENTIFIER_TRANSPARENT_ALIAS (target)
+                 && ! TREE_CHAIN (target));
+      *alias = target;
+    }
+
+  return target;
+}
+
 /* Output to FILE (an assembly file) a reference to NAME.  If NAME
    starts with a *, the rest of NAME is output verbatim.  Otherwise
    NAME is transformed in a target-specific way (usually by the
@@ -2025,7 +2069,15 @@ assemble_name (FILE *file, const char *name)
 
   id = maybe_get_identifier (real_name);
   if (id)
-    mark_referenced (id);
+    {
+      tree id_orig = id;
+
+      mark_referenced (id);
+      ultimate_transparent_alias_target (&id);
+      if (id != id_orig)
+       name = IDENTIFIER_POINTER (id);
+      gcc_assert (! TREE_CHAIN (id));
+    }
 
   assemble_name_raw (file, name);
 }
@@ -2040,11 +2092,6 @@ assemble_static_space (unsigned HOST_WIDE_INT size)
   const char *namestring;
   rtx x;
 
-#if 0
-  if (flag_shared_data)
-    data_section ();
-#endif
-
   ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno);
   ++const_labelno;
   namestring = ggc_strdup (name);
@@ -2095,9 +2142,9 @@ assemble_trampoline_template (void)
   /* By default, put trampoline templates in read-only data section.  */
 
 #ifdef TRAMPOLINE_SECTION
-  TRAMPOLINE_SECTION ();
+  switch_to_section (TRAMPOLINE_SECTION);
 #else
-  readonly_data_section ();
+  switch_to_section (readonly_data_section);
 #endif
 
   /* Write the assembler code to define one.  */
@@ -2237,14 +2284,14 @@ assemble_integer (rtx x, unsigned int size, unsigned int align, int force)
     }
 
   gcc_assert (!force);
-  
+
   return false;
 }
 \f
 void
 assemble_real (REAL_VALUE_TYPE d, enum machine_mode mode, unsigned int align)
 {
-  long data[4];
+  long data[4] = {0, 0, 0, 0};
   int i;
   int bitsize, nelts, nunits, units_per;
 
@@ -2414,14 +2461,15 @@ const_hash_1 (const tree exp)
 
     case CONSTRUCTOR:
       {
-       tree link;
-       
+       unsigned HOST_WIDE_INT idx;
+       tree value;
+
        hi = 5 + int_size_in_bytes (TREE_TYPE (exp));
-       
-       for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
-         if (TREE_VALUE (link))
-           hi = hi * 603 + const_hash_1 (TREE_VALUE (link));
-       
+
+       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
+         if (value)
+           hi = hi * 603 + const_hash_1 (value);
+
        return hi;
       }
 
@@ -2508,6 +2556,8 @@ compare_constant (const tree t1, const tree t2)
       /* Integer constants are the same only if the same width of type.  */
       if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
        return 0;
+      if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
+       return 0;
       return tree_int_cst_equal (t1, t2);
 
     case REAL_CST:
@@ -2531,8 +2581,9 @@ compare_constant (const tree t1, const tree t2)
 
     case CONSTRUCTOR:
       {
-       tree l1, l2;
-       
+       VEC(constructor_elt, gc) *v1, *v2;
+       unsigned HOST_WIDE_INT idx;
+
        typecode = TREE_CODE (TREE_TYPE (t1));
        if (typecode != TREE_CODE (TREE_TYPE (t2)))
          return 0;
@@ -2554,28 +2605,34 @@ compare_constant (const tree t1, const tree t2)
              return 0;
          }
 
-       for (l1 = CONSTRUCTOR_ELTS (t1), l2 = CONSTRUCTOR_ELTS (t2);
-            l1 && l2;
-            l1 = TREE_CHAIN (l1), l2 = TREE_CHAIN (l2))
+       v1 = CONSTRUCTOR_ELTS (t1);
+       v2 = CONSTRUCTOR_ELTS (t2);
+       if (VEC_length (constructor_elt, v1)
+           != VEC_length (constructor_elt, v2))
+           return 0;
+
+       for (idx = 0; idx < VEC_length (constructor_elt, v1); ++idx)
          {
+           constructor_elt *c1 = VEC_index (constructor_elt, v1, idx);
+           constructor_elt *c2 = VEC_index (constructor_elt, v2, idx);
+
            /* Check that each value is the same...  */
-           if (! compare_constant (TREE_VALUE (l1), TREE_VALUE (l2)))
+           if (!compare_constant (c1->value, c2->value))
              return 0;
            /* ... and that they apply to the same fields!  */
            if (typecode == ARRAY_TYPE)
              {
-               if (! compare_constant (TREE_PURPOSE (l1),
-                                       TREE_PURPOSE (l2)))
+               if (!compare_constant (c1->index, c2->index))
                  return 0;
              }
            else
              {
-               if (TREE_PURPOSE (l1) != TREE_PURPOSE (l2))
+               if (c1->index != c2->index)
                  return 0;
              }
          }
-       
-       return l1 == NULL_TREE && l2 == NULL_TREE;
+
+       return 1;
       }
 
     case ADDR_EXPR:
@@ -2659,26 +2716,72 @@ copy_constant (tree exp)
     case CONSTRUCTOR:
       {
        tree copy = copy_node (exp);
-       tree list = copy_list (CONSTRUCTOR_ELTS (exp));
-       tree tail;
-
-       CONSTRUCTOR_ELTS (copy) = list;
-       for (tail = list; tail; tail = TREE_CHAIN (tail))
-         TREE_VALUE (tail) = copy_constant (TREE_VALUE (tail));
+       VEC(constructor_elt, gc) *v;
+       unsigned HOST_WIDE_INT idx;
+       tree purpose, value;
 
+       v = VEC_alloc(constructor_elt, gc, VEC_length(constructor_elt,
+                                                     CONSTRUCTOR_ELTS (exp)));
+       FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, purpose, value)
+         {
+           constructor_elt *ce = VEC_quick_push (constructor_elt, v, NULL);
+           ce->index = purpose;
+           ce->value = copy_constant (value);
+         }
+       CONSTRUCTOR_ELTS (copy) = v;
        return copy;
       }
 
     default:
       {
        tree t = lang_hooks.expand_constant (exp);
-       
+
        gcc_assert (t == exp);
        return copy_constant (t);
       }
     }
 }
 \f
+/* Return the alignment of constant EXP in bits.  */
+
+static unsigned int
+get_constant_alignment (tree exp)
+{
+  unsigned int align;
+
+  align = TYPE_ALIGN (TREE_TYPE (exp));
+#ifdef CONSTANT_ALIGNMENT
+  align = CONSTANT_ALIGNMENT (exp, align);
+#endif
+  return align;
+}
+
+/* Return the section into which constant EXP should be placed.  */
+
+static section *
+get_constant_section (tree exp)
+{
+  if (IN_NAMED_SECTION (exp))
+    return get_named_section (exp, NULL, compute_reloc_for_constant (exp));
+  else
+    return targetm.asm_out.select_section (exp,
+                                          compute_reloc_for_constant (exp),
+                                          get_constant_alignment (exp));
+}
+
+/* Return the size of constant EXP in bytes.  */
+
+static HOST_WIDE_INT
+get_constant_size (tree exp)
+{
+  HOST_WIDE_INT size;
+
+  size = int_size_in_bytes (TREE_TYPE (exp));
+  if (TREE_CODE (exp) == STRING_CST)
+    size = MAX (TREE_STRING_LENGTH (exp), size);
+  return size;
+}
+
 /* Subroutine of output_constant_def:
    No constant equal to EXP is known to have been output.
    Make a constant descriptor to enter EXP in the hash table.
@@ -2707,9 +2810,16 @@ build_constant_desc (tree exp)
   ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
 
   /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
-  symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
-  SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
-  SYMBOL_REF_DECL (symbol) = desc->value;
+  if (use_object_blocks_p ())
+    {
+      section *sect = get_constant_section (exp);
+      symbol = create_block_symbol (ggc_strdup (label),
+                                   get_block_for_section (sect), -1);
+    }
+  else
+    symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
+  SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL;
+  SET_SYMBOL_REF_DECL (symbol, desc->value);
   TREE_CONSTANT_POOL_ADDRESS_P (symbol) = 1;
 
   rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), symbol);
@@ -2801,54 +2911,57 @@ maybe_output_constant_def_contents (struct constant_descriptor_tree *desc,
   output_constant_def_contents (symbol);
 }
 
+/* Subroutine of output_constant_def_contents.  Output the definition
+   of constant EXP, which is pointed to by label LABEL.  ALIGN is the
+   constant's alignment in bits.  */
+
+static void
+assemble_constant_contents (tree exp, const char *label, unsigned int align)
+{
+  HOST_WIDE_INT size;
+
+  size = get_constant_size (exp);
+
+  /* Do any machine/system dependent processing of the constant.  */
+#ifdef ASM_DECLARE_CONSTANT_NAME
+  ASM_DECLARE_CONSTANT_NAME (asm_out_file, label, exp, size);
+#else
+  /* Standard thing is just output label for the constant.  */
+  ASM_OUTPUT_LABEL (asm_out_file, label);
+#endif /* ASM_DECLARE_CONSTANT_NAME */
+
+  /* Output the value of EXP.  */
+  output_constant (exp, size, align);
+}
+
 /* We must output the constant data referred to by SYMBOL; do so.  */
 
 static void
 output_constant_def_contents (rtx symbol)
 {
   tree exp = SYMBOL_REF_DECL (symbol);
-  const char *label = XSTR (symbol, 0);
-  HOST_WIDE_INT size;
+  unsigned int align;
 
   /* Make sure any other constants whose addresses appear in EXP
      are assigned label numbers.  */
-  int reloc = compute_reloc_for_constant (exp);
-
-  /* Align the location counter as required by EXP's data type.  */
-  unsigned int align = TYPE_ALIGN (TREE_TYPE (exp));
-#ifdef CONSTANT_ALIGNMENT
-  align = CONSTANT_ALIGNMENT (exp, align);
-#endif
-
   output_addressed_constants (exp);
 
   /* We are no longer deferring this constant.  */
   TREE_ASM_WRITTEN (exp) = 1;
 
-  if (IN_NAMED_SECTION (exp))
-    named_section (exp, NULL, reloc);
+  /* If the constant is part of an object block, make sure that the
+     decl has been positioned within its block, but do not write out
+     its definition yet.  output_object_blocks will do that later.  */
+  if (SYMBOL_REF_HAS_BLOCK_INFO_P (symbol) && SYMBOL_REF_BLOCK (symbol))
+    place_block_symbol (symbol);
   else
-    targetm.asm_out.select_section (exp, reloc, align);
-
-  if (align > BITS_PER_UNIT)
     {
-      ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+      switch_to_section (get_constant_section (exp));
+      align = get_constant_alignment (exp);
+      if (align > BITS_PER_UNIT)
+       ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+      assemble_constant_contents (exp, XSTR (symbol, 0), align);
     }
-
-  size = int_size_in_bytes (TREE_TYPE (exp));
-  if (TREE_CODE (exp) == STRING_CST)
-    size = MAX (TREE_STRING_LENGTH (exp), size);
-
-  /* Do any machine/system dependent processing of the constant.  */
-#ifdef ASM_DECLARE_CONSTANT_NAME
-  ASM_DECLARE_CONSTANT_NAME (asm_out_file, label, exp, size);
-#else
-  /* Standard thing is just output label for the constant.  */
-  ASM_OUTPUT_LABEL (asm_out_file, label);
-#endif /* ASM_DECLARE_CONSTANT_NAME */
-
-  /* Output the value of EXP.  */
-  output_constant (exp, size, align);
   if (flag_mudflap)
     mudflap_enqueue_constant (exp);
 }
@@ -2887,7 +3000,6 @@ struct rtx_constant_pool GTY(())
      constant addresses are restricted so that such constants must be stored
      in memory.  */
   htab_t GTY((param_is (struct constant_descriptor_rtx))) const_rtx_htab;
-  htab_t GTY((param_is (struct constant_descriptor_rtx))) const_rtx_sym_htab;
 
   /* Current offset in constant pool (does not include any
      machine-specific header).  */
@@ -2928,23 +3040,6 @@ const_desc_rtx_eq (const void *a, const void *b)
   return rtx_equal_p (x->constant, y->constant);
 }
 
-/* Hash and compare functions for const_rtx_sym_htab.  */
-
-static hashval_t
-const_desc_rtx_sym_hash (const void *ptr)
-{
-  const struct constant_descriptor_rtx *desc = ptr;
-  return htab_hash_string (XSTR (desc->sym, 0));
-}
-
-static int
-const_desc_rtx_sym_eq (const void *a, const void *b)
-{
-  const struct constant_descriptor_rtx *x = a;
-  const struct constant_descriptor_rtx *y = b;
-  return XSTR (x->sym, 0) == XSTR (y->sym, 0);
-}
-
 /* This is the worker function for const_rtx_hash, called via for_each_rtx.  */
 
 static int
@@ -3031,27 +3126,34 @@ const_rtx_hash (rtx x)
 }
 
 \f
+/* Create and return a new rtx constant pool.  */
+
+static struct rtx_constant_pool *
+create_constant_pool (void)
+{
+  struct rtx_constant_pool *pool;
+
+  pool = ggc_alloc (sizeof (struct rtx_constant_pool));
+  pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
+                                         const_desc_rtx_eq, NULL);
+  pool->first = NULL;
+  pool->last = NULL;
+  pool->offset = 0;
+  return pool;
+}
+
 /* Initialize constant pool hashing for a new function.  */
 
 void
 init_varasm_status (struct function *f)
 {
   struct varasm_status *p;
-  struct rtx_constant_pool *pool;
 
   p = ggc_alloc (sizeof (struct varasm_status));
   f->varasm = p;
 
-  pool = ggc_alloc (sizeof (struct rtx_constant_pool));
-  p->pool = pool;
+  p->pool = create_constant_pool ();
   p->deferred_constants = 0;
-
-  pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
-                                         const_desc_rtx_eq, NULL);
-  pool->const_rtx_sym_htab = htab_create_ggc (31, const_desc_rtx_sym_hash,
-                                             const_desc_rtx_sym_eq, NULL);
-  pool->first = pool->last = NULL;
-  pool->offset = 0;
 }
 \f
 /* Given a MINUS expression, simplify it if both sides
@@ -3071,7 +3173,7 @@ rtx
 force_const_mem (enum machine_mode mode, rtx x)
 {
   struct constant_descriptor_rtx *desc, tmp;
-  struct rtx_constant_pool *pool = cfun->varasm->pool;
+  struct rtx_constant_pool *pool;
   char label[256];
   rtx def, symbol;
   hashval_t hash;
@@ -3082,13 +3184,21 @@ force_const_mem (enum machine_mode mode, rtx x)
   if (targetm.cannot_force_const_mem (x))
     return NULL_RTX;
 
+  /* Record that this function has used a constant pool entry.  */
+  current_function_uses_const_pool = 1;
+
+  /* Decide which pool to use.  */
+  pool = (targetm.use_blocks_for_constant_p (mode, x)
+         ? shared_constant_pool
+         : cfun->varasm->pool);
+
   /* Lookup the value in the hashtable.  */
   tmp.constant = x;
   tmp.mode = mode;
   hash = const_rtx_hash (x);
   slot = htab_find_slot_with_hash (pool->const_rtx_htab, &tmp, hash, INSERT);
   desc = *slot;
-  
+
   /* If the constant was already present, return its memory.  */
   if (desc)
     return copy_rtx (desc->mem);
@@ -3132,15 +3242,18 @@ force_const_mem (enum machine_mode mode, rtx x)
 
   /* Construct the SYMBOL_REF.  Make sure to mark it as belonging to
      the constants pool.  */
-  desc->sym = symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
-  SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
+  if (use_object_blocks_p () && targetm.use_blocks_for_constant_p (mode, x))
+    {
+      section *sect = targetm.asm_out.select_rtx_section (mode, x, align);
+      symbol = create_block_symbol (ggc_strdup (label),
+                                   get_block_for_section (sect), -1);
+    }
+  else
+    symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
+  desc->sym = symbol;
+  SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL;
   CONSTANT_POOL_ADDRESS_P (symbol) = 1;
-  current_function_uses_const_pool = 1;
-
-  /* Insert the descriptor into the symbol cross-reference table too.  */
-  slot = htab_find_slot (pool->const_rtx_sym_htab, desc, INSERT);
-  gcc_assert (!*slot);
-  *slot = desc;
+  SET_SYMBOL_REF_CONSTANT (symbol, desc);
 
   /* Construct the MEM.  */
   desc->mem = def = gen_const_mem (mode, symbol);
@@ -3155,23 +3268,12 @@ force_const_mem (enum machine_mode mode, rtx x)
   return copy_rtx (def);
 }
 \f
-/* Given a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true, return a pointer to
-   the corresponding constant_descriptor_rtx structure.  */
-
-static struct constant_descriptor_rtx *
-find_pool_constant (struct rtx_constant_pool *pool, rtx sym)
-{
-  struct constant_descriptor_rtx tmp;
-  tmp.sym = sym;
-  return htab_find (pool->const_rtx_sym_htab, &tmp);
-}
-
 /* Given a constant pool SYMBOL_REF, return the corresponding constant.  */
 
 rtx
 get_pool_constant (rtx addr)
 {
-  return find_pool_constant (cfun->varasm->pool, addr)->constant;
+  return SYMBOL_REF_CONSTANT (addr)->constant;
 }
 
 /* Given a constant pool SYMBOL_REF, return the corresponding constant
@@ -3182,25 +3284,17 @@ get_pool_constant_mark (rtx addr, bool *pmarked)
 {
   struct constant_descriptor_rtx *desc;
 
-  desc = find_pool_constant (cfun->varasm->pool, addr);
+  desc = SYMBOL_REF_CONSTANT (addr);
   *pmarked = (desc->mark != 0);
   return desc->constant;
 }
 
-/* Likewise, but for the constant pool of a specific function.  */
-
-rtx
-get_pool_constant_for_function (struct function *f, rtx addr)
-{
-  return find_pool_constant (f->varasm->pool, addr)->constant;
-}
-
 /* Similar, return the mode.  */
 
 enum machine_mode
 get_pool_mode (rtx addr)
 {
-  return find_pool_constant (cfun->varasm->pool, addr)->mode;
+  return SYMBOL_REF_CONSTANT (addr)->mode;
 }
 
 /* Return the size of the constant pool.  */
@@ -3220,15 +3314,16 @@ output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
   switch (GET_MODE_CLASS (mode))
     {
     case MODE_FLOAT:
+    case MODE_DECIMAL_FLOAT:
       {
        REAL_VALUE_TYPE r;
-       
+
        gcc_assert (GET_CODE (x) == CONST_DOUBLE);
        REAL_VALUE_FROM_CONST_DOUBLE (r, x);
        assemble_real (r, mode, align);
        break;
       }
-      
+
     case MODE_INT:
     case MODE_PARTIAL_INT:
       assemble_integer (x, GET_MODE_SIZE (mode), align, 1);
@@ -3257,15 +3352,15 @@ output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
     }
 }
 
-/* Worker function for output_constant_pool.  Emit POOL.  */
+/* Worker function for output_constant_pool.  Emit constant DESC,
+   giving it ALIGN bits of alignment.  */
 
 static void
-output_constant_pool_1 (struct constant_descriptor_rtx *desc)
+output_constant_pool_1 (struct constant_descriptor_rtx *desc,
+                       unsigned int align)
 {
   rtx x, tmp;
 
-  if (!desc->mark)
-    return;
   x = desc->constant;
 
   /* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
@@ -3298,28 +3393,25 @@ output_constant_pool_1 (struct constant_descriptor_rtx *desc)
       break;
     }
 
-  /* First switch to correct section.  */
-  targetm.asm_out.select_rtx_section (desc->mode, x, desc->align);
-
 #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
   ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, desc->mode,
-                                desc->align, desc->labelno, done);
+                                align, desc->labelno, done);
 #endif
 
-  assemble_align (desc->align);
+  assemble_align (align);
 
   /* Output the label.  */
   targetm.asm_out.internal_label (asm_out_file, "LC", desc->labelno);
 
   /* Output the data.  */
-  output_constant_pool_2 (desc->mode, x, desc->align);
+  output_constant_pool_2 (desc->mode, x, align);
 
   /* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
      sections have proper size.  */
-  if (desc->align > GET_MODE_BITSIZE (desc->mode)
-      && in_section == in_named
-      && get_named_section_flags (in_named_name) & SECTION_MERGE)
-    assemble_align (desc->align);
+  if (align > GET_MODE_BITSIZE (desc->mode)
+      && in_section
+      && (in_section->common.flags & SECTION_MERGE))
+    assemble_align (align);
 
 #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
  done:
@@ -3332,9 +3424,8 @@ output_constant_pool_1 (struct constant_descriptor_rtx *desc)
    be used with for_each_rtx to mark all SYMBOL_REFs in an rtx.  */
 
 static int
-mark_constant (rtx *current_rtx, void *data)
+mark_constant (rtx *current_rtx, void *data ATTRIBUTE_UNUSED)
 {
-  struct rtx_constant_pool *pool = data;
   rtx x = *current_rtx;
 
   if (x == NULL_RTX || GET_CODE (x) != SYMBOL_REF)
@@ -3342,11 +3433,11 @@ mark_constant (rtx *current_rtx, void *data)
 
   if (CONSTANT_POOL_ADDRESS_P (x))
     {
-      struct constant_descriptor_rtx *desc = find_pool_constant (pool, x);
+      struct constant_descriptor_rtx *desc = SYMBOL_REF_CONSTANT (x);
       if (desc->mark == 0)
        {
          desc->mark = 1;
-         for_each_rtx (&desc->constant, mark_constant, pool);
+         for_each_rtx (&desc->constant, mark_constant, NULL);
        }
     }
   else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
@@ -3360,7 +3451,7 @@ mark_constant (rtx *current_rtx, void *data)
     }
 
   return -1;
-} 
+}
 
 /* Look through appropriate parts of INSN, marking all entries in the
    constant pool which are actually being used.  Entries that are only
@@ -3368,7 +3459,7 @@ mark_constant (rtx *current_rtx, void *data)
    deferred strings that are used.  */
 
 static void
-mark_constants (struct rtx_constant_pool *pool, rtx insn)
+mark_constants (rtx insn)
 {
   if (!INSN_P (insn))
     return;
@@ -3384,11 +3475,11 @@ mark_constants (struct rtx_constant_pool *pool, rtx insn)
        {
          rtx subinsn = XVECEXP (seq, 0, i);
          if (INSN_P (subinsn))
-           for_each_rtx (&PATTERN (subinsn), mark_constant, pool);
+           for_each_rtx (&PATTERN (subinsn), mark_constant, NULL);
        }
     }
   else
-    for_each_rtx (&PATTERN (insn), mark_constant, pool);
+    for_each_rtx (&PATTERN (insn), mark_constant, NULL);
 }
 
 /* Look through the instructions for this function, and mark all the
@@ -3396,48 +3487,81 @@ mark_constants (struct rtx_constant_pool *pool, rtx insn)
    which have indeed been used.  */
 
 static void
-mark_constant_pool (struct rtx_constant_pool *pool)
+mark_constant_pool (void)
 {
   rtx insn, link;
 
-  if (pool->first == 0 && n_deferred_constants == 0)
+  if (!current_function_uses_const_pool && n_deferred_constants == 0)
     return;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    mark_constants (pool, insn);
+    mark_constants (insn);
 
   for (link = current_function_epilogue_delay_list;
        link;
        link = XEXP (link, 1))
-    mark_constants (pool, XEXP (link, 0));
+    mark_constants (XEXP (link, 0));
 }
 
-/* Write all the constants in the constant pool.  */
+/* Write all the constants in POOL.  */
 
-void
+static void
+output_constant_pool_contents (struct rtx_constant_pool *pool)
+{
+  struct constant_descriptor_rtx *desc;
+
+  for (desc = pool->first; desc ; desc = desc->next)
+    if (desc->mark)
+      {
+       /* If the constant is part of an object_block, make sure that
+          the constant has been positioned within its block, but do not
+          write out its definition yet.  output_object_blocks will do
+          that later.  */
+       if (SYMBOL_REF_HAS_BLOCK_INFO_P (desc->sym)
+           && SYMBOL_REF_BLOCK (desc->sym))
+         place_block_symbol (desc->sym);
+       else
+         {
+           switch_to_section (targetm.asm_out.select_rtx_section
+                              (desc->mode, desc->constant, desc->align));
+           output_constant_pool_1 (desc, desc->align);
+         }
+      }
+}
+
+/* Mark all constants that are used in the current function, then write
+   out the function's private constant pool.  */
+
+static void
 output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
                      tree fndecl ATTRIBUTE_UNUSED)
 {
   struct rtx_constant_pool *pool = cfun->varasm->pool;
-  struct constant_descriptor_rtx *desc;
 
   /* It is possible for gcc to call force_const_mem and then to later
      discard the instructions which refer to the constant.  In such a
      case we do not need to output the constant.  */
-  mark_constant_pool (pool);
+  mark_constant_pool ();
 
 #ifdef ASM_OUTPUT_POOL_PROLOGUE
   ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool->offset);
 #endif
 
-  for (desc = pool->first; desc ; desc = desc->next)
-    output_constant_pool_1 (desc);
+  output_constant_pool_contents (pool);
 
 #ifdef ASM_OUTPUT_POOL_EPILOGUE
   ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool->offset);
 #endif
 }
 \f
+/* Write the contents of the shared constant pool.  */
+
+void
+output_shared_constant_pool (void)
+{
+  output_constant_pool_contents (shared_constant_pool);
+}
+\f
 /* Determine what kind of relocations EXP may need.  */
 
 int
@@ -3485,14 +3609,17 @@ compute_reloc_for_constant (tree exp)
     case NOP_EXPR:
     case CONVERT_EXPR:
     case NON_LVALUE_EXPR:
+    case VIEW_CONVERT_EXPR:
       reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
       break;
 
     case CONSTRUCTOR:
-      for (tem = CONSTRUCTOR_ELTS (exp); tem; tem = TREE_CHAIN (tem))
-       if (TREE_VALUE (tem) != 0)
-         reloc |= compute_reloc_for_constant (TREE_VALUE (tem));
-
+      {
+       unsigned HOST_WIDE_INT idx;
+       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, tem)
+         if (tem != 0)
+           reloc |= compute_reloc_for_constant (tem);
+      }
       break;
 
     default:
@@ -3541,14 +3668,17 @@ output_addressed_constants (tree exp)
     case NOP_EXPR:
     case CONVERT_EXPR:
     case NON_LVALUE_EXPR:
+    case VIEW_CONVERT_EXPR:
       output_addressed_constants (TREE_OPERAND (exp, 0));
       break;
 
     case CONSTRUCTOR:
-      for (tem = CONSTRUCTOR_ELTS (exp); tem; tem = TREE_CHAIN (tem))
-       if (TREE_VALUE (tem) != 0)
-         output_addressed_constants (TREE_VALUE (tem));
-
+      {
+       unsigned HOST_WIDE_INT idx;
+       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, tem)
+         if (tem != 0)
+           output_addressed_constants (tem);
+      }
       break;
 
     default:
@@ -3579,16 +3709,16 @@ initializer_constant_valid_p (tree value, tree endtype)
       if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
           || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
          && TREE_CONSTANT (value)
-         && CONSTRUCTOR_ELTS (value))
+         && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (value)))
        {
+         unsigned HOST_WIDE_INT idx;
          tree elt;
          bool absolute = true;
 
-         for (elt = CONSTRUCTOR_ELTS (value); elt; elt = TREE_CHAIN (elt))
+         FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt)
            {
              tree reloc;
-             value = TREE_VALUE (elt);
-             reloc = initializer_constant_valid_p (value, TREE_TYPE (value));
+             reloc = initializer_constant_valid_p (elt, TREE_TYPE (elt));
              if (!reloc)
                return NULL_TREE;
              if (reloc != null_pointer_node)
@@ -3612,18 +3742,24 @@ initializer_constant_valid_p (tree value, tree endtype)
     case ADDR_EXPR:
     case FDESC_EXPR:
       value = staticp (TREE_OPERAND (value, 0));
-      /* "&(*a).f" is like unto pointer arithmetic.  If "a" turns out to
-        be a constant, this is old-skool offsetof-like nonsense.  */
-      if (value
-         && TREE_CODE (value) == INDIRECT_REF
-         && TREE_CONSTANT (TREE_OPERAND (value, 0)))
-       return null_pointer_node;
-      /* Taking the address of a nested function involves a trampoline.  */
-      if (value
-         && TREE_CODE (value) == FUNCTION_DECL
-         && ((decl_function_context (value) && !DECL_NO_STATIC_CHAIN (value))
-             || DECL_NON_ADDR_CONST_P (value)))
-       return NULL_TREE;
+      if (value)
+       {
+         /* "&(*a).f" is like unto pointer arithmetic.  If "a" turns out to
+            be a constant, this is old-skool offsetof-like nonsense.  */
+         if (TREE_CODE (value) == INDIRECT_REF
+             && TREE_CONSTANT (TREE_OPERAND (value, 0)))
+           return null_pointer_node;
+         /* Taking the address of a nested function involves a trampoline.  */
+         if (TREE_CODE (value) == FUNCTION_DECL
+             && ((decl_function_context (value)
+                  && !DECL_NO_STATIC_CHAIN (value))
+                 || DECL_DLLIMPORT_P (value)))
+           return NULL_TREE;
+         /* "&{...}" requires a temporary to hold the constructed
+            object.  */
+         if (TREE_CODE (value) == CONSTRUCTOR)
+           return NULL_TREE;
+       }
       return value;
 
     case VIEW_CONVERT_EXPR:
@@ -3675,6 +3811,9 @@ initializer_constant_valid_p (tree value, tree endtype)
             || TREE_CODE (dest_type) == OFFSET_TYPE)
            && INTEGRAL_TYPE_P (src_type))
          {
+           if (TREE_CODE (src) == INTEGER_CST
+               && TYPE_PRECISION (dest_type) >= TYPE_PRECISION (src_type))
+             return null_pointer_node;
            if (integer_zerop (src))
              return null_pointer_node;
            else if (TYPE_PRECISION (dest_type) <= TYPE_PRECISION (src_type))
@@ -3832,19 +3971,63 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
   if (size == 0 || flag_syntax_only)
     return;
 
+  /* See if we're trying to initialize a pointer in a non-default mode
+     to the address of some declaration somewhere.  If the target says
+     the mode is valid for pointers, assume the target has a way of
+     resolving it.  */
+  if (TREE_CODE (exp) == NOP_EXPR
+      && POINTER_TYPE_P (TREE_TYPE (exp))
+      && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp))))
+    {
+      tree saved_type = TREE_TYPE (exp);
+
+      /* Peel off any intermediate conversions-to-pointer for valid
+        pointer modes.  */
+      while (TREE_CODE (exp) == NOP_EXPR
+            && POINTER_TYPE_P (TREE_TYPE (exp))
+            && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp))))
+       exp = TREE_OPERAND (exp, 0);
+
+      /* If what we're left with is the address of something, we can
+        convert the address to the final type and output it that
+        way.  */
+      if (TREE_CODE (exp) == ADDR_EXPR)
+       exp = build1 (ADDR_EXPR, saved_type, TREE_OPERAND (exp, 0));
+      /* Likewise for constant ints.  */
+      else if (TREE_CODE (exp) == INTEGER_CST)
+       exp = build_int_cst_wide (saved_type, TREE_INT_CST_LOW (exp),
+                                 TREE_INT_CST_HIGH (exp));
+      
+    }
+
   /* Eliminate any conversions since we'll be outputting the underlying
      constant.  */
   while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
         || TREE_CODE (exp) == NON_LVALUE_EXPR
         || TREE_CODE (exp) == VIEW_CONVERT_EXPR)
-    exp = TREE_OPERAND (exp, 0);
+    {
+      HOST_WIDE_INT type_size = int_size_in_bytes (TREE_TYPE (exp));
+      HOST_WIDE_INT op_size = int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+      /* Make sure eliminating the conversion is really a no-op, except with
+        VIEW_CONVERT_EXPRs to allow for wild Ada unchecked conversions and
+        union types to allow for Ada unchecked unions.  */
+      if (type_size > op_size
+         && TREE_CODE (exp) != VIEW_CONVERT_EXPR
+         && TREE_CODE (TREE_TYPE (exp)) != UNION_TYPE)
+       internal_error ("no-op convert from %wd to %wd bytes in initializer",
+                       op_size, type_size);
+
+      exp = TREE_OPERAND (exp, 0);
+    }
 
   code = TREE_CODE (TREE_TYPE (exp));
   thissize = int_size_in_bytes (TREE_TYPE (exp));
 
   /* Allow a constructor with no elements for any data type.
      This means to fill the space with zeros.  */
-  if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0)
+  if (TREE_CODE (exp) == CONSTRUCTOR
+      && VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (exp)))
     {
       assemble_zeros (size);
       return;
@@ -3866,7 +4049,6 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
      Otherwise, break and ensure SIZE is the size written.  */
   switch (code)
     {
-    case CHAR_TYPE:
     case BOOLEAN_TYPE:
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
@@ -3911,12 +4093,12 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
            tree link;
            unsigned int nalign;
            enum machine_mode inner;
-           
+
            inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
            nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
-           
+
            elt_size = GET_MODE_SIZE (inner);
-           
+
            link = TREE_VECTOR_CST_ELTS (exp);
            output_constant (TREE_VALUE (link), elt_size, align);
            while ((link = TREE_CHAIN (link)) != NULL)
@@ -3954,6 +4136,8 @@ static unsigned HOST_WIDE_INT
 array_size_for_constructor (tree val)
 {
   tree max_index, i;
+  unsigned HOST_WIDE_INT cnt;
+  tree index, value, tmp;
 
   /* This code used to attempt to handle string constants that are not
      arrays of single-bytes, but nothing else does, so there's no point in
@@ -3962,10 +4146,8 @@ array_size_for_constructor (tree val)
     return TREE_STRING_LENGTH (val);
 
   max_index = NULL_TREE;
-  for (i = CONSTRUCTOR_ELTS (val); i; i = TREE_CHAIN (i))
+  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (val), cnt, index, value)
     {
-      tree index = TREE_PURPOSE (i);
-
       if (TREE_CODE (index) == RANGE_EXPR)
        index = TREE_OPERAND (index, 1);
       if (max_index == NULL_TREE || tree_int_cst_lt (max_index, index))
@@ -3976,10 +4158,10 @@ array_size_for_constructor (tree val)
     return 0;
 
   /* Compute the total number of array elements.  */
-  i = size_binop (MINUS_EXPR, convert (sizetype, max_index),
-                 convert (sizetype,
-                          TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)))));
-  i = size_binop (PLUS_EXPR, i, convert (sizetype, integer_one_node));
+  tmp = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)));
+  i = size_binop (MINUS_EXPR, fold_convert (sizetype, max_index),
+                 fold_convert (sizetype, tmp));
+  i = size_binop (PLUS_EXPR, i, build_int_cst (sizetype, 1));
 
   /* Multiply by the array element unit size to find number of bytes.  */
   i = size_binop (MULT_EXPR, i, TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val))));
@@ -3995,7 +4177,7 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
                    unsigned int align)
 {
   tree type = TREE_TYPE (exp);
-  tree link, field = 0;
+  tree field = 0;
   tree min_index = 0;
   /* Number of bytes output or skipped so far.
      In other words, current position within the constructor.  */
@@ -4003,6 +4185,8 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
   /* Nonzero means BYTE contains part of a byte, to be output.  */
   int byte_buffer_in_use = 0;
   int byte = 0;
+  unsigned HOST_WIDE_INT cnt;
+  constructor_elt *ce;
 
   gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
 
@@ -4022,29 +4206,28 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
      There is always a maximum of one element in the chain LINK for unions
      (even if the initializer in a source program incorrectly contains
      more one).  */
-  for (link = CONSTRUCTOR_ELTS (exp);
-       link;
-       link = TREE_CHAIN (link),
-       field = field ? TREE_CHAIN (field) : 0)
+  for (cnt = 0;
+       VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), cnt, ce);
+       cnt++, field = field ? TREE_CHAIN (field) : 0)
     {
-      tree val = TREE_VALUE (link);
+      tree val = ce->value;
       tree index = 0;
 
       /* The element in a union constructor specifies the proper field
         or index.  */
       if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
           || TREE_CODE (type) == QUAL_UNION_TYPE)
-         && TREE_PURPOSE (link) != 0)
-       field = TREE_PURPOSE (link);
+         && ce->index != 0)
+       field = ce->index;
 
       else if (TREE_CODE (type) == ARRAY_TYPE)
-       index = TREE_PURPOSE (link);
+       index = ce->index;
 
 #ifdef ASM_COMMENT_START
       if (field && flag_verbose_asm)
        fprintf (asm_out_file, "%s %s:\n",
-                ASM_COMMENT_START, 
-                DECL_NAME (field) 
+                ASM_COMMENT_START,
+                DECL_NAME (field)
                 ? IDENTIFIER_POINTER (DECL_NAME (field))
                 : "<anonymous>");
 #endif
@@ -4101,6 +4284,7 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
             if each element has the proper size.  */
          if ((field != 0 || index != 0) && pos != total_bytes)
            {
+             gcc_assert (pos >= total_bytes);
              assemble_zeros (pos - total_bytes);
              total_bytes = pos;
            }
@@ -4176,6 +4360,7 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
              /* If still not at proper byte, advance to there.  */
              if (next_offset / BITS_PER_UNIT != total_bytes)
                {
+                 gcc_assert (next_offset / BITS_PER_UNIT >= total_bytes);
                  assemble_zeros (next_offset / BITS_PER_UNIT - total_bytes);
                  total_bytes = next_offset / BITS_PER_UNIT;
                }
@@ -4347,16 +4532,16 @@ merge_weak (tree newdecl, tree olddecl)
         declare_weak because the NEWDECL and OLDDECL was not yet
         been merged; therefore, TREE_ASM_WRITTEN was not set.  */
       if (TREE_ASM_WRITTEN (olddecl))
-       error ("%Jweak declaration of %qD must precede definition",
-              newdecl, newdecl);
+       error ("weak declaration of %q+D must precede definition",
+              newdecl);
 
       /* If we've already generated rtl referencing OLDDECL, we may
         have done so in a way that will not function properly with
         a weak symbol.  */
       else if (TREE_USED (olddecl)
               && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (olddecl)))
-       warning (0, "%Jweak declaration of %qD after first use results "
-                 "in unspecified behavior", newdecl, newdecl);
+       warning (0, "weak declaration of %q+D after first use results "
+                 "in unspecified behavior", newdecl);
 
       if (SUPPORTS_WEAK)
        {
@@ -4389,49 +4574,134 @@ void
 declare_weak (tree decl)
 {
   if (! TREE_PUBLIC (decl))
-    error ("%Jweak declaration of %qD must be public", decl, decl);
+    error ("weak declaration of %q+D must be public", decl);
   else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
-    error ("%Jweak declaration of %qD must precede definition", decl, decl);
+    error ("weak declaration of %q+D must precede definition", decl);
   else if (SUPPORTS_WEAK)
     {
       if (! DECL_WEAK (decl))
        weak_decls = tree_cons (NULL, decl, weak_decls);
     }
   else
-    warning (0, "%Jweak declaration of %qD not supported", decl, decl);
+    warning (0, "weak declaration of %q+D not supported", decl);
 
   mark_weak (decl);
 }
 
-/* Emit any pending weak declarations.  */
-
-void
-weak_finish (void)
+static void
+weak_finish_1 (tree decl)
 {
-  tree t;
-
-  for (t = weak_decls; t; t = TREE_CHAIN (t))
-    {
-      tree decl = TREE_VALUE (t);
 #if defined (ASM_WEAKEN_DECL) || defined (ASM_WEAKEN_LABEL)
-      const char *const name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  const char *const name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
 #endif
 
-      if (! TREE_USED (decl))
-       continue;
+  if (! TREE_USED (decl))
+    return;
 
 #ifdef ASM_WEAKEN_DECL
-      ASM_WEAKEN_DECL (asm_out_file, decl, name, NULL);
+  ASM_WEAKEN_DECL (asm_out_file, decl, name, NULL);
 #else
 #ifdef ASM_WEAKEN_LABEL
-      ASM_WEAKEN_LABEL (asm_out_file, name);
+  ASM_WEAKEN_LABEL (asm_out_file, name);
 #else
 #ifdef ASM_OUTPUT_WEAK_ALIAS
-      warning (0, "only weak aliases are supported in this configuration");
-      return;
+  {
+    static bool warn_once = 0;
+    if (! warn_once)
+      {
+       warning (0, "only weak aliases are supported in this configuration");
+       warn_once = 1;
+      }
+    return;
+  }
+#endif
 #endif
 #endif
+}
+
+/* This TREE_LIST contains weakref targets.  */
+
+static GTY(()) tree weakref_targets;
+
+/* Forward declaration.  */
+static tree find_decl_and_mark_needed (tree decl, tree target);
+
+/* Emit any pending weak declarations.  */
+
+void
+weak_finish (void)
+{
+  tree t;
+
+  for (t = weakref_targets; t; t = TREE_CHAIN (t))
+    {
+      tree alias_decl = TREE_PURPOSE (t);
+      tree target = ultimate_transparent_alias_target (&TREE_VALUE (t));
+
+      if (! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias_decl)))
+       /* Remove alias_decl from the weak list, but leave entries for
+          the target alone.  */
+       target = NULL_TREE;
+#ifndef ASM_OUTPUT_WEAKREF
+      else if (! TREE_SYMBOL_REFERENCED (target))
+       {
+         /* Use ASM_WEAKEN_LABEL only if ASM_WEAKEN_DECL is not
+            defined, otherwise we and weak_finish_1 would use a
+            different macros.  */
+# if defined ASM_WEAKEN_LABEL && ! defined ASM_WEAKEN_DECL
+         ASM_WEAKEN_LABEL (asm_out_file, IDENTIFIER_POINTER (target));
+# else
+         tree decl = find_decl_and_mark_needed (alias_decl, target);
+
+         if (! decl)
+           {
+             decl = build_decl (TREE_CODE (alias_decl), target,
+                                TREE_TYPE (alias_decl));
+
+             DECL_EXTERNAL (decl) = 1;
+             TREE_PUBLIC (decl) = 1;
+             DECL_ARTIFICIAL (decl) = 1;
+             TREE_NOTHROW (decl) = TREE_NOTHROW (alias_decl);
+             TREE_USED (decl) = 1;
+           }
+
+         weak_finish_1 (decl);
+# endif
+       }
 #endif
+
+      {
+       tree *p;
+       tree t2;
+
+       /* Remove the alias and the target from the pending weak list
+          so that we do not emit any .weak directives for the former,
+          nor multiple .weak directives for the latter.  */
+       for (p = &weak_decls; (t2 = *p) ; )
+         {
+           if (TREE_VALUE (t2) == alias_decl
+               || target == DECL_ASSEMBLER_NAME (TREE_VALUE (t2)))
+             *p = TREE_CHAIN (t2);
+           else
+             p = &TREE_CHAIN (t2);
+         }
+
+       /* Remove other weakrefs to the same target, to speed things up.  */
+       for (p = &TREE_CHAIN (t); (t2 = *p) ; )
+         {
+           if (target == ultimate_transparent_alias_target (&TREE_VALUE (t2)))
+             *p = TREE_CHAIN (t2);
+           else
+             p = &TREE_CHAIN (t2);
+         }
+      }
+    }
+
+  for (t = weak_decls; t; t = TREE_CHAIN (t))
+    {
+      tree decl = TREE_VALUE (t);
+
+      weak_finish_1 (decl);
     }
 }
 
@@ -4462,6 +4732,18 @@ globalize_decl (tree decl)
          else
            p = &TREE_CHAIN (t);
        }
+
+       /* Remove weakrefs to the same target from the pending weakref
+          list, for the same reason.  */
+       for (p = &weakref_targets; (t = *p) ; )
+         {
+           if (DECL_ASSEMBLER_NAME (decl)
+               == ultimate_transparent_alias_target (&TREE_VALUE (t)))
+             *p = TREE_CHAIN (t);
+           else
+             p = &TREE_CHAIN (t);
+         }
+
       return;
     }
 #elif defined(ASM_MAKE_LABEL_LINKONCE)
@@ -4497,27 +4779,28 @@ find_decl_and_mark_needed (tree decl, tree target)
   struct cgraph_node *fnode = NULL;
   struct cgraph_varpool_node *vnode = NULL;
 
-  /* C++ thunk emitting code produces aliases late in the game.
-     Avoid confusing cgraph code in that case.  */
-  if (!cgraph_global_info_ready)
+  if (TREE_CODE (decl) == FUNCTION_DECL)
     {
-      if (TREE_CODE (decl) == FUNCTION_DECL)
-       {
-         fnode = cgraph_node_for_asm (target);
-         if (fnode == NULL)
-           vnode = cgraph_varpool_node_for_asm (target);
-       }
-      else
-       {
-         vnode = cgraph_varpool_node_for_asm (target);
-         if (vnode == NULL)
-           fnode = cgraph_node_for_asm (target);
-       }
+      fnode = cgraph_node_for_asm (target);
+      if (fnode == NULL)
+       vnode = cgraph_varpool_node_for_asm (target);
+    }
+  else
+    {
+      vnode = cgraph_varpool_node_for_asm (target);
+      if (vnode == NULL)
+       fnode = cgraph_node_for_asm (target);
     }
 
   if (fnode)
     {
-      cgraph_mark_needed_node (fnode);
+      /* We can't mark function nodes as used after cgraph global info
+        is finished.  This wouldn't generally be necessary, but C++
+        virtual table thunks are introduced late in the game and
+        might seem like they need marking, although in fact they
+        don't.  */
+      if (! cgraph_global_info_ready)
+       cgraph_mark_needed_node (fnode);
       return fnode->decl;
     }
   else if (vnode)
@@ -4525,7 +4808,7 @@ find_decl_and_mark_needed (tree decl, tree target)
       cgraph_varpool_mark_needed_node (vnode);
       return vnode->decl;
     }
-  else 
+  else
     return NULL_TREE;
 }
 
@@ -4534,7 +4817,7 @@ find_decl_and_mark_needed (tree decl, tree target)
    tree node is DECL to have the value of the tree node TARGET.  */
 
 static void
-do_assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
+do_assemble_alias (tree decl, tree target)
 {
   if (TREE_ASM_WRITTEN (decl))
     return;
@@ -4542,6 +4825,27 @@ do_assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
   TREE_ASM_WRITTEN (decl) = 1;
   TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
 
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+    {
+      ultimate_transparent_alias_target (&target);
+
+      if (!TREE_SYMBOL_REFERENCED (target))
+       weakref_targets = tree_cons (decl, target, weakref_targets);
+
+#ifdef ASM_OUTPUT_WEAKREF
+      ASM_OUTPUT_WEAKREF (asm_out_file, decl,
+                         IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+                         IDENTIFIER_POINTER (target));
+#else
+      if (!SUPPORTS_WEAK)
+       {
+         error ("%Jweakref is not supported in this configuration", decl);
+         return;
+       }
+#endif
+      return;
+    }
+
 #ifdef ASM_OUTPUT_DEF
   /* Make name accessible from other files, if appropriate.  */
 
@@ -4576,6 +4880,17 @@ do_assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
        *p = TREE_CHAIN (t);
       else
        p = &TREE_CHAIN (t);
+
+    /* Remove weakrefs to the same target from the pending weakref
+       list, for the same reason.  */
+    for (p = &weakref_targets; (t = *p) ; )
+      {
+       if (DECL_ASSEMBLER_NAME (decl)
+           == ultimate_transparent_alias_target (&TREE_VALUE (t)))
+         *p = TREE_CHAIN (t);
+       else
+         p = &TREE_CHAIN (t);
+      }
   }
 #endif
 }
@@ -4595,11 +4910,15 @@ finish_aliases_1 (void)
 
       target_decl = find_decl_and_mark_needed (p->decl, p->target);
       if (target_decl == NULL)
-       error ("%J%qD aliased to undefined symbol %qE",
-              p->decl, p->decl, p->target);
-      else if (DECL_EXTERNAL (target_decl))
-       error ("%J%qD aliased to external symbol %qE",
-              p->decl, p->decl, p->target);
+       {
+         if (! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
+           error ("%q+D aliased to undefined symbol %qs",
+                  p->decl, IDENTIFIER_POINTER (p->target));
+       }
+      else if (DECL_EXTERNAL (target_decl)
+              && ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
+       error ("%q+D aliased to external symbol %qs",
+              p->decl, IDENTIFIER_POINTER (p->target));
     }
 }
 
@@ -4626,19 +4945,43 @@ void
 assemble_alias (tree decl, tree target)
 {
   tree target_decl;
+  bool is_weakref = false;
+
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+    {
+      tree alias = DECL_ASSEMBLER_NAME (decl);
+
+      is_weakref = true;
+
+      ultimate_transparent_alias_target (&target);
 
+      if (alias == target)
+       error ("weakref %q+D ultimately targets itself", decl);
+      else
+       {
+#ifndef ASM_OUTPUT_WEAKREF
+         IDENTIFIER_TRANSPARENT_ALIAS (alias) = 1;
+         TREE_CHAIN (alias) = target;
+#endif
+       }
+      if (TREE_PUBLIC (decl))
+       error ("weakref %q+D must have static linkage", decl);
+    }
+  else
+    {
 #if !defined (ASM_OUTPUT_DEF)
 # if !defined(ASM_OUTPUT_WEAK_ALIAS) && !defined (ASM_WEAKEN_DECL)
-  error ("%Jalias definitions not supported in this configuration", decl);
-  return;
-# else
-  if (!DECL_WEAK (decl))
-    {
-      error ("%Jonly weak aliases are supported in this configuration", decl);
+      error ("%Jalias definitions not supported in this configuration", decl);
       return;
-    }
+# else
+      if (!DECL_WEAK (decl))
+       {
+         error ("%Jonly weak aliases are supported in this configuration", decl);
+         return;
+       }
 # endif
 #endif
+    }
 
   /* We must force creation of DECL_RTL for debug info generation, even though
      we don't use it here.  */
@@ -4648,7 +4991,8 @@ assemble_alias (tree decl, tree target)
   /* A quirk of the initial implementation of aliases required that the user
      add "extern" to all of them.  Which is silly, but now historical.  Do
      note that the symbol is in fact locally defined.  */
-  DECL_EXTERNAL (decl) = 0;
+  if (! is_weakref)
+    DECL_EXTERNAL (decl) = 0;
 
   /* Allow aliases to aliases.  */
   if (TREE_CODE (decl) == FUNCTION_DECL)
@@ -4749,39 +5093,82 @@ make_decl_one_only (tree decl)
 void
 init_varasm_once (void)
 {
-  in_named_htab = htab_create_ggc (31, in_named_entry_hash,
-                                  in_named_entry_eq, NULL);
+  section_htab = htab_create_ggc (31, section_entry_hash,
+                                 section_entry_eq, NULL);
+  object_block_htab = htab_create_ggc (31, object_block_entry_hash,
+                                      object_block_entry_eq, NULL);
   const_desc_htab = htab_create_ggc (1009, const_desc_hash,
                                     const_desc_eq, NULL);
 
   const_alias_set = new_alias_set ();
+  shared_constant_pool = create_constant_pool ();
+
+#ifdef TEXT_SECTION_ASM_OP
+  text_section = get_unnamed_section (SECTION_CODE, output_section_asm_op,
+                                     TEXT_SECTION_ASM_OP);
+#endif
+
+#ifdef DATA_SECTION_ASM_OP
+  data_section = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
+                                     DATA_SECTION_ASM_OP);
+#endif
+
+#ifdef SDATA_SECTION_ASM_OP
+  sdata_section = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
+                                      SDATA_SECTION_ASM_OP);
+#endif
+
+#ifdef READONLY_DATA_SECTION_ASM_OP
+  readonly_data_section = get_unnamed_section (0, output_section_asm_op,
+                                              READONLY_DATA_SECTION_ASM_OP);
+#endif
+
+#ifdef CTORS_SECTION_ASM_OP
+  ctors_section = get_unnamed_section (0, output_section_asm_op,
+                                      CTORS_SECTION_ASM_OP);
+#endif
+
+#ifdef DTORS_SECTION_ASM_OP
+  dtors_section = get_unnamed_section (0, output_section_asm_op,
+                                      DTORS_SECTION_ASM_OP);
+#endif
+
+#ifdef BSS_SECTION_ASM_OP
+  bss_section = get_unnamed_section (SECTION_WRITE | SECTION_BSS,
+                                    output_section_asm_op,
+                                    BSS_SECTION_ASM_OP);
+#endif
+
+#ifdef SBSS_SECTION_ASM_OP
+  sbss_section = get_unnamed_section (SECTION_WRITE | SECTION_BSS,
+                                     output_section_asm_op,
+                                     SBSS_SECTION_ASM_OP);
+#endif
+
+  tls_comm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
+                                          | SECTION_COMMON, emit_tls_common);
+  lcomm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
+                                       | SECTION_COMMON, emit_local);
+  comm_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS
+                                      | SECTION_COMMON, emit_common);
+
+#if defined ASM_OUTPUT_ALIGNED_BSS || defined ASM_OUTPUT_BSS
+  bss_noswitch_section = get_noswitch_section (SECTION_WRITE | SECTION_BSS,
+                                              emit_bss);
+#endif
+
+  targetm.asm_out.init_sections ();
+
+  if (readonly_data_section == NULL)
+    readonly_data_section = text_section;
 }
 
-static enum tls_model
-decl_tls_model (tree decl)
+enum tls_model
+decl_default_tls_model (tree decl)
 {
   enum tls_model kind;
-  tree attr = lookup_attribute ("tls_model", DECL_ATTRIBUTES (decl));
   bool is_local;
 
-  if (attr)
-    {
-      attr = TREE_VALUE (TREE_VALUE (attr));
-      gcc_assert (TREE_CODE (attr) == STRING_CST);
-      
-      if (!strcmp (TREE_STRING_POINTER (attr), "local-exec"))
-       kind = TLS_MODEL_LOCAL_EXEC;
-      else if (!strcmp (TREE_STRING_POINTER (attr), "initial-exec"))
-       kind = TLS_MODEL_INITIAL_EXEC;
-      else if (!strcmp (TREE_STRING_POINTER (attr), "local-dynamic"))
-       kind = optimize ? TLS_MODEL_LOCAL_DYNAMIC : TLS_MODEL_GLOBAL_DYNAMIC;
-      else if (!strcmp (TREE_STRING_POINTER (attr), "global-dynamic"))
-       kind = TLS_MODEL_GLOBAL_DYNAMIC;
-      else
-       gcc_unreachable ();
-      return kind;
-    }
-
   is_local = targetm.binds_local_p (decl);
   if (!flag_shlib)
     {
@@ -4790,6 +5177,7 @@ decl_tls_model (tree decl)
       else
        kind = TLS_MODEL_INITIAL_EXEC;
     }
+
   /* Local dynamic is inefficient when we're not combining the
      parts of the address.  */
   else if (optimize && is_local)
@@ -4830,17 +5218,17 @@ default_section_type_flags_1 (tree decl, const char *name, int reloc,
           && cfun->unlikely_text_section_name
           && strcmp (name, cfun->unlikely_text_section_name) == 0)
     flags = SECTION_CODE;
-  else if (!decl 
+  else if (!decl
           && (!current_function_decl || !cfun)
           && strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
-    flags = SECTION_CODE; 
+    flags = SECTION_CODE;
   else
     flags = SECTION_WRITE;
 
   if (decl && DECL_ONE_ONLY (decl))
     flags |= SECTION_LINKONCE;
 
-  if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+  if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
     flags |= SECTION_TLS | SECTION_WRITE;
 
   if (strcmp (name, ".bss") == 0
@@ -4875,6 +5263,16 @@ default_section_type_flags_1 (tree decl, const char *name, int reloc,
   return flags;
 }
 
+/* Return true if the target supports some form of global BSS,
+   either through bss_noswitch_section, or by selecting a BSS
+   section in TARGET_ASM_SELECT_SECTION.  */
+
+bool
+have_global_bss_p (void)
+{
+  return bss_noswitch_section || targetm.have_switchable_bss_sections;
+}
+
 /* Output assembly to switch to section NAME with attribute FLAGS.
    Four variants for common object file formats.  */
 
@@ -4899,7 +5297,7 @@ default_elf_asm_named_section (const char *name, unsigned int flags,
      part of a COMDAT groups, in which case GAS requires the full
      declaration every time.  */
   if (!(HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
-      && ! named_section_first_declaration (name))
+      && (flags & SECTION_DECLARED))
     {
       fprintf (asm_out_file, "\t.section\t%s\n", name);
       return;
@@ -4947,7 +5345,7 @@ default_elf_asm_named_section (const char *name, unsigned int flags,
       if (flags & SECTION_ENTSIZE)
        fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
       if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
-       fprintf (asm_out_file, ",%s,comdat", 
+       fprintf (asm_out_file, ",%s,comdat",
                 lang_hooks.decls.comdat_group (decl));
     }
 
@@ -4955,7 +5353,7 @@ default_elf_asm_named_section (const char *name, unsigned int flags,
 }
 
 void
-default_coff_asm_named_section (const char *name, unsigned int flags, 
+default_coff_asm_named_section (const char *name, unsigned int flags,
                                tree decl ATTRIBUTE_UNUSED)
 {
   char flagchars[8], *f = flagchars;
@@ -4987,16 +5385,14 @@ default_pe_asm_named_section (const char *name, unsigned int flags,
 \f
 /* The lame default section selector.  */
 
-void
+section *
 default_select_section (tree decl, int reloc,
                        unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
-  bool readonly = false;
-
   if (DECL_P (decl))
     {
       if (decl_readonly_section (decl, reloc))
-       readonly = true;
+       return readonly_data_section;
     }
   else if (TREE_CODE (decl) == CONSTRUCTOR)
     {
@@ -5004,60 +5400,17 @@ default_select_section (tree decl, int reloc,
             || !TREE_READONLY (decl)
             || TREE_SIDE_EFFECTS (decl)
             || !TREE_CONSTANT (decl)))
-       readonly = true;
+       return readonly_data_section;
     }
   else if (TREE_CODE (decl) == STRING_CST)
-    readonly = true;
+    return readonly_data_section;
   else if (! (flag_pic && reloc))
-    readonly = true;
+    return readonly_data_section;
 
-  if (readonly)
-    readonly_data_section ();
-  else
-    data_section ();
+  return data_section;
 }
 
-/* A helper function for default_elf_select_section and
-   default_elf_unique_section.  Categorizes the DECL.  */
-
 enum section_category
-{
-  SECCAT_TEXT,
-
-  SECCAT_RODATA,
-  SECCAT_RODATA_MERGE_STR,
-  SECCAT_RODATA_MERGE_STR_INIT,
-  SECCAT_RODATA_MERGE_CONST,
-  SECCAT_SRODATA,
-
-  SECCAT_DATA,
-
-  /* To optimize loading of shared programs, define following subsections
-     of data section:
-       _REL    Contains data that has relocations, so they get grouped
-               together and dynamic linker will visit fewer pages in memory.
-       _RO     Contains data that is otherwise read-only.  This is useful
-               with prelinking as most relocations won't be dynamically
-               linked and thus stay read only.
-       _LOCAL  Marks data containing relocations only to local objects.
-               These relocations will get fully resolved by prelinking.  */
-  SECCAT_DATA_REL,
-  SECCAT_DATA_REL_LOCAL,
-  SECCAT_DATA_REL_RO,
-  SECCAT_DATA_REL_RO_LOCAL,
-
-  SECCAT_SDATA,
-  SECCAT_TDATA,
-
-  SECCAT_BSS,
-  SECCAT_SBSS,
-  SECCAT_TBSS
-};
-
-static enum section_category
-categorize_decl_for_section (tree, int, int);
-
-static enum section_category
 categorize_decl_for_section (tree decl, int reloc, int shlib)
 {
   enum section_category ret;
@@ -5073,12 +5426,7 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
     }
   else if (TREE_CODE (decl) == VAR_DECL)
     {
-      if (DECL_INITIAL (decl) == NULL
-         || DECL_INITIAL (decl) == error_mark_node
-         || (flag_zero_initialized_in_bss
-             /* Leave constant zeroes in .rodata so they can be shared.  */
-             && !TREE_READONLY (decl)
-             && initializer_zerop (DECL_INITIAL (decl))))
+      if (bss_initializer_p (decl))
        ret = SECCAT_BSS;
       else if (! TREE_READONLY (decl)
               || TREE_SIDE_EFFECTS (decl)
@@ -5118,7 +5466,7 @@ categorize_decl_for_section (tree decl, int reloc, int shlib)
     ret = SECCAT_RODATA;
 
   /* There are no read-only thread-local sections.  */
-  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
     {
       /* Note that this would be *just* SECCAT_BSS, except that there's
         no concept of a read-only thread-local-data section.  */
@@ -5170,14 +5518,14 @@ decl_readonly_section_1 (tree decl, int reloc, int shlib)
 
 /* Select a section based on the above categorization.  */
 
-void
+section *
 default_elf_select_section (tree decl, int reloc,
                            unsigned HOST_WIDE_INT align)
 {
-  default_elf_select_section_1 (decl, reloc, align, flag_pic);
+  return default_elf_select_section_1 (decl, reloc, align, flag_pic);
 }
 
-void
+section *
 default_elf_select_section_1 (tree decl, int reloc,
                              unsigned HOST_WIDE_INT align, int shlib)
 {
@@ -5188,23 +5536,18 @@ default_elf_select_section_1 (tree decl, int reloc,
       /* We're not supposed to be called on FUNCTION_DECLs.  */
       gcc_unreachable ();
     case SECCAT_RODATA:
-      readonly_data_section ();
-      return;
+      return readonly_data_section;
     case SECCAT_RODATA_MERGE_STR:
-      mergeable_string_section (decl, align, 0);
-      return;
+      return mergeable_string_section (decl, align, 0);
     case SECCAT_RODATA_MERGE_STR_INIT:
-      mergeable_string_section (DECL_INITIAL (decl), align, 0);
-      return;
+      return mergeable_string_section (DECL_INITIAL (decl), align, 0);
     case SECCAT_RODATA_MERGE_CONST:
-      mergeable_constant_section (DECL_MODE (decl), align, 0);
-      return;
+      return mergeable_constant_section (DECL_MODE (decl), align, 0);
     case SECCAT_SRODATA:
       sname = ".sdata2";
       break;
     case SECCAT_DATA:
-      data_section ();
-      return;
+      return data_section;
     case SECCAT_DATA_REL:
       sname = ".data.rel";
       break;
@@ -5224,13 +5567,10 @@ default_elf_select_section_1 (tree decl, int reloc,
       sname = ".tdata";
       break;
     case SECCAT_BSS:
-#ifdef BSS_SECTION_ASM_OP
-      bss_section ();
-      return;
-#else
+      if (bss_section)
+       return bss_section;
       sname = ".bss";
       break;
-#endif
     case SECCAT_SBSS:
       sname = ".sbss";
       break;
@@ -5243,7 +5583,7 @@ default_elf_select_section_1 (tree decl, int reloc,
 
   if (!DECL_P (decl))
     decl = NULL_TREE;
-  named_section (decl, sname, reloc);
+  return get_named_section (decl, sname, reloc);
 }
 
 /* Construct a unique section name based on the decl name and the
@@ -5279,11 +5619,20 @@ default_unique_section_1 (tree decl, int reloc, int shlib)
       prefix = one_only ? ".gnu.linkonce.s2." : ".sdata2.";
       break;
     case SECCAT_DATA:
+      prefix = one_only ? ".gnu.linkonce.d." : ".data.";
+      break;
     case SECCAT_DATA_REL:
+      prefix = one_only ? ".gnu.linkonce.d.rel." : ".data.rel.";
+      break;
     case SECCAT_DATA_REL_LOCAL:
+      prefix = one_only ? ".gnu.linkonce.d.rel.local." : ".data.rel.local.";
+      break;
     case SECCAT_DATA_REL_RO:
+      prefix = one_only ? ".gnu.linkonce.d.rel.ro." : ".data.rel.ro.";
+      break;
     case SECCAT_DATA_REL_RO_LOCAL:
-      prefix = one_only ? ".gnu.linkonce.d." : ".data.";
+      prefix = one_only ? ".gnu.linkonce.d.rel.ro.local."
+              : ".data.rel.ro.local.";
       break;
     case SECCAT_SDATA:
       prefix = one_only ? ".gnu.linkonce.s." : ".sdata.";
@@ -5316,7 +5665,7 @@ default_unique_section_1 (tree decl, int reloc, int shlib)
   DECL_SECTION_NAME (decl) = build_string (nlen + plen, string);
 }
 
-void
+section *
 default_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED,
                            rtx x,
                            unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
@@ -5327,17 +5676,16 @@ default_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED,
       case CONST:
       case SYMBOL_REF:
       case LABEL_REF:
-       data_section ();
-       return;
+       return data_section;
 
       default:
        break;
       }
 
-  readonly_data_section ();
+  return readonly_data_section;
 }
 
-void
+section *
 default_elf_select_rtx_section (enum machine_mode mode, rtx x,
                                unsigned HOST_WIDE_INT align)
 {
@@ -5348,18 +5696,16 @@ default_elf_select_rtx_section (enum machine_mode mode, rtx x,
       {
       case CONST:
       case SYMBOL_REF:
-       named_section (NULL_TREE, ".data.rel.ro", 3);
-       return;
+       return get_named_section (NULL, ".data.rel.ro", 3);
 
       case LABEL_REF:
-       named_section (NULL_TREE, ".data.rel.ro.local", 1);
-       return;
+       return get_named_section (NULL, ".data.rel.ro.local", 1);
 
       default:
        break;
       }
 
-  mergeable_constant_section (mode, align, 0);
+  return mergeable_constant_section (mode, align, 0);
 }
 
 /* Set the generally applicable flags on the SYMBOL_REF for EXP.  */
@@ -5377,13 +5723,13 @@ default_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
   if (GET_CODE (symbol) != SYMBOL_REF)
     return;
 
-  flags = 0;
+  flags = SYMBOL_REF_FLAGS (symbol) & SYMBOL_FLAG_HAS_BLOCK_INFO;
   if (TREE_CODE (decl) == FUNCTION_DECL)
     flags |= SYMBOL_FLAG_FUNCTION;
   if (targetm.binds_local_p (decl))
     flags |= SYMBOL_FLAG_LOCAL;
-  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
-    flags |= decl_tls_model (decl) << SYMBOL_FLAG_TLS_SHIFT;
+  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
+    flags |= DECL_TLS_MODEL (decl) << SYMBOL_FLAG_TLS_SHIFT;
   else if (targetm.in_small_data_p (decl))
     flags |= SYMBOL_FLAG_SMALL;
   /* ??? Why is DECL_EXTERNAL ever set for non-PUBLIC names?  Without
@@ -5404,6 +5750,59 @@ default_strip_name_encoding (const char *str)
   return str + (*str == '*');
 }
 
+#ifdef ASM_OUTPUT_DEF
+/* The default implementation of TARGET_ASM_OUTPUT_ANCHOR.  Define the
+   anchor relative to ".", the current section position.  */
+
+void
+default_asm_output_anchor (rtx symbol)
+{
+  char buffer[100];
+
+  sprintf (buffer, ". + " HOST_WIDE_INT_PRINT_DEC,
+          SYMBOL_REF_BLOCK_OFFSET (symbol));
+  ASM_OUTPUT_DEF (asm_out_file, XSTR (symbol, 0), buffer);
+}
+#endif
+
+/* The default implementation of TARGET_USE_ANCHORS_FOR_SYMBOL_P.  */
+
+bool
+default_use_anchors_for_symbol_p (rtx symbol)
+{
+  section *sect;
+  tree decl;
+
+  /* Don't use anchors for mergeable sections.  The linker might move
+     the objects around.  */
+  sect = SYMBOL_REF_BLOCK (symbol)->sect;
+  if (sect->common.flags & SECTION_MERGE)
+    return false;
+
+  /* Don't use anchors for small data sections.  The small data register
+     acts as an anchor for such sections.  */
+  if (sect->common.flags & SECTION_SMALL)
+    return false;
+
+  decl = SYMBOL_REF_DECL (symbol);
+  if (decl && DECL_P (decl))
+    {
+      /* Don't use section anchors for decls that might be defined by
+        other modules.  */
+      if (!targetm.binds_local_p (decl))
+       return false;
+
+      /* Don't use section anchors for decls that will be placed in a
+        small data section.  */
+      /* ??? Ideally, this check would be redundant with the SECTION_SMALL
+        one above.  The problem is that we only use SECTION_SMALL for
+        sections that should be marked as small in the section directive.  */
+      if (targetm.in_small_data_p (decl))
+       return false;
+    }
+  return true;
+}
+
 /* Assume ELF-ish defaults, since that's pretty much the most liberal
    wrt cross-module name binding.  */
 
@@ -5421,21 +5820,29 @@ default_binds_local_p_1 (tree exp, int shlib)
   /* A non-decl is an entry in the constant pool.  */
   if (!DECL_P (exp))
     local_p = true;
+  /* Weakrefs may not bind locally, even though the weakref itself is
+     always static and therefore local.  */
+  else if (lookup_attribute ("weakref", DECL_ATTRIBUTES (exp)))
+    local_p = false;
   /* Static variables are always local.  */
   else if (! TREE_PUBLIC (exp))
     local_p = true;
-  /* A variable is local if the user explicitly tells us so.  */
-  else if (DECL_VISIBILITY_SPECIFIED (exp) && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+  /* A variable is local if the user has said explicitly that it will
+     be.  */
+  else if (DECL_VISIBILITY_SPECIFIED (exp)
+          && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
     local_p = true;
-  /* Otherwise, variables defined outside this object may not be local.  */
+  /* Variables defined outside this object might not be local.  */
   else if (DECL_EXTERNAL (exp))
     local_p = false;
-  /* Linkonce and weak data are never local.  */
-  else if (DECL_ONE_ONLY (exp) || DECL_WEAK (exp))
-    local_p = false;
-  /* If none of the above and visibility is not default, make local.  */
+  /* If defined in this object and visibility is not default, must be
+     local.  */
   else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
     local_p = true;
+  /* Default visibility weak data can be overridden by a strong symbol
+     in another module and so are not local.  */
+  else if (DECL_WEAK (exp))
+    local_p = false;
   /* If PIC, then assume that any global name can be overridden by
      symbols resolved from other modules.  */
   else if (shlib)
@@ -5483,7 +5890,15 @@ default_emit_unwind_label (FILE * stream ATTRIBUTE_UNUSED,
                           tree decl ATTRIBUTE_UNUSED,
                           int for_eh ATTRIBUTE_UNUSED,
                           int empty ATTRIBUTE_UNUSED)
-{ 
+{
+}
+
+/* Default function to output a label to divide up the exception table.
+   The default is to do nothing.  A target that needs/wants to divide
+   up the table must provide it's own function to do this.  */
+void
+default_emit_except_table_label (FILE * stream ATTRIBUTE_UNUSED)
+{
 }
 
 /* This is how to output an internal numbered label where PREFIX is
@@ -5524,7 +5939,260 @@ file_end_indicate_exec_stack (void)
   if (trampolines_created)
     flags |= SECTION_CODE;
 
-  named_section_flags (".note.GNU-stack", flags);
+  switch_to_section (get_section (".note.GNU-stack", flags, NULL));
+}
+
+/* Output DIRECTIVE (a C string) followed by a newline.  This is used as
+   a get_unnamed_section callback.  */
+
+void
+output_section_asm_op (const void *directive)
+{
+  fprintf (asm_out_file, "%s\n", (const char *) directive);
+}
+
+/* Emit assembly code to switch to section NEW_SECTION.  Do nothing if
+   the current section is NEW_SECTION.  */
+
+void
+switch_to_section (section *new_section)
+{
+  if (in_section == new_section)
+    return;
+
+  if (new_section->common.flags & SECTION_FORGET)
+    in_section = NULL;
+  else
+    in_section = new_section;
+
+  switch (SECTION_STYLE (new_section))
+    {
+    case SECTION_NAMED:
+      if (cfun
+         && !cfun->unlikely_text_section_name
+         && strcmp (new_section->named.name,
+                    UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
+       cfun->unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
+
+      targetm.asm_out.named_section (new_section->named.name,
+                                    new_section->named.common.flags,
+                                    new_section->named.decl);
+      break;
+
+    case SECTION_UNNAMED:
+      new_section->unnamed.callback (new_section->unnamed.data);
+      break;
+
+    case SECTION_NOSWITCH:
+      gcc_unreachable ();
+      break;
+    }
+
+  new_section->common.flags |= SECTION_DECLARED;
+}
+
+/* If block symbol SYMBOL has not yet been assigned an offset, place
+   it at the end of its block.  */
+
+void
+place_block_symbol (rtx symbol)
+{
+  unsigned HOST_WIDE_INT size, mask, offset;
+  struct constant_descriptor_rtx *desc;
+  unsigned int alignment;
+  struct object_block *block;
+  tree decl;
+
+  gcc_assert (SYMBOL_REF_BLOCK (symbol));
+  if (SYMBOL_REF_BLOCK_OFFSET (symbol) >= 0)
+    return;
+
+  /* Work out the symbol's size and alignment.  */
+  if (CONSTANT_POOL_ADDRESS_P (symbol))
+    {
+      desc = SYMBOL_REF_CONSTANT (symbol);
+      alignment = desc->align;
+      size = GET_MODE_SIZE (desc->mode);
+    }
+  else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
+    {
+      decl = SYMBOL_REF_DECL (symbol);
+      alignment = get_constant_alignment (decl);
+      size = get_constant_size (decl);
+    }
+  else
+    {
+      decl = SYMBOL_REF_DECL (symbol);
+      alignment = DECL_ALIGN (decl);
+      size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+    }
+
+  /* Calculate the object's offset from the start of the block.  */
+  block = SYMBOL_REF_BLOCK (symbol);
+  mask = alignment / BITS_PER_UNIT - 1;
+  offset = (block->size + mask) & ~mask;
+  SYMBOL_REF_BLOCK_OFFSET (symbol) = offset;
+
+  /* Record the block's new alignment and size.  */
+  block->alignment = MAX (block->alignment, alignment);
+  block->size = offset + size;
+
+  VEC_safe_push (rtx, gc, block->objects, symbol);
+}
+
+/* Return the anchor that should be used to address byte offset OFFSET
+   from the first object in BLOCK.  MODEL is the TLS model used
+   to access it.  */
+
+rtx
+get_section_anchor (struct object_block *block, HOST_WIDE_INT offset,
+                   enum tls_model model)
+{
+  char label[100];
+  unsigned int begin, middle, end;
+  unsigned HOST_WIDE_INT min_offset, max_offset, range, bias, delta;
+  rtx anchor;
+
+  /* Work out the anchor's offset.  Use an offset of 0 for the first
+     anchor so that we don't pessimize the case where we take the address
+     of a variable at the beginning of the block.  This is particularly
+     useful when a block has only one variable assigned to it.
+
+     We try to place anchors RANGE bytes apart, so there can then be
+     anchors at +/-RANGE, +/-2 * RANGE, and so on, up to the limits of
+     a ptr_mode offset.  With some target settings, the lowest such
+     anchor might be out of range for the lowest ptr_mode offset;
+     likewise the highest anchor for the highest offset.  Use anchors
+     at the extreme ends of the ptr_mode range in such cases.
+
+     All arithmetic uses unsigned integers in order to avoid
+     signed overflow.  */
+  max_offset = (unsigned HOST_WIDE_INT) targetm.max_anchor_offset;
+  min_offset = (unsigned HOST_WIDE_INT) targetm.min_anchor_offset;
+  range = max_offset - min_offset + 1;
+  if (range == 0)
+    offset = 0;
+  else
+    {
+      bias = 1 << (GET_MODE_BITSIZE (ptr_mode) - 1);
+      if (offset < 0)
+       {
+         delta = -(unsigned HOST_WIDE_INT) offset + max_offset;
+         delta -= delta % range;
+         if (delta > bias)
+           delta = bias;
+         offset = (HOST_WIDE_INT) (-delta);
+       }
+      else
+       {
+         delta = (unsigned HOST_WIDE_INT) offset - min_offset;
+         delta -= delta % range;
+         if (delta > bias - 1)
+           delta = bias - 1;
+         offset = (HOST_WIDE_INT) delta;
+       }
+    }
+
+  /* Do a binary search to see if there's already an anchor we can use.
+     Set BEGIN to the new anchor's index if not.  */
+  begin = 0;
+  end = VEC_length (rtx, block->anchors);
+  while (begin != end)
+    {
+      middle = (end + begin) / 2;
+      anchor = VEC_index (rtx, block->anchors, middle);
+      if (SYMBOL_REF_BLOCK_OFFSET (anchor) > offset)
+       end = middle;
+      else if (SYMBOL_REF_BLOCK_OFFSET (anchor) < offset)
+       begin = middle + 1;
+      else if (SYMBOL_REF_TLS_MODEL (anchor) > model)
+       end = middle;
+      else if (SYMBOL_REF_TLS_MODEL (anchor) < model)
+       begin = middle + 1;
+      else
+       return anchor;
+    }
+
+  /* Create a new anchor with a unique label.  */
+  ASM_GENERATE_INTERNAL_LABEL (label, "LANCHOR", anchor_labelno++);
+  anchor = create_block_symbol (ggc_strdup (label), block, offset);
+  SYMBOL_REF_FLAGS (anchor) |= SYMBOL_FLAG_LOCAL | SYMBOL_FLAG_ANCHOR;
+  SYMBOL_REF_FLAGS (anchor) |= model << SYMBOL_FLAG_TLS_SHIFT;
+
+  /* Insert it at index BEGIN.  */
+  VEC_safe_insert (rtx, gc, block->anchors, begin, anchor);
+  return anchor;
+}
+
+/* Output the objects in BLOCK.  */
+
+static void
+output_object_block (struct object_block *block)
+{
+  struct constant_descriptor_rtx *desc;
+  unsigned int i;
+  HOST_WIDE_INT offset;
+  tree decl;
+  rtx symbol;
+
+  if (block->objects == NULL)
+    return;
+
+  /* Switch to the section and make sure that the first byte is
+     suitably aligned.  */
+  switch_to_section (block->sect);
+  assemble_align (block->alignment);
+
+  /* Define the values of all anchors relative to the current section
+     position.  */
+  for (i = 0; VEC_iterate (rtx, block->anchors, i, symbol); i++)
+    targetm.asm_out.output_anchor (symbol);
+
+  /* Output the objects themselves.  */
+  offset = 0;
+  for (i = 0; VEC_iterate (rtx, block->objects, i, symbol); i++)
+    {
+      /* Move to the object's offset, padding with zeros if necessary.  */
+      assemble_zeros (SYMBOL_REF_BLOCK_OFFSET (symbol) - offset);
+      offset = SYMBOL_REF_BLOCK_OFFSET (symbol);
+      if (CONSTANT_POOL_ADDRESS_P (symbol))
+       {
+         desc = SYMBOL_REF_CONSTANT (symbol);
+         output_constant_pool_1 (desc, 1);
+         offset += GET_MODE_SIZE (desc->mode);
+       }
+      else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
+       {
+         decl = SYMBOL_REF_DECL (symbol);
+         assemble_constant_contents (decl, XSTR (symbol, 0),
+                                     get_constant_alignment (decl));
+         offset += get_constant_size (decl);
+       }
+      else
+       {
+         decl = SYMBOL_REF_DECL (symbol);
+         assemble_variable_contents (decl, XSTR (symbol, 0), false);
+         offset += tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+       }
+    }
+}
+
+/* A htab_traverse callback used to call output_object_block for
+   each member of object_block_htab.  */
+
+static int
+output_object_block_htab (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+  output_object_block ((struct object_block *) (*slot));
+  return 1;
+}
+
+/* Output the definitions of all object_blocks.  */
+
+void
+output_object_blocks (void)
+{
+  htab_traverse (object_block_htab, output_object_block_htab, NULL);
 }
 
 #include "gt-varasm.h"