OSDN Git Service

* zh_CN.po: Update.
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index 1aee983..82c2df3 100644 (file)
@@ -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 *,
@@ -146,8 +143,36 @@ static bool asm_emit_uninitialised (tree, const char*,
                                    unsigned HOST_WIDE_INT);
 static void mark_weak (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;
+
+/* 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,25 +181,82 @@ 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.  */
+/* Helper routines for maintaining section_htab.  */
 
-struct in_named_entry GTY(())
+static int
+section_entry_eq (const void *p1, const void *p2)
 {
-  const char *name;
-  unsigned int flags;
-  bool declared;
-};
+  const section *old = p1;
+  const char *new = p2;
 
-static GTY((param_is (struct in_named_entry))) htab_t in_named_htab;
+  return strcmp (old->named.name, new) == 0;
+}
 
-/* Define functions like text_section for any extra sections.  */
-#ifdef EXTRA_SECTION_FUNCTIONS
-EXTRA_SECTION_FUNCTIONS
-#endif
+static hashval_t
+section_entry_hash (const void *p)
+{
+  const section *old = p;
+  return htab_hash_string (old->named.name);
+}
+
+/* Return a new unnamed section with the given fields.  */
+
+section *
+get_unnamed_section (unsigned int flags, void (*callback) (const void *),
+                    const void *data)
+{
+  section *sect;
+
+  sect = ggc_alloc (sizeof (struct unnamed_section));
+  sect->unnamed.common.flags = flags;
+  sect->unnamed.callback = callback;
+  sect->unnamed.data = data;
+  sect->unnamed.next = unnamed_sections;
+
+  unnamed_sections = sect;
+  return sect;
+}
+
+/* Return the named section structure associated with NAME.  Create
+   a new section with the given fields if no such structure exists.  */
+
+section *
+get_section (const char *name, unsigned int flags, tree decl)
+{
+  section *sect, **slot;
+
+  slot = (section **)
+    htab_find_slot_with_hash (section_htab, name,
+                             htab_hash_string (name), INSERT);
+  flags |= SECTION_NAMED;
+  if (*slot == NULL)
+    {
+      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
+    {
+      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;
+         if (decl)
+           error ("%+D causes a section type conflict", decl);
+         else
+           gcc_unreachable ();
+       }
+    }
+  return sect;
+}
 
 static void
 initialize_cold_section_name (void)
@@ -202,22 +284,9 @@ initialize_cold_section_name (void)
     cfun->unlikely_text_section_name =  UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
 }
 
-/* Tell assembler to switch to text section.  */
-
-void
-text_section (void)
-{
-  if (in_section != in_text)
-    {
-      in_section = in_text;
-      last_text_section = in_text;
-      fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
-    }
-}
-
 /* Tell assembler to switch to unlikely-to-be-executed text section.  */
 
-void
+section *
 unlikely_text_section (void)
 {
   if (cfun)
@@ -225,225 +294,42 @@ unlikely_text_section (void)
       if (!cfun->unlikely_text_section_name)
        initialize_cold_section_name ();
 
-      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;
-       }
+      return get_named_section (NULL, cfun->unlikely_text_section_name, 0);
     }
   else
-    {
-      named_section (NULL_TREE, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
-      in_section = in_unlikely_executed_text;
-      last_text_section = in_unlikely_executed_text;
-    }
-}
-
-/* Tell assembler to switch to data section.  */
-
-void
-data_section (void)
-{
-  if (in_section != in_data)
-    {
-      in_section = in_data;
-      fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
-    }
+    return get_named_section (NULL, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
 }
 
-/* Tell assembler to switch to read-only data section.  This is normally
-   the text section.  */
-
-void
-readonly_data_section (void)
-{
-#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
-}
-
-/* Determine if we're in the text section.  */
-
-int
-in_text_section (void)
-{
-  return in_section == in_text;
-}
-
-/* Determine if we're in the unlikely-to-be-executed text section.  */
-
-int
-in_unlikely_text_section (void)
-{
-  bool ret_val;
-
-  if (cfun)
-    {
-      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));
-    }
-  else
-    {
-      ret_val = ((in_section == in_unlikely_executed_text)
-                || (in_section == in_named
-                    && strcmp (in_named_name,
-                               UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0));
-    }
-
-  return ret_val;
-}
-
-/* Determine if we're in the data section.  */
-
-int
-in_data_section (void)
-{
-  return in_section == in_data;
-}
-
-/* Helper routines for maintaining in_named_htab.  */
-
-static int
-in_named_entry_eq (const void *p1, const void *p2)
-{
-  const struct in_named_entry *old = p1;
-  const char *new = p2;
-
-  return strcmp (old->name, new) == 0;
-}
-
-static hashval_t
-in_named_entry_hash (const void *p)
-{
-  const struct in_named_entry *old = p;
-  return htab_hash_string (old->name);
-}
-
-/* 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.  */
-
-static unsigned int
-get_named_section_flags (const char *section)
-{
-  struct in_named_entry **slot;
-
-  slot = (struct in_named_entry **)
-    htab_find_slot_with_hash (in_named_htab, section,
-                             htab_hash_string (section), NO_INSERT);
-
-  return slot ? (*slot)->flags : 0;
-}
-
-/* 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.  */
+/* 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.  */
 
 bool
-named_section_first_declaration (const char *name)
+unlikely_text_section_p (section *sect)
 {
-  struct in_named_entry **slot;
+  const char *name;
 
-  slot = (struct in_named_entry **)
-    htab_find_slot_with_hash (in_named_htab, name,
-                             htab_hash_string (name), NO_INSERT);
-  if (! (*slot)->declared)
-    {
-      (*slot)->declared = true;
-      return true;
-    }
+  if (cfun)
+    name = cfun->unlikely_text_section_name;
   else
-    {
-      return false;
-    }
-}
-
-
-/* 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)
-{
-  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)
-    {
-      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;
-
-  return true;
-}
-
-/* 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.  */
-
-void
-named_section_real (const char *name, unsigned int flags, tree decl)
-{
-  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);
-
-      if (flags & SECTION_FORGET)
-       in_section = no_section;
-      else
-       {
-         in_named_name = ggc_strdup (name);
-         in_section = in_named;
-       }
-    }
+    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
+         && (sect->common.flags & SECTION_NAMED) != 0
+         && 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 +337,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 +357,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 +371,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 +396,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,12 +412,28 @@ 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;
@@ -569,44 +442,29 @@ function_section (tree decl)
     reloc = 1;
   
 #ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
-  targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+  return 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);
-  else
-    text_section ();
+  return 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));
+  return targetm.asm_out.select_section (current_function_decl,
+                                        in_cold_section_p,
+                                        DECL_ALIGN (current_function_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);
-  else
-    function_section (decl);
+  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))
@@ -619,9 +477,8 @@ default_function_rodata_section (tree decl)
          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 +489,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,22 +500,21 @@ 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 ();
+  return readonly_data_section;
 }
 
 /* Switch to section for variable DECL.  RELOC is the same as the
@@ -669,14 +524,15 @@ void
 variable_section (tree decl, int reloc)
 {
   if (IN_NAMED_SECTION (decl))
-    named_section (decl, NULL, reloc);
+    switch_to_section (get_named_section (decl, NULL, reloc));
   else
-    targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+    switch_to_section (targetm.asm_out.select_section (decl, reloc,
+                                                      DECL_ALIGN (decl)));
 }
 
-/* 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 +575,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 +604,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.  */
@@ -955,8 +789,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
@@ -1091,28 +926,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 +976,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);
 }
@@ -1278,7 +1091,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 +1101,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;
@@ -1310,11 +1123,11 @@ assemble_start_function (tree decl, const char *fnname)
        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);
+  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);
@@ -1369,11 +1182,6 @@ assemble_start_function (tree decl, const char *fnname)
   /* Standard thing is just output label for the function.  */
   ASM_OUTPUT_LABEL (asm_out_file, fnname);
 #endif /* ASM_DECLARE_FUNCTION_NAME */
-
-  /* Add NOTE_INSN_SWITCH_TEXT_SECTIONS notes.  Don't do this if the current
-     function is a thunk, because we don't have a CFG in that case.  */
-  if (!current_function_is_thunk)
-    insert_section_boundary_note ();
 }
 
 /* Output assembler code associated with defining the size of the
@@ -1383,29 +1191,31 @@ void
 assemble_end_function (tree decl, const char *fnname)
 {
 #ifdef ASM_DECLARE_FUNCTION_SIZE
+  /* We could have switched section in the middle of the function.  */
+  if (flag_reorder_blocks_and_partition)
+    switch_to_section (function_section (decl));
   ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
 #endif
   if (! CONSTANT_POOL_BEFORE_FUNCTION)
     {
       output_constant_pool (fnname, decl);
-      function_section (decl); /* need to switch back */
+      switch_to_section (function_section (decl)); /* need to switch back */
     }
   /* Output labels for end of hot/cold text sections (to be used by
      debug info.)  */
   if (flag_reorder_blocks_and_partition)
     {
-      enum in_section save_text_section;
+      section *save_text_section;
 
       save_text_section = in_section;
-      unlikely_text_section ();
+      switch_to_section (unlikely_text_section ());
       ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_end_label);
       if (first_function_block_is_cold)
-       text_section ();
+       switch_to_section (text_section);
       else
-       function_section (decl);
+       switch_to_section (function_section (decl));
       ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_end_label);
-      if (save_text_section == in_unlikely_executed_text)
-       unlikely_text_section ();
+      switch_to_section (save_text_section);
     }
 }
 \f
@@ -1421,8 +1231,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++)
@@ -1791,7 +1600,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   variable_section (decl, reloc);
 
   /* dbxout.c needs to know this.  */
-  if (in_text_section () || in_unlikely_text_section ())
+  if (in_section && (in_section->common.flags & SECTION_CODE) != 0)
     DECL_IN_TEXT_SECTION (decl) = 1;
 
   /* Output the alignment of this data.  */
@@ -1997,6 +1806,31 @@ mark_decl_referenced (tree decl)
      which do not need to be marked.  */
 }
 
+
+/* Follow the IDENTIFIER_TRANSPARENT_ALIAS chain starting at *ALIAS
+   until we find an identifier that is not itself a transparent alias.
+   Modify the alias passed to it by reference (and all aliases on the
+   way to the ultimate target), such that they do not have to be
+   followed again, and return the ultimate target of the alias
+   chain.  */
+
+static inline tree
+ultimate_transparent_alias_target (tree *alias)
+{
+  tree target = *alias;
+
+  if (IDENTIFIER_TRANSPARENT_ALIAS (target))
+    {
+      gcc_assert (TREE_CHAIN (target));
+      target = ultimate_transparent_alias_target (&TREE_CHAIN (target));
+      gcc_assert (! IDENTIFIER_TRANSPARENT_ALIAS (target)
+                 && ! TREE_CHAIN (target));
+      *alias = target;
+    }
+
+  return target;
+}
+
 /* Output to FILE (an assembly file) a reference to NAME.  If NAME
    starts with a *, the rest of NAME is output verbatim.  Otherwise
    NAME is transformed in a target-specific way (usually by the
@@ -2026,7 +1860,15 @@ assemble_name (FILE *file, const char *name)
 
   id = maybe_get_identifier (real_name);
   if (id)
-    mark_referenced (id);
+    {
+      tree id_orig = id;
+
+      mark_referenced (id);
+      ultimate_transparent_alias_target (&id);
+      if (id != id_orig)
+       name = IDENTIFIER_POINTER (id);
+      gcc_assert (! TREE_CHAIN (id));
+    }
 
   assemble_name_raw (file, name);
 }
@@ -2043,7 +1885,7 @@ assemble_static_space (unsigned HOST_WIDE_INT size)
 
 #if 0
   if (flag_shared_data)
-    data_section ();
+    switch_to_section (data_section);
 #endif
 
   ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno);
@@ -2096,9 +1938,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.  */
@@ -2841,9 +2683,9 @@ output_constant_def_contents (rtx symbol)
   TREE_ASM_WRITTEN (exp) = 1;
 
   if (IN_NAMED_SECTION (exp))
-    named_section (exp, NULL, reloc);
+    switch_to_section (get_named_section (exp, NULL, reloc));
   else
-    targetm.asm_out.select_section (exp, reloc, align);
+    switch_to_section (targetm.asm_out.select_section (exp, reloc, align));
 
   if (align > BITS_PER_UNIT)
     {
@@ -3314,7 +3156,8 @@ output_constant_pool_1 (struct constant_descriptor_rtx *desc)
     }
 
   /* First switch to correct section.  */
-  targetm.asm_out.select_rtx_section (desc->mode, x, desc->align);
+  switch_to_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,
@@ -3332,8 +3175,8 @@ output_constant_pool_1 (struct constant_descriptor_rtx *desc)
   /* 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)
+      && in_section
+      && (in_section->common.flags & SECTION_MERGE))
     assemble_align (desc->align);
 
 #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
@@ -4466,35 +4309,120 @@ declare_weak (tree decl)
   mark_weak (decl);
 }
 
-/* Emit any pending weak declarations.  */
-
-void
-weak_finish (void)
+static void
+weak_finish_1 (tree decl)
 {
-  tree t;
-
-  for (t = weak_decls; t; t = TREE_CHAIN (t))
-    {
-      tree decl = TREE_VALUE (t);
 #if defined (ASM_WEAKEN_DECL) || defined (ASM_WEAKEN_LABEL)
-      const char *const name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  const char *const name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
 #endif
 
-      if (! TREE_USED (decl))
-       continue;
+  if (! TREE_USED (decl))
+    return;
 
 #ifdef ASM_WEAKEN_DECL
-      ASM_WEAKEN_DECL (asm_out_file, decl, name, NULL);
+  ASM_WEAKEN_DECL (asm_out_file, decl, name, NULL);
 #else
 #ifdef ASM_WEAKEN_LABEL
-      ASM_WEAKEN_LABEL (asm_out_file, name);
+  ASM_WEAKEN_LABEL (asm_out_file, name);
 #else
 #ifdef ASM_OUTPUT_WEAK_ALIAS
-      warning (0, "only weak aliases are supported in this configuration");
-      return;
+  {
+    static bool warn_once = 0;
+    if (! warn_once)
+      {
+       warning (0, "only weak aliases are supported in this configuration");
+       warn_once = 1;
+      }
+    return;
+  }
 #endif
 #endif
 #endif
+}
+
+/* This TREE_LIST contains weakref targets.  */
+
+static GTY(()) tree weakref_targets;
+
+/* Forward declaration.  */
+static tree find_decl_and_mark_needed (tree decl, tree target);
+
+/* Emit any pending weak declarations.  */
+
+void
+weak_finish (void)
+{
+  tree t;
+
+  for (t = weakref_targets; t; t = TREE_CHAIN (t))
+    {
+      tree alias_decl = TREE_PURPOSE (t);
+      tree target = ultimate_transparent_alias_target (&TREE_VALUE (t));
+
+      if (! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias_decl)))
+       /* Remove alias_decl from the weak list, but leave entries for
+          the target alone.  */
+       target = NULL_TREE;
+#ifndef ASM_OUTPUT_WEAKREF
+      else if (! TREE_SYMBOL_REFERENCED (target))
+       {
+         /* Use ASM_WEAKEN_LABEL only if ASM_WEAKEN_DECL is not
+            defined, otherwise we and weak_finish_1 would use a
+            different macros.  */
+# if defined ASM_WEAKEN_LABEL && ! defined ASM_WEAKEN_DECL
+         ASM_WEAKEN_LABEL (asm_out_file, IDENTIFIER_POINTER (target));
+# else
+         tree decl = find_decl_and_mark_needed (alias_decl, target);
+
+         if (! decl)
+           {
+             decl = build_decl (TREE_CODE (alias_decl), target,
+                                TREE_TYPE (alias_decl));
+
+             DECL_EXTERNAL (decl) = 1;
+             TREE_PUBLIC (decl) = 1;
+             DECL_ARTIFICIAL (decl) = 1;
+             TREE_NOTHROW (decl) = TREE_NOTHROW (alias_decl);
+             TREE_USED (decl) = 1;
+           }
+
+         weak_finish_1 (decl);
+# endif
+       }
+#endif
+
+      {
+       tree *p;
+       tree t2;
+
+       /* Remove the alias and the target from the pending weak list
+          so that we do not emit any .weak directives for the former,
+          nor multiple .weak directives for the latter.  */
+       for (p = &weak_decls; (t2 = *p) ; )
+         {
+           if (TREE_VALUE (t2) == alias_decl
+               || target == DECL_ASSEMBLER_NAME (TREE_VALUE (t2)))
+             *p = TREE_CHAIN (t2);
+           else
+             p = &TREE_CHAIN (t2);
+         }
+
+       /* Remove other weakrefs to the same target, to speed things up.  */
+       for (p = &TREE_CHAIN (t); (t2 = *p) ; )
+         {
+           if (target == ultimate_transparent_alias_target (&TREE_VALUE (t2)))
+             *p = TREE_CHAIN (t2);
+           else
+             p = &TREE_CHAIN (t2);
+         }
+      }
+    }
+
+  for (t = weak_decls; t; t = TREE_CHAIN (t))
+    {
+      tree decl = TREE_VALUE (t);
+
+      weak_finish_1 (decl);
     }
 }
 
@@ -4525,6 +4453,18 @@ globalize_decl (tree decl)
          else
            p = &TREE_CHAIN (t);
        }
+
+       /* Remove weakrefs to the same target from the pending weakref
+          list, for the same reason.  */
+       for (p = &weakref_targets; (t = *p) ; )
+         {
+           if (DECL_ASSEMBLER_NAME (decl)
+               == ultimate_transparent_alias_target (&TREE_VALUE (t)))
+             *p = TREE_CHAIN (t);
+           else
+             p = &TREE_CHAIN (t);
+         }
+
       return;
     }
 #elif defined(ASM_MAKE_LABEL_LINKONCE)
@@ -4560,27 +4500,28 @@ find_decl_and_mark_needed (tree decl, tree target)
   struct cgraph_node *fnode = NULL;
   struct cgraph_varpool_node *vnode = NULL;
 
-  /* C++ thunk emitting code produces aliases late in the game.
-     Avoid confusing cgraph code in that case.  */
-  if (!cgraph_global_info_ready)
+  if (TREE_CODE (decl) == FUNCTION_DECL)
     {
-      if (TREE_CODE (decl) == FUNCTION_DECL)
-       {
-         fnode = cgraph_node_for_asm (target);
-         if (fnode == NULL)
-           vnode = cgraph_varpool_node_for_asm (target);
-       }
-      else
-       {
-         vnode = cgraph_varpool_node_for_asm (target);
-         if (vnode == NULL)
-           fnode = cgraph_node_for_asm (target);
-       }
+      fnode = cgraph_node_for_asm (target);
+      if (fnode == NULL)
+       vnode = cgraph_varpool_node_for_asm (target);
+    }
+  else
+    {
+      vnode = cgraph_varpool_node_for_asm (target);
+      if (vnode == NULL)
+       fnode = cgraph_node_for_asm (target);
     }
 
   if (fnode)
     {
-      cgraph_mark_needed_node (fnode);
+      /* We can't mark function nodes as used after cgraph global info
+        is finished.  This wouldn't generally be necessary, but C++
+        virtual table thunks are introduced late in the game and
+        might seem like they need marking, although in fact they
+        don't.  */
+      if (! cgraph_global_info_ready)
+       cgraph_mark_needed_node (fnode);
       return fnode->decl;
     }
   else if (vnode)
@@ -4597,7 +4538,7 @@ find_decl_and_mark_needed (tree decl, tree target)
    tree node is DECL to have the value of the tree node TARGET.  */
 
 static void
-do_assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
+do_assemble_alias (tree decl, tree target)
 {
   if (TREE_ASM_WRITTEN (decl))
     return;
@@ -4605,6 +4546,27 @@ do_assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
   TREE_ASM_WRITTEN (decl) = 1;
   TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
 
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+    {
+      ultimate_transparent_alias_target (&target);
+
+      if (!TREE_SYMBOL_REFERENCED (target))
+       weakref_targets = tree_cons (decl, target, weakref_targets);
+
+#ifdef ASM_OUTPUT_WEAKREF
+      ASM_OUTPUT_WEAKREF (asm_out_file, decl,
+                         IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+                         IDENTIFIER_POINTER (target));
+#else
+      if (!SUPPORTS_WEAK)
+       {
+         error ("%Jweakref is not supported in this configuration", decl);
+         return;
+       }
+#endif
+      return;
+    }
+
 #ifdef ASM_OUTPUT_DEF
   /* Make name accessible from other files, if appropriate.  */
 
@@ -4639,6 +4601,17 @@ do_assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
        *p = TREE_CHAIN (t);
       else
        p = &TREE_CHAIN (t);
+
+    /* Remove weakrefs to the same target from the pending weakref
+       list, for the same reason.  */
+    for (p = &weakref_targets; (t = *p) ; )
+      {
+       if (DECL_ASSEMBLER_NAME (decl)
+           == ultimate_transparent_alias_target (&TREE_VALUE (t)))
+         *p = TREE_CHAIN (t);
+       else
+         p = &TREE_CHAIN (t);
+      }
   }
 #endif
 }
@@ -4658,9 +4631,13 @@ finish_aliases_1 (void)
 
       target_decl = find_decl_and_mark_needed (p->decl, p->target);
       if (target_decl == NULL)
-       error ("%q+D aliased to undefined symbol %qs",
-              p->decl, IDENTIFIER_POINTER (p->target));
-      else if (DECL_EXTERNAL (target_decl))
+       {
+         if (! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
+           error ("%q+D aliased to undefined symbol %qs",
+                  p->decl, IDENTIFIER_POINTER (p->target));
+       }
+      else if (DECL_EXTERNAL (target_decl)
+              && ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
        error ("%q+D aliased to external symbol %qs",
               p->decl, IDENTIFIER_POINTER (p->target));
     }
@@ -4689,19 +4666,43 @@ void
 assemble_alias (tree decl, tree target)
 {
   tree target_decl;
+  bool is_weakref = false;
+
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+    {
+      tree alias = DECL_ASSEMBLER_NAME (decl);
+
+      is_weakref = true;
+
+      ultimate_transparent_alias_target (&target);
 
+      if (alias == target)
+       error ("weakref %q+D ultimately targets itself", decl);
+      else
+       {
+#ifndef ASM_OUTPUT_WEAKREF
+         IDENTIFIER_TRANSPARENT_ALIAS (alias) = 1;
+         TREE_CHAIN (alias) = target;
+#endif
+       }
+      if (TREE_PUBLIC (decl))
+       error ("weakref %q+D must have static linkage", decl);
+    }
+  else
+    {
 #if !defined (ASM_OUTPUT_DEF)
 # if !defined(ASM_OUTPUT_WEAK_ALIAS) && !defined (ASM_WEAKEN_DECL)
-  error ("%Jalias definitions not supported in this configuration", decl);
-  return;
-# else
-  if (!DECL_WEAK (decl))
-    {
-      error ("%Jonly weak aliases are supported in this configuration", decl);
+      error ("%Jalias definitions not supported in this configuration", decl);
       return;
-    }
+# else
+      if (!DECL_WEAK (decl))
+       {
+         error ("%Jonly weak aliases are supported in this configuration", decl);
+         return;
+       }
 # endif
 #endif
+    }
 
   /* We must force creation of DECL_RTL for debug info generation, even though
      we don't use it here.  */
@@ -4711,7 +4712,8 @@ assemble_alias (tree decl, tree target)
   /* A quirk of the initial implementation of aliases required that the user
      add "extern" to all of them.  Which is silly, but now historical.  Do
      note that the symbol is in fact locally defined.  */
-  DECL_EXTERNAL (decl) = 0;
+  if (! is_weakref)
+    DECL_EXTERNAL (decl) = 0;
 
   /* Allow aliases to aliases.  */
   if (TREE_CODE (decl) == FUNCTION_DECL)
@@ -4812,12 +4814,59 @@ 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);
   const_desc_htab = htab_create_ggc (1009, const_desc_hash,
                                     const_desc_eq, NULL);
 
   const_alias_set = new_alias_set ();
+
+#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
+
+  targetm.asm_out.init_sections ();
+
+  if (readonly_data_section == NULL)
+    readonly_data_section = text_section;
 }
 
 enum tls_model
@@ -4944,7 +4993,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;
@@ -5032,16 +5081,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)
     {
@@ -5049,17 +5096,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
@@ -5175,14 +5219,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)
 {
@@ -5193,23 +5237,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;
@@ -5229,13 +5268,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;
@@ -5248,7 +5284,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
@@ -5284,11 +5320,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.";
@@ -5321,7 +5366,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)
@@ -5332,17 +5377,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)
 {
@@ -5353,18 +5397,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.  */
@@ -5426,21 +5468,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)
@@ -5529,7 +5579,48 @@ 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;
+
+  if (new_section->common.flags & 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);
+    }
+  else
+    new_section->unnamed.callback (new_section->unnamed.data);
+
+  new_section->common.flags |= SECTION_DECLARED;
 }
 
 #include "gt-varasm.h"