diff --git a/gcc/config/rs6000/rs6000-opts.h b/gcc/config/rs6000/rs6000-opts.h
index a8194783e018..cc780f569308 100644
--- a/gcc/config/rs6000/rs6000-opts.h
+++ b/gcc/config/rs6000/rs6000-opts.h
@@ -120,7 +120,8 @@ enum rs6000_sdata_type {
   SDATA_NONE,			/* No small data support.  */
   SDATA_DATA,			/* Just put data in .sbss/.sdata, don't use relocs.  */
   SDATA_SYSV,			/* Use r13 to point to .sdata/.sbss.  */
-  SDATA_EABI			/* Use r13 like above, r2 points to .sdata2/.sbss2.  */
+  SDATA_EABI,			/* Use r13 like above, r2 points to .sdata2/.sbss2.  */
+  SDATA_EXPLICIT		/* Use r13 (or r2?) for explicit sdata.  */
 };
 
 /* Type of traceback to use.  */
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index ddc61bdaffe7..a679709a055f 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -2819,6 +2819,10 @@ rs6000_debug_reg_global (void)
       fprintf (stderr, DEBUG_FMT_S, "sdata", "eabi");
       break;
 
+    case SDATA_EXPLICIT:
+      fprintf (stderr, DEBUG_FMT_S, "sdata", "explicit");
+      break;
+
     }
 
   switch (rs6000_traceback)
@@ -6098,6 +6102,8 @@ rs6000_file_start (void)
 	case SDATA_DATA: fprintf (file, "%s -msdata=data", start); start = ""; break;
 	case SDATA_SYSV: fprintf (file, "%s -msdata=sysv", start); start = ""; break;
 	case SDATA_EABI: fprintf (file, "%s -msdata=eabi", start); start = ""; break;
+	case SDATA_EXPLICIT:
+	  fprintf (file, "%s -msdata=explicit", start); start = ""; break;
 	}
 
       if (rs6000_sdata && g_switch_value)
@@ -21240,8 +21246,10 @@ rs6000_output_function_entry (FILE *file, const char *fname)
 /* Print an operand.  Recognize special options, documented below.  */
 
 #if TARGET_ELF
-#define SMALL_DATA_RELOC ((rs6000_sdata == SDATA_EABI) ? "sda21" : "sdarel")
-#define SMALL_DATA_REG ((rs6000_sdata == SDATA_EABI) ? 0 : 13)
+#define SMALL_DATA_EABI_P (rs6000_sdata == SDATA_EABI \
+			   || (rs6000_sdata == SDATA_EXPLICIT && TARGET_EABI))
+#define SMALL_DATA_RELOC (SMALL_DATA_EABI_P ? "sda21" : "sdarel")
+#define SMALL_DATA_REG (SMALL_DATA_EABI_P ? 0 : 13)
 #else
 #define SMALL_DATA_RELOC "sda21"
 #define SMALL_DATA_REG 0
@@ -33221,6 +33229,11 @@ rs6000_elf_in_small_data_p (const_tree decl)
     }
   else
     {
+      /* Explicit mode means no implicit assignment to small data
+	 sections.  */
+      if (rs6000_sdata == SDATA_EXPLICIT)
+	return false;
+
       /* If we are told not to put readonly data in sdata, then don't.  */
       if (TREE_READONLY (decl) && rs6000_sdata != SDATA_EABI
 	  && !rs6000_readonly_in_sdata)
diff --git a/gcc/config/rs6000/sysv4.h b/gcc/config/rs6000/sysv4.h
index bb19d0dcd411..83f527c57af1 100644
--- a/gcc/config/rs6000/sysv4.h
+++ b/gcc/config/rs6000/sysv4.h
@@ -119,6 +119,8 @@ do {									\
 	rs6000_sdata = SDATA_DATA;					\
       else if (!strcmp (rs6000_sdata_name, "default"))			\
 	rs6000_sdata = (TARGET_EABI) ? SDATA_EABI : SDATA_SYSV;		\
+      else if (!strcmp (rs6000_sdata_name, "explicit"))			\
+	rs6000_sdata = SDATA_EXPLICIT;					\
       else if (!strcmp (rs6000_sdata_name, "sysv"))			\
 	rs6000_sdata = SDATA_SYSV;					\
       else if (!strcmp (rs6000_sdata_name, "eabi"))			\
diff --git a/gcc/config/rs6000/sysv4.opt b/gcc/config/rs6000/sysv4.opt
index 34fea0ddd08a..d11053e4bdaf 100644
--- a/gcc/config/rs6000/sysv4.opt
+++ b/gcc/config/rs6000/sysv4.opt
@@ -25,7 +25,7 @@ Target RejectNegative Joined Var(rs6000_abi_name)
 
 msdata=
 Target RejectNegative Joined Var(rs6000_sdata_name)
--msdata=[none,data,sysv,eabi]	Select method for sdata handling.
+-msdata=[none,data,sysv,eabi,explicit]	Select method for sdata handling.
 
 mreadonly-in-sdata
 Target Report Var(rs6000_readonly_in_sdata) Init(1) Save
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 444159178a76..86dbb1d8700d 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -22824,6 +22824,16 @@ On embedded PowerPC systems, put all initialized global and static data
 in the @code{.data} section, and all uninitialized data in the
 @code{.bss} section.
 
+@item -msdata=explicit
+@itemx -msdata
+@opindex msdata=explicit
+@opindex msdata
+Put all initialized global and static data that is not assigned to an
+explicit section in the @code{.data} section, and all uninitialized data
+that is not assigned to an explicit section in the @code{.bss} section.
+Use small data access patterns to access variables explicitly assigned
+to small data sections.
+
 @item -mblock-move-inline-limit=@var{num}
 @opindex mblock-move-inline-limit
 Inline all block moves (such as calls to @code{memcpy} or structure
diff --git a/gcc/testsuite/gcc.target/powerpc/ppc-sdata-3.c b/gcc/testsuite/gcc.target/powerpc/ppc-sdata-3.c
new file mode 100644
index 000000000000..750e5ad234af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/ppc-sdata-3.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-msdata=explicit" } */
+/* { dg-require-effective-target powerpc_eabi_ok } */
+/* { dg-require-effective-target nonpic } */
+/* { dg-final { scan-assembler "\\.section\[ \t\]\\.sdata," } } */
+/* { dg-final { scan-assembler "\\.section\[ \t\]\\.sbss," } } */
+/* { dg-final { scan-assembler "\\.section\[ \t\]\\.sdata2," } } */
+/* { dg-final { scan-assembler "\\.section\[ \t\]\\.sbss2," } } */
+/* { dg-final { scan-assembler "i@ha" } } */
+/* { dg-final { scan-assembler "j@sda(rel|21)\\((13|0)\\)" } } */
+/* { dg-final { scan-assembler "k@sda(rel|21)\\((13|0)\\)" } } */
+/* { dg-final { scan-assembler "l@sda(rel|21)\\((2|13|0)\\)" } } */
+/* { dg-final { scan-assembler "m@sda(rel|21)\\((2|13|0)\\)" } } */
+
+static int i;
+static int j __attribute__((section(".sbss")));
+static int k __attribute__((section(".sdata"))) = 2;
+static int l __attribute__((section(".sbss2")));
+static int m __attribute__((section(".sdata2"))) = 4;
+int f(void) {
+  return i + j + k + l + m;
+}
