OSDN Git Service

* builtins.c (dummy_object): Use build_int_cst instead of convert.
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index ac511f6..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.
@@ -127,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 *,
@@ -141,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
@@ -156,294 +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 *stripped_name;
-  char *name, *buffer;
-  tree dsn;
-
-  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)
-    {
-      name = alloca (TREE_STRING_LENGTH (dsn) + 1);
-      memcpy (name, TREE_STRING_POINTER (dsn), TREE_STRING_LENGTH (dsn) + 1);
+  const section *old = p1;
+  const char *new = p2;
 
-      stripped_name = targetm.strip_name_encoding (name);
+  return strcmp (old->named.name, new) == 0;
+}
 
-      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;
+
+  gcc_assert (cfun && current_function_decl);
+  if (cfun->unlikely_text_section_name)
+    return;
 
-  slot = (struct in_named_entry **)
-    htab_find_slot_with_hash (in_named_htab, name,
-                             htab_hash_string (name), NO_INSERT);
-  if (! (*slot)->declared)
+  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;
 
@@ -451,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 ("%+D causes a section type conflict", decl);
-    }
-
-  named_section_real (name, flags, decl);
+  return get_section (name, flags, decl);
 }
 
 /* If required, set DECL_SECTION_NAME to a unique name.  */
@@ -488,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
@@ -514,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);
@@ -539,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;
@@ -555,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))
@@ -617,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)
@@ -632,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
@@ -644,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)
@@ -719,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)
@@ -768,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.  */
@@ -862,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.
@@ -888,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);
@@ -898,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;
@@ -915,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);
@@ -923,11 +1005,11 @@ make_decl_rtl (tree decl)
     }
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  
+
   if (name[0] != '*' && TREE_CODE (decl) != FUNCTION_DECL
       && DECL_REGISTER (decl))
     {
-      error ("register name not specified for %q+D", decl);    
+      error ("register name not specified for %q+D", decl);
     }
   else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
     {
@@ -955,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
@@ -1010,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)
@@ -1091,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);
 }
@@ -1152,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);
 }
@@ -1199,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
@@ -1240,7 +1305,7 @@ 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)
     {
@@ -1278,7 +1343,7 @@ 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);
 
@@ -1288,7 +1353,7 @@ assemble_start_function (tree decl, const char *fnname)
       if (!current_function_is_thunk
          && BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
        {
-         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;
@@ -1304,18 +1369,18 @@ assemble_start_function (tree decl, const char *fnname)
 
       initialize_cold_section_name ();
 
-      if (cfun->unlikely_text_section_name 
+      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);
 
@@ -1375,35 +1440,34 @@ assemble_start_function (tree decl, const char *fnname)
    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)
-    function_section (decl);
+    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
@@ -1419,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++)
@@ -1467,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.  */
+
+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 */
 
-  switch (destination)
+  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.
@@ -1603,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);
@@ -1674,7 +1755,10 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
       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);
 
@@ -1722,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_P (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, "requested alignment for %q+D is greater than "
-                 "implemented alignment of %wu", 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);
     }
 }
 
@@ -1995,6 +2015,14 @@ 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)
 {
@@ -2064,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);
@@ -2119,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.  */
@@ -2261,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;
 
@@ -2440,13 +2463,13 @@ const_hash_1 (const tree exp)
       {
        unsigned HOST_WIDE_INT idx;
        tree value;
-       
+
        hi = 5 + int_size_in_bytes (TREE_TYPE (exp));
-       
+
        FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
          if (value)
            hi = hi * 603 + const_hash_1 (value);
-       
+
        return hi;
       }
 
@@ -2533,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:
@@ -2558,7 +2583,7 @@ compare_constant (const tree t1, const tree t2)
       {
        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;
@@ -2606,7 +2631,7 @@ compare_constant (const tree t1, const tree t2)
                  return 0;
              }
          }
-       
+
        return 1;
       }
 
@@ -2694,7 +2719,7 @@ copy_constant (tree exp)
        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)
@@ -2710,13 +2735,53 @@ copy_constant (tree exp)
     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.
@@ -2745,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);
@@ -2839,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);
 }
@@ -2925,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).  */
@@ -2966,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
@@ -3068,28 +3125,35 @@ const_rtx_hash (rtx x)
   return h;
 }
 
-\f
+\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
@@ -3109,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;
@@ -3120,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);
@@ -3170,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);
@@ -3193,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
@@ -3220,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.  */
@@ -3258,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);
@@ -3295,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)
@@ -3336,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:
@@ -3370,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)
@@ -3380,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))
@@ -3398,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
@@ -3406,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;
@@ -3422,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
@@ -3434,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
@@ -3656,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_DLLIMPORT_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:
@@ -3719,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))
@@ -3898,6 +3993,11 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
         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
@@ -3949,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:
@@ -3994,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)
@@ -4038,7 +4137,7 @@ array_size_for_constructor (tree val)
 {
   tree max_index, i;
   unsigned HOST_WIDE_INT cnt;
-  tree index, value;
+  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
@@ -4059,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))));
@@ -4127,8 +4226,8 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
 #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
@@ -4499,10 +4598,6 @@ weak_finish_1 (tree decl)
   if (! TREE_USED (decl))
     return;
 
-  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
-      && lookup_attribute ("alias", DECL_ATTRIBUTES (decl)))
-    return;
-
 #ifdef ASM_WEAKEN_DECL
   ASM_WEAKEN_DECL (asm_out_file, decl, name, NULL);
 #else
@@ -4550,7 +4645,10 @@ weak_finish (void)
 #ifndef ASM_OUTPUT_WEAKREF
       else if (! TREE_SYMBOL_REFERENCED (target))
        {
-# ifdef ASM_WEAKEN_LABEL
+         /* 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);
@@ -4710,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;
 }
 
@@ -4735,7 +4833,7 @@ do_assemble_alias (tree decl, tree target)
        weakref_targets = tree_cons (decl, target, weakref_targets);
 
 #ifdef ASM_OUTPUT_WEAKREF
-      ASM_OUTPUT_WEAKREF (asm_out_file,
+      ASM_OUTPUT_WEAKREF (asm_out_file, decl,
                          IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
                          IDENTIFIER_POINTER (target));
 #else
@@ -4866,6 +4964,8 @@ assemble_alias (tree decl, tree target)
          TREE_CHAIN (alias) = target;
 #endif
        }
+      if (TREE_PUBLIC (decl))
+       error ("weakref %q+D must have static linkage", decl);
     }
   else
     {
@@ -4993,12 +5093,74 @@ 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;
 }
 
 enum tls_model
@@ -5056,10 +5218,10 @@ 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;
 
@@ -5101,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.  */
 
@@ -5125,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;
@@ -5173,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));
     }
 
@@ -5181,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;
@@ -5213,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)
     {
@@ -5230,17 +5400,14 @@ 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;
 }
 
 enum section_category
@@ -5259,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)
@@ -5356,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)
 {
@@ -5374,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;
@@ -5410,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;
@@ -5429,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
@@ -5465,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.";
@@ -5502,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)
@@ -5513,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)
 {
@@ -5534,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.  */
@@ -5563,7 +5723,7 @@ 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))
@@ -5590,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.  */
 
@@ -5607,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)
@@ -5669,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
@@ -5710,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"