OSDN Git Service

* zh_CN.po: Update.
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index e937e65..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;
-       }
-    }
-  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);
-    }
-}
-
-/* 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));
+      return get_named_section (NULL, 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;
+    return get_named_section (NULL, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 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;
-    }
-}
+    name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
 
-
-/* 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;
+  return (name
+         && sect
+         && (sect->common.flags & SECTION_NAMED) != 0
+         && strcmp (name, sect->named.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.  */
+/* 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_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;
-       }
-    }
-
-  if (in_text_section () || in_unlikely_text_section ())
-    {
-      last_text_section = in_section;
-      last_text_section_name = name;
-    }
-}
-
-/* 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.  */
-
-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);
@@ -1380,30 +1193,29 @@ 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)
-    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 +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++)
@@ -1789,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.  */
@@ -1995,6 +1806,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)
 {
@@ -2042,9 +1861,12 @@ assemble_name (FILE *file, const char *name)
   id = maybe_get_identifier (real_name);
   if (id)
     {
+      tree id_orig = id;
+
       mark_referenced (id);
       ultimate_transparent_alias_target (&id);
-      name = IDENTIFIER_POINTER (id);
+      if (id != id_orig)
+       name = IDENTIFIER_POINTER (id);
       gcc_assert (! TREE_CHAIN (id));
     }
 
@@ -2063,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);
@@ -2116,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.  */
@@ -2861,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)
     {
@@ -3334,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,
@@ -3352,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
@@ -4496,10 +4319,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
@@ -4547,7 +4366,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);
@@ -4732,7 +4554,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
@@ -4863,6 +4685,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
     {
@@ -4990,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
@@ -5122,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;
@@ -5210,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)
     {
@@ -5227,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
@@ -5353,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)
 {
@@ -5371,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;
@@ -5407,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;
@@ -5426,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
@@ -5462,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.";
@@ -5499,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)
@@ -5510,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)
 {
@@ -5531,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.  */
@@ -5604,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)
@@ -5707,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"