Patchwork Fix section flags conflict handling (PR middle-end/31490)

login
register
mail settings
Submitter Jakub Jelinek
Date Jan. 27, 2011, 8:47 p.m.
Message ID <20110127204734.GQ2724@tyan-ft48-01.lab.bos.redhat.com>
Download mbox | patch
Permalink /patch/80738/
State New
Headers show

Comments

Jakub Jelinek - Jan. 27, 2011, 8:47 p.m.
Hi!

Attached are two versions of a patch to revert the IMHO incorrect fix
for this PR and instead silently accept merging of read-only
and writable only because of relocations section flags into writable
only because of relocations.

The problem with ignoring the reloc rw mask for named section
is that gcc uses then wrong section flags e.g. while compiling glibc
nscd (which is compiled using -fpie) - the binary is then DT_TEXTREL,
which is undesirable for security reasons and is often rejected e.g. by
SELinux.

For -O+ (and without -fno-toplevel-reorder) both patches ought to behave
the same, the only difference is for -O0 where the first patch
reports section conflict errors erratically (the order of
get_variable_section calls depends on varpool needed queue order), while
the second patch tries harder and calls them in the declared order, so if
there are two conflicting decls, the error is reported on the second one
and never the first one.

Both patches were bootstrapped/regtested on x86_64-linux and i686-linux,
ok for trunk?  Which one?

	Jakub
2011-01-27  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/31490
	* output.h (SECTION_RELRO): Define.
	(SECTION_MACH_DEP): Adjust.
	(get_variable_section): New prototype.
	* config/darwin.h (SECTION_NO_ANCHOR): Adjust.
	* varpool.c (varpool_finalize_named_section_flags): New function.
	(varpool_assemble_pending_decls): Call it.
	* cgraph.h (varpool_finalize_named_section_flags): New prototype.
	* cgraphunit.c (cgraph_output_in_order): Call
	varpool_finalize_named_section_flags.
	* varasm.c (get_section): Allow section flags conflicts between
	relro and read-only sections if the section hasn't been declared yet.
	Set SECTION_OVERRIDE after diagnosing section type conflict.
	(get_variable_section): No longer static.
	(default_section_type_flags): Use SECTION_WRITE | SECTION_RELRO for
	readonly sections that need relocations.
	(decl_readonly_section_1): New function.
	(decl_readonly_section): Use it.

	Revert:
	2010-11-17  Dinar Temirbulatov <dtemirbulatov@gmail.com>
		    Steve Ellcey  <sje@cup.hp.com>

	PR middle-end/31490
	* varasm.c (categorize_decl_for_section): Ignore reloc_rw_mask
	if section attribute used.

	* gcc.dg/pr31490-2.c: New test.
	* gcc.dg/pr31490-3.c: New test.
	* gcc.dg/pr31490-4.c: New test.
	* gcc.dg/20051207-3.c: Adjust expected error line.
	* gcc.dg/tls/section-1.c: Likewise.
2011-01-27  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/31490
	* output.h (SECTION_RELRO): Define.
	(SECTION_MACH_DEP): Adjust.
	(get_variable_section): New prototype.
	* config/darwin.h (SECTION_NO_ANCHOR): Adjust.
	* varpool.c (varpool_finalize_named_section_flags): New function.
	(varpool_assemble_pending_decls): Call it.
	* cgraph.h (varpool_finalize_named_section_flags): New prototype.
	* cgraphunit.c (cgraph_output_in_order): Call
	varpool_finalize_named_section_flags.
	* varasm.c (get_section): Allow section flags conflicts between
	relro and read-only sections if the section hasn't been declared yet.
	Set SECTION_OVERRIDE after diagnosing section type conflict.
	(get_variable_section): No longer static.
	(default_section_type_flags): Use SECTION_WRITE | SECTION_RELRO for
	readonly sections that need relocations.
	(decl_readonly_section_1): New function.
	(decl_readonly_section): Use it.

	Revert:
	2010-11-17  Dinar Temirbulatov <dtemirbulatov@gmail.com>
		    Steve Ellcey  <sje@cup.hp.com>

	PR middle-end/31490
	* varasm.c (categorize_decl_for_section): Ignore reloc_rw_mask
	if section attribute used.

	* gcc.dg/pr31490-2.c: New test.
	* gcc.dg/pr31490-3.c: New test.
	* gcc.dg/pr31490-4.c: New test.

--- gcc/output.h.jj	2011-01-27 17:33:28.200496345 +0100
+++ gcc/output.h	2011-01-27 17:40:33.355649071 +0100
@@ -441,7 +441,8 @@ extern void no_asm_to_stream (FILE *);
 #define SECTION_DECLARED 0x100000	/* section has been used */
 #define SECTION_STYLE_MASK 0x600000	/* bits used for SECTION_STYLE */
 #define SECTION_COMMON   0x800000	/* contains common data */
-#define SECTION_MACH_DEP 0x1000000	/* subsequent bits reserved for target */
+#define SECTION_RELRO	 0x1000000	/* data is readonly after relocation processing */
+#define SECTION_MACH_DEP 0x2000000	/* subsequent bits reserved for target */
 
 /* This SECTION_STYLE is used for unnamed sections that we can switch
    to using a special assembler directive.  */
@@ -585,6 +586,7 @@ extern section *get_unnamed_section (uns
 				     const void *);
 extern section *get_section (const char *, unsigned int, tree);
 extern section *get_named_section (tree, const char *, int);
+extern section *get_variable_section (tree, bool);
 extern void place_block_symbol (rtx);
 extern rtx get_section_anchor (struct object_block *, HOST_WIDE_INT,
 			       enum tls_model);
--- gcc/varpool.c.jj	2011-01-27 17:33:28.229830104 +0100
+++ gcc/varpool.c	2011-01-27 19:48:24.567639053 +0100
@@ -565,11 +565,29 @@ varpool_remove_unreferenced_decls (void)
   varpool_analyze_pending_decls ();
 }
 
+/* For variables in named sections make sure get_variable_section
+   is called before we switch to those sections.  Then section
+   conflicts between read-only and read-only requiring relocations
+   sections can be resolved.  */
+void
+varpool_finalize_named_section_flags (struct varpool_node *node)
+{
+  if (!TREE_ASM_WRITTEN (node->decl)
+      && !node->alias
+      && !node->in_other_partition
+      && !DECL_EXTERNAL (node->decl)
+      && TREE_CODE (node->decl) == VAR_DECL
+      && !DECL_HAS_VALUE_EXPR_P (node->decl)
+      && DECL_SECTION_NAME (node->decl))
+    get_variable_section (node->decl, false);
+}
+
 /* Output all variables enqueued to be assembled.  */
 bool
 varpool_assemble_pending_decls (void)
 {
   bool changed = false;
+  struct varpool_node *node;
 
   if (seen_error ())
     return false;
@@ -580,6 +598,9 @@ varpool_assemble_pending_decls (void)
      elsewhere.  */
   varpool_analyze_pending_decls ();
 
+  for (node = varpool_nodes_queue; node; node = node->next_needed)
+    varpool_finalize_named_section_flags (node);
+
   while (varpool_nodes_queue)
     {
       struct varpool_node *node = varpool_nodes_queue;
--- gcc/config/darwin.h.jj	2011-01-27 17:33:28.217391021 +0100
+++ gcc/config/darwin.h	2011-01-27 17:40:33.356655497 +0100
@@ -654,7 +654,7 @@ int darwin_label_is_anonymous_local_objc
 /* Private flag applied to disable section-anchors in a particular section.
    This needs to be kept in sync with the flags used by varasm.c (defined in
    output.h).  */
-#define SECTION_NO_ANCHOR 0x2000000
+#define SECTION_NO_ANCHOR 0x4000000
 
 /* Declare the section variables.  */
 #ifndef USED_FOR_TARGET
--- gcc/cgraph.h.jj	2011-01-27 17:33:28.011433405 +0100
+++ gcc/cgraph.h	2011-01-27 17:33:28.011433405 +0100
@@ -720,6 +720,7 @@ bool cgraph_node_can_be_local_p (struct 
 
 struct varpool_node * varpool_get_node (const_tree decl);
 void varpool_remove_node (struct varpool_node *node);
+void varpool_finalize_named_section_flags (struct varpool_node *node);
 bool varpool_assemble_pending_decls (void);
 bool varpool_assemble_decl (struct varpool_node *node);
 bool varpool_analyze_pending_decls (void);
--- gcc/varasm.c.jj	2011-01-27 17:40:25.196565130 +0100
+++ gcc/varasm.c	2011-01-27 17:40:33.361429176 +0100
@@ -119,6 +119,7 @@ static void output_addressed_constants (
 static unsigned HOST_WIDE_INT array_size_for_constructor (tree);
 static unsigned min_align (unsigned, unsigned);
 static void globalize_decl (tree);
+static bool decl_readonly_section_1 (enum section_category);
 #ifdef BSS_SECTION_ASM_OP
 #ifdef ASM_OUTPUT_BSS
 static void asm_output_bss (FILE *, tree, const char *,
@@ -294,11 +295,31 @@ get_section (const char *name, unsigned 
       if ((sect->common.flags & ~SECTION_DECLARED) != flags
 	  && ((sect->common.flags | flags) & SECTION_OVERRIDE) == 0)
 	{
+	  /* It is fine if one of the section flags is
+	     SECTION_WRITE | SECTION_RELRO and the other has none of these
+	     flags (i.e. read-only) in named sections and either the
+	     section hasn't been declared yet or has been declared as writable.
+	     In that case just make sure the resulting flags are
+	     SECTION_WRITE | SECTION_RELRO, ie. writable only because of
+	     relocations.  */
+	  if (((sect->common.flags ^ flags) & (SECTION_WRITE | SECTION_RELRO))
+	      == (SECTION_WRITE | SECTION_RELRO)
+	      && (sect->common.flags
+		  & ~(SECTION_DECLARED | SECTION_WRITE | SECTION_RELRO))
+		 == (flags & ~(SECTION_WRITE | SECTION_RELRO))
+	      && ((sect->common.flags & SECTION_DECLARED) == 0
+		  || (sect->common.flags & SECTION_WRITE)))
+	    {
+	      sect->common.flags |= (SECTION_WRITE | SECTION_RELRO);
+	      return sect;
+	    }
 	  /* Sanity check user variables for flag changes.  */
 	  if (decl == 0)
 	    decl = sect->named.decl;
 	  gcc_assert (decl);
 	  error ("%+D causes a section type conflict", decl);
+	  /* Make sure we don't error about one section multiple times.  */
+	  sect->common.flags |= SECTION_OVERRIDE;
 	}
     }
   return sect;
@@ -985,7 +1006,7 @@ align_variable (tree decl, bool dont_out
    should be placed.  PREFER_NOSWITCH_P is true if a noswitch
    section should be used wherever possible.  */
 
-static section *
+section *
 get_variable_section (tree decl, bool prefer_noswitch_p)
 {
   addr_space_t as = ADDR_SPACE_GENERIC;
@@ -6026,8 +6047,18 @@ default_section_type_flags (tree decl, c
 
   if (decl && TREE_CODE (decl) == FUNCTION_DECL)
     flags = SECTION_CODE;
-  else if (decl && decl_readonly_section (decl, reloc))
-    flags = 0;
+  else if (decl)
+    {
+      enum section_category category
+	= categorize_decl_for_section (decl, reloc);
+      if (decl_readonly_section_1 (category))
+	flags = 0;
+      else if (category == SECCAT_DATA_REL_RO
+	       || category == SECCAT_DATA_REL_RO_LOCAL)
+	flags = SECTION_WRITE | SECTION_RELRO;
+      else
+	flags = SECTION_WRITE;
+    }
   else
     flags = SECTION_WRITE;
 
@@ -6250,17 +6281,13 @@ categorize_decl_for_section (const_tree 
 	  /* Here the reloc_rw_mask is not testing whether the section should
 	     be read-only or not, but whether the dynamic link will have to
 	     do something.  If so, we wish to segregate the data in order to
-	     minimize cache misses inside the dynamic linker.  If the data
-	     has a section attribute, ignore reloc_rw_mask() so that all data
-             in a given named section is catagorized in the same way.  */
-	  if (reloc & targetm.asm_out.reloc_rw_mask ()
-	      && !lookup_attribute ("section", DECL_ATTRIBUTES (decl)))
+	     minimize cache misses inside the dynamic linker.  */
+	  if (reloc & targetm.asm_out.reloc_rw_mask ())
 	    ret = reloc == 1 ? SECCAT_DATA_REL_LOCAL : SECCAT_DATA_REL;
 	  else
 	    ret = SECCAT_DATA;
 	}
-      else if (reloc & targetm.asm_out.reloc_rw_mask ()
-	       && !lookup_attribute ("section", DECL_ATTRIBUTES (decl)))
+      else if (reloc & targetm.asm_out.reloc_rw_mask ())
 	ret = reloc == 1 ? SECCAT_DATA_REL_RO_LOCAL : SECCAT_DATA_REL_RO;
       else if (reloc || flag_merge_constants < 2)
 	/* C and C++ don't allow different variables to share the same
@@ -6311,10 +6338,10 @@ categorize_decl_for_section (const_tree 
   return ret;
 }
 
-bool
-decl_readonly_section (const_tree decl, int reloc)
+static bool
+decl_readonly_section_1 (enum section_category category)
 {
-  switch (categorize_decl_for_section (decl, reloc))
+  switch (category)
     {
     case SECCAT_RODATA:
     case SECCAT_RODATA_MERGE_STR:
@@ -6322,13 +6349,17 @@ decl_readonly_section (const_tree decl, 
     case SECCAT_RODATA_MERGE_CONST:
     case SECCAT_SRODATA:
       return true;
-      break;
     default:
       return false;
-      break;
     }
 }
 
+bool
+decl_readonly_section (const_tree decl, int reloc)
+{
+  return decl_readonly_section_1 (categorize_decl_for_section (decl, reloc));
+}
+
 /* Select a section based on the above categorization.  */
 
 section *
--- gcc/cgraphunit.c.jj	2011-01-27 17:33:29.416940770 +0100
+++ gcc/cgraphunit.c	2011-01-27 19:48:24.567639053 +0100
@@ -1708,6 +1708,10 @@ cgraph_output_in_order (void)
   varpool_empty_needed_queue ();
 
   for (i = 0; i < max; ++i)
+    if (nodes[i].kind == ORDER_VAR)
+      varpool_finalize_named_section_flags (nodes[i].u.v);
+
+  for (i = 0; i < max; ++i)
     {
       switch (nodes[i].kind)
 	{
--- gcc/testsuite/gcc.dg/pr31490-2.c.jj	2011-01-27 17:40:33.365546146 +0100
+++ gcc/testsuite/gcc.dg/pr31490-2.c	2011-01-27 17:40:33.365546146 +0100
@@ -0,0 +1,7 @@
+/* PR middle-end/31490 */
+/* { dg-do compile } */
+/* { dg-options "-fpic" { target fpic } } */
+/* { dg-require-named-sections "" } */
+
+const char *const x __attribute__((section("foo"))) = "";
+const char *const g __attribute__((section("foo"))) = (const char *) 0;
--- gcc/testsuite/gcc.dg/pr31490-3.c.jj	2011-01-27 17:40:33.365546146 +0100
+++ gcc/testsuite/gcc.dg/pr31490-3.c	2011-01-27 17:40:33.365546146 +0100
@@ -0,0 +1,7 @@
+/* PR middle-end/31490 */
+/* { dg-do compile } */
+/* { dg-options "-fpic" { target fpic } } */
+/* { dg-require-named-sections "" } */
+
+const char *const x __attribute__((section("foo"))) = (const char *) 0;
+const char *const g __attribute__((section("foo"))) = "bar";
--- gcc/testsuite/gcc.dg/pr31490-4.c.jj	2011-01-27 17:40:33.366545270 +0100
+++ gcc/testsuite/gcc.dg/pr31490-4.c	2011-01-27 17:40:33.366545270 +0100
@@ -0,0 +1,10 @@
+/* PR middle-end/31490 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-options "-O2 -fpic" { target fpic } } */
+/* { dg-require-named-sections "" } */
+
+const char *const x __attribute__((section("foo"))) = "";
+const char *const g __attribute__((section("foo"))) = (const char *) 0;
+const char *const y __attribute__((section("bar"))) = (const char *) 0;
+const char *const h __attribute__((section("bar"))) = "bar";

Patch

--- gcc/output.h.jj	2011-01-07 19:36:14.000000000 +0100
+++ gcc/output.h	2011-01-07 19:36:14.000000000 +0100
@@ -441,7 +441,8 @@  extern void no_asm_to_stream (FILE *);
 #define SECTION_DECLARED 0x100000	/* section has been used */
 #define SECTION_STYLE_MASK 0x600000	/* bits used for SECTION_STYLE */
 #define SECTION_COMMON   0x800000	/* contains common data */
-#define SECTION_MACH_DEP 0x1000000	/* subsequent bits reserved for target */
+#define SECTION_RELRO	 0x1000000	/* data is readonly after relocation processing */
+#define SECTION_MACH_DEP 0x2000000	/* subsequent bits reserved for target */
 
 /* This SECTION_STYLE is used for unnamed sections that we can switch
    to using a special assembler directive.  */
@@ -585,6 +586,7 @@  extern section *get_unnamed_section (uns
 				     const void *);
 extern section *get_section (const char *, unsigned int, tree);
 extern section *get_named_section (tree, const char *, int);
+extern section *get_variable_section (tree, bool);
 extern void place_block_symbol (rtx);
 extern rtx get_section_anchor (struct object_block *, HOST_WIDE_INT,
 			       enum tls_model);
--- gcc/varpool.c.jj	2011-01-21 13:57:10.000000000 +0100
+++ gcc/varpool.c	2011-01-27 15:35:42.815683220 +0100
@@ -565,6 +565,26 @@  varpool_remove_unreferenced_decls (void)
   varpool_analyze_pending_decls ();
 }
 
+/* For variables in named sections make sure get_variable_section
+   is called before we switch to those sections.  Then section
+   conflicts between read-only and read-only requiring relocations
+   sections can be resolved.  */
+void
+varpool_finalize_named_section_flags (void)
+{
+  struct varpool_node *node;
+
+  for (node = varpool_nodes_queue; node; node = node->next_needed)
+    if (!TREE_ASM_WRITTEN (node->decl)
+	&& !node->alias
+	&& !node->in_other_partition
+	&& !DECL_EXTERNAL (node->decl)
+	&& TREE_CODE (node->decl) == VAR_DECL
+	&& !DECL_HAS_VALUE_EXPR_P (node->decl)
+	&& DECL_SECTION_NAME (node->decl))
+      get_variable_section (node->decl, false);
+}
+
 /* Output all variables enqueued to be assembled.  */
 bool
 varpool_assemble_pending_decls (void)
@@ -580,6 +600,8 @@  varpool_assemble_pending_decls (void)
      elsewhere.  */
   varpool_analyze_pending_decls ();
 
+  varpool_finalize_named_section_flags ();
+
   while (varpool_nodes_queue)
     {
       struct varpool_node *node = varpool_nodes_queue;
--- gcc/config/darwin.h.jj	2011-01-07 19:36:14.149776496 +0100
+++ gcc/config/darwin.h	2011-01-27 14:05:18.982402120 +0100
@@ -654,7 +654,7 @@  int darwin_label_is_anonymous_local_objc
 /* Private flag applied to disable section-anchors in a particular section.
    This needs to be kept in sync with the flags used by varasm.c (defined in
    output.h).  */
-#define SECTION_NO_ANCHOR 0x2000000
+#define SECTION_NO_ANCHOR 0x4000000
 
 /* Declare the section variables.  */
 #ifndef USED_FOR_TARGET
--- gcc/cgraph.h.jj	2011-01-26 17:51:18.000000000 +0100
+++ gcc/cgraph.h	2011-01-26 17:51:18.000000000 +0100
@@ -720,6 +720,7 @@  bool cgraph_node_can_be_local_p (struct 
 
 struct varpool_node * varpool_get_node (const_tree decl);
 void varpool_remove_node (struct varpool_node *node);
+void varpool_finalize_named_section_flags (void);
 bool varpool_assemble_pending_decls (void);
 bool varpool_assemble_decl (struct varpool_node *node);
 bool varpool_analyze_pending_decls (void);
--- gcc/varasm.c.jj	2011-01-26 21:04:07.450083781 +0100
+++ gcc/varasm.c	2011-01-27 15:49:43.314420175 +0100
@@ -119,6 +119,7 @@  static void output_addressed_constants (
 static unsigned HOST_WIDE_INT array_size_for_constructor (tree);
 static unsigned min_align (unsigned, unsigned);
 static void globalize_decl (tree);
+static bool decl_readonly_section_1 (enum section_category);
 #ifdef BSS_SECTION_ASM_OP
 #ifdef ASM_OUTPUT_BSS
 static void asm_output_bss (FILE *, tree, const char *,
@@ -294,11 +295,31 @@  get_section (const char *name, unsigned 
       if ((sect->common.flags & ~SECTION_DECLARED) != flags
 	  && ((sect->common.flags | flags) & SECTION_OVERRIDE) == 0)
 	{
+	  /* It is fine if one of the section flags is
+	     SECTION_WRITE | SECTION_RELRO and the other has none of these
+	     flags (i.e. read-only) in named sections and either the
+	     section hasn't been declared yet or has been declared as writable.
+	     In that case just make sure the resulting flags are
+	     SECTION_WRITE | SECTION_RELRO, ie. writable only because of
+	     relocations.  */
+	  if (((sect->common.flags ^ flags) & (SECTION_WRITE | SECTION_RELRO))
+	      == (SECTION_WRITE | SECTION_RELRO)
+	      && (sect->common.flags
+		  & ~(SECTION_DECLARED | SECTION_WRITE | SECTION_RELRO))
+		 == (flags & ~(SECTION_WRITE | SECTION_RELRO))
+	      && ((sect->common.flags & SECTION_DECLARED) == 0
+		  || (sect->common.flags & SECTION_WRITE)))
+	    {
+	      sect->common.flags |= (SECTION_WRITE | SECTION_RELRO);
+	      return sect;
+	    }
 	  /* Sanity check user variables for flag changes.  */
 	  if (decl == 0)
 	    decl = sect->named.decl;
 	  gcc_assert (decl);
 	  error ("%+D causes a section type conflict", decl);
+	  /* Make sure we don't error about one section multiple times.  */
+	  sect->common.flags |= SECTION_OVERRIDE;
 	}
     }
   return sect;
@@ -985,7 +1006,7 @@  align_variable (tree decl, bool dont_out
    should be placed.  PREFER_NOSWITCH_P is true if a noswitch
    section should be used wherever possible.  */
 
-static section *
+section *
 get_variable_section (tree decl, bool prefer_noswitch_p)
 {
   addr_space_t as = ADDR_SPACE_GENERIC;
@@ -6026,8 +6047,18 @@  default_section_type_flags (tree decl, c
 
   if (decl && TREE_CODE (decl) == FUNCTION_DECL)
     flags = SECTION_CODE;
-  else if (decl && decl_readonly_section (decl, reloc))
-    flags = 0;
+  else if (decl)
+    {
+      enum section_category category
+	= categorize_decl_for_section (decl, reloc);
+      if (decl_readonly_section_1 (category))
+	flags = 0;
+      else if (category == SECCAT_DATA_REL_RO
+	       || category == SECCAT_DATA_REL_RO_LOCAL)
+	flags = SECTION_WRITE | SECTION_RELRO;
+      else
+	flags = SECTION_WRITE;
+    }
   else
     flags = SECTION_WRITE;
 
@@ -6250,17 +6281,13 @@  categorize_decl_for_section (const_tree 
 	  /* Here the reloc_rw_mask is not testing whether the section should
 	     be read-only or not, but whether the dynamic link will have to
 	     do something.  If so, we wish to segregate the data in order to
-	     minimize cache misses inside the dynamic linker.  If the data
-	     has a section attribute, ignore reloc_rw_mask() so that all data
-             in a given named section is catagorized in the same way.  */
-	  if (reloc & targetm.asm_out.reloc_rw_mask ()
-	      && !lookup_attribute ("section", DECL_ATTRIBUTES (decl)))
+	     minimize cache misses inside the dynamic linker.  */
+	  if (reloc & targetm.asm_out.reloc_rw_mask ())
 	    ret = reloc == 1 ? SECCAT_DATA_REL_LOCAL : SECCAT_DATA_REL;
 	  else
 	    ret = SECCAT_DATA;
 	}
-      else if (reloc & targetm.asm_out.reloc_rw_mask ()
-	       && !lookup_attribute ("section", DECL_ATTRIBUTES (decl)))
+      else if (reloc & targetm.asm_out.reloc_rw_mask ())
 	ret = reloc == 1 ? SECCAT_DATA_REL_RO_LOCAL : SECCAT_DATA_REL_RO;
       else if (reloc || flag_merge_constants < 2)
 	/* C and C++ don't allow different variables to share the same
@@ -6311,10 +6338,10 @@  categorize_decl_for_section (const_tree 
   return ret;
 }
 
-bool
-decl_readonly_section (const_tree decl, int reloc)
+static bool
+decl_readonly_section_1 (enum section_category category)
 {
-  switch (categorize_decl_for_section (decl, reloc))
+  switch (category)
     {
     case SECCAT_RODATA:
     case SECCAT_RODATA_MERGE_STR:
@@ -6322,13 +6349,17 @@  decl_readonly_section (const_tree decl, 
     case SECCAT_RODATA_MERGE_CONST:
     case SECCAT_SRODATA:
       return true;
-      break;
     default:
       return false;
-      break;
     }
 }
 
+bool
+decl_readonly_section (const_tree decl, int reloc)
+{
+  return decl_readonly_section_1 (categorize_decl_for_section (decl, reloc));
+}
+
 /* Select a section based on the above categorization.  */
 
 section *
--- gcc/cgraphunit.c.jj	2011-01-26 17:51:18.000000000 +0100
+++ gcc/cgraphunit.c	2011-01-27 15:40:14.594808388 +0100
@@ -1648,6 +1648,8 @@  cgraph_output_in_order (void)
 
   varpool_analyze_pending_decls ();
 
+  varpool_finalize_named_section_flags ();
+
   for (pf = cgraph_nodes; pf; pf = pf->next)
     {
       if (pf->process)
--- gcc/testsuite/gcc.dg/pr31490-2.c.jj	2011-01-27 13:26:35.703763981 +0100
+++ gcc/testsuite/gcc.dg/pr31490-2.c	2011-01-27 13:29:14.954465242 +0100
@@ -0,0 +1,7 @@ 
+/* PR middle-end/31490 */
+/* { dg-do compile } */
+/* { dg-options "-fpic" { target fpic } } */
+/* { dg-require-named-sections "" } */
+
+const char *const x __attribute__((section("foo"))) = "";
+const char *const g __attribute__((section("foo"))) = (const char *) 0;
--- gcc/testsuite/gcc.dg/pr31490-3.c.jj	2011-01-27 13:26:35.000000000 +0100
+++ gcc/testsuite/gcc.dg/pr31490-3.c	2011-01-27 13:29:04.150433327 +0100
@@ -0,0 +1,7 @@ 
+/* PR middle-end/31490 */
+/* { dg-do compile } */
+/* { dg-options "-fpic" { target fpic } } */
+/* { dg-require-named-sections "" } */
+
+const char *const x __attribute__((section("foo"))) = (const char *) 0;
+const char *const g __attribute__((section("foo"))) = "bar";
--- gcc/testsuite/gcc.dg/pr31490-4.c.jj	2011-01-27 13:26:35.000000000 +0100
+++ gcc/testsuite/gcc.dg/pr31490-4.c	2011-01-27 15:51:45.728402672 +0100
@@ -0,0 +1,10 @@ 
+/* PR middle-end/31490 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-options "-O2 -fpic" { target fpic } } */
+/* { dg-require-named-sections "" } */
+
+const char *const x __attribute__((section("foo"))) = "";
+const char *const g __attribute__((section("foo"))) = (const char *) 0;
+const char *const y __attribute__((section("bar"))) = (const char *) 0;
+const char *const h __attribute__((section("bar"))) = "bar";
--- gcc/testsuite/gcc.dg/20051207-3.c.jj	2010-06-11 11:00:48.000000000 +0200
+++ gcc/testsuite/gcc.dg/20051207-3.c	2011-01-27 19:34:48.540619527 +0100
@@ -3,5 +3,5 @@ 
    .eh_frame.  The warning therefore belongs on the second decl.  */
 /* { dg-options "-fno-unit-at-a-time" } */
 /* { dg-require-named-sections "" } */
-int a __attribute__((section (".eh_frame"))) = 1;
-const int b __attribute__((section (".eh_frame"))) = 1; /* { dg-error "section type conflict" } */
+int a __attribute__((section (".eh_frame"))) = 1; /* { dg-error "section type conflict" } */
+const int b __attribute__((section (".eh_frame"))) = 1;
--- gcc/testsuite/gcc.dg/tls/section-1.c.jj	2010-06-11 11:00:43.000000000 +0200
+++ gcc/testsuite/gcc.dg/tls/section-1.c	2011-01-27 19:34:31.744545308 +0100
@@ -8,5 +8,5 @@  __thread int i A("foo");		/* Ok */
 
 __thread int j A(".data");  /* { dg-error "causes a section type conflict" "conflict with .data section" { xfail *-*-* } } */
 
-int k A("bar");
-__thread int l A("bar");  /* { dg-error "causes a section type conflict" "conflict with user-defined section" } */
+int k A("bar");  /* { dg-error "causes a section type conflict" "conflict with user-defined section" } */
+__thread int l A("bar");