--- 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");
