Add -static-pie to GCC driver to create static PIE

Submitted by H.J. Lu on Aug. 8, 2017, 10:18 p.m.

Details

Message ID 20170808221841.GA16793@gmail.com
State New
Headers show

Commit Message

H.J. Lu Aug. 8, 2017, 10:18 p.m.
This patch adds -static-pie to GCC driver to create static PIE.  A static
position independent executable (PIE) is similar to static executable,
but can be loaded at any address without a dynamic linker.  All linker
input files must be compiled with -fpie or -fPIE and linker must support
--no-dynamic-linker to avoid linking with dynamic linker.  "-z text" is
also needed to prevent dynamic relocations in read-only segments.

OK for trunk?

H.J.
---
	PR driver/81498
	* common.opt (-static-pie): New alias.
	(shared): Negate static-pie.
	(static-pie): New option.
	* config/gnu-user.h (GNU_USER_TARGET_STARTFILE_SPEC): Add
	-static-pie support.
	(GNU_USER_TARGET_ENDFILE_SPEC): Likewise.
	(LINK_EH_SPEC): Likewise.
	(LINK_GCC_C_SEQUENCE_SPEC): Likewise.
	* config/i386/gnu-user.h (GNU_USER_TARGET_LINK_SPEC): Likewise.
	* config/i386/gnu-user64.h (GNU_USER_TARGET_LINK_SPEC): Likewise.
	* gcc.c (LINK_COMMAND_SPEC): Likewise.
	(init_gcc_specs): Likewise.
	(init_spec): Likewise.
	* doc/invoke.texi: Document -static-pie.
---
 gcc/common.opt               |  9 ++++++++-
 gcc/config/gnu-user.h        | 15 ++++++++-------
 gcc/config/i386/gnu-user.h   |  7 ++++---
 gcc/config/i386/gnu-user64.h | 11 ++++++-----
 gcc/doc/invoke.texi          | 11 ++++++++++-
 gcc/gcc.c                    | 17 ++++++++++-------
 6 files changed, 46 insertions(+), 24 deletions(-)

Comments

Richard Guenther Aug. 9, 2017, 5:36 a.m.
On August 9, 2017 12:18:41 AM GMT+02:00, "H.J. Lu" <hongjiu.lu@intel.com> wrote:
>This patch adds -static-pie to GCC driver to create static PIE.  A
>static
>position independent executable (PIE) is similar to static executable,
>but can be loaded at any address without a dynamic linker.  All linker
>input files must be compiled with -fpie or -fPIE and linker must
>support
>--no-dynamic-linker to avoid linking with dynamic linker.  "-z text" is
>also needed to prevent dynamic relocations in read-only segments.
>
>OK for trunk?

What's wrong with -static -pie?

>H.J.
>---
>	PR driver/81498
>	* common.opt (-static-pie): New alias.
>	(shared): Negate static-pie.
>	(static-pie): New option.
>	* config/gnu-user.h (GNU_USER_TARGET_STARTFILE_SPEC): Add
>	-static-pie support.
>	(GNU_USER_TARGET_ENDFILE_SPEC): Likewise.
>	(LINK_EH_SPEC): Likewise.
>	(LINK_GCC_C_SEQUENCE_SPEC): Likewise.
>	* config/i386/gnu-user.h (GNU_USER_TARGET_LINK_SPEC): Likewise.
>	* config/i386/gnu-user64.h (GNU_USER_TARGET_LINK_SPEC): Likewise.
>	* gcc.c (LINK_COMMAND_SPEC): Likewise.
>	(init_gcc_specs): Likewise.
>	(init_spec): Likewise.
>	* doc/invoke.texi: Document -static-pie.
>---
> gcc/common.opt               |  9 ++++++++-
> gcc/config/gnu-user.h        | 15 ++++++++-------
> gcc/config/i386/gnu-user.h   |  7 ++++---
> gcc/config/i386/gnu-user64.h | 11 ++++++-----
> gcc/doc/invoke.texi          | 11 ++++++++++-
> gcc/gcc.c                    | 17 ++++++++++-------
> 6 files changed, 46 insertions(+), 24 deletions(-)
>
>diff --git a/gcc/common.opt b/gcc/common.opt
>index 1cb1c83d306..246566168cc 100644
>--- a/gcc/common.opt
>+++ b/gcc/common.opt
>@@ -353,6 +353,9 @@ Common Alias(pedantic-errors)
> -pie
> Driver Alias(pie)
> 
>+-static-pie
>+Driver Alias(static-pie)
>+
> -pipe
> Driver Alias(pipe)
> 
>@@ -3062,7 +3065,7 @@ x
> Driver Joined Separate
> 
> shared
>-Driver RejectNegative Negative(pie)
>+Driver RejectNegative Negative(static-pie)
> Create a shared library.
> 
> shared-libgcc
>@@ -3114,6 +3117,10 @@ pie
> Driver RejectNegative Negative(no-pie)
> Create a position independent executable.
> 
>+static-pie
>+Driver RejectNegative Negative(pie)
>+Create a static position independent executable.
>+
> z
> Driver Joined Separate
> 
>diff --git a/gcc/config/gnu-user.h b/gcc/config/gnu-user.h
>index de605b0c466..a967b69a350 100644
>--- a/gcc/config/gnu-user.h
>+++ b/gcc/config/gnu-user.h
>@@ -53,11 +53,11 @@ see the files COPYING3 and COPYING.RUNTIME
>respectively.  If not, see
>   "%{shared:; \
>      pg|p|profile:gcrt1.o%s; \
>      static:crt1.o%s; \
>-     " PIE_SPEC ":Scrt1.o%s; \
>+     static-pie|" PIE_SPEC ":Scrt1.o%s; \
>      :crt1.o%s} \
>    crti.o%s \
>    %{static:crtbeginT.o%s; \
>-     shared|" PIE_SPEC ":crtbeginS.o%s; \
>+     shared|static-pie|" PIE_SPEC ":crtbeginS.o%s; \
>      :crtbegin.o%s} \
>    %{fvtable-verify=none:%s; \
>      fvtable-verify=preinit:vtv_start_preinit.o%s; \
>@@ -70,7 +70,7 @@ see the files COPYING3 and COPYING.RUNTIME
>respectively.  If not, see
>      :crt1.o%s} \
>    crti.o%s \
>    %{static:crtbeginT.o%s; \
>-     shared|pie:crtbeginS.o%s; \
>+     shared|pie|static-pie:crtbeginS.o%s; \
>      :crtbegin.o%s} \
>    %{fvtable-verify=none:%s; \
>      fvtable-verify=preinit:vtv_start_preinit.o%s; \
>@@ -92,7 +92,7 @@ see the files COPYING3 and COPYING.RUNTIME
>respectively.  If not, see
>      fvtable-verify=preinit:vtv_end_preinit.o%s; \
>      fvtable-verify=std:vtv_end.o%s} \
>    %{static:crtend.o%s; \
>-     shared|" PIE_SPEC ":crtendS.o%s; \
>+     shared|static-pie|" PIE_SPEC ":crtendS.o%s; \
>      :crtend.o%s} \
>    crtn.o%s \
>    " CRTOFFLOADEND
>@@ -102,7 +102,7 @@ see the files COPYING3 and COPYING.RUNTIME
>respectively.  If not, see
>      fvtable-verify=preinit:vtv_end_preinit.o%s; \
>      fvtable-verify=std:vtv_end.o%s} \
>    %{static:crtend.o%s; \
>-     shared|pie:crtendS.o%s; \
>+     shared|pie|static-pie:crtendS.o%s; \
>      :crtend.o%s} \
>    crtn.o%s \
>    " CRTOFFLOADEND
>@@ -132,12 +132,13 @@ see the files COPYING3 and COPYING.RUNTIME
>respectively.  If not, see
> #define LIB_SPEC GNU_USER_TARGET_LIB_SPEC
> 
> #if defined(HAVE_LD_EH_FRAME_HDR)
>-#define LINK_EH_SPEC "%{!static:--eh-frame-hdr} "
>+#define LINK_EH_SPEC "%{!static|static-pie:--eh-frame-hdr} "
> #endif
> 
> #undef LINK_GCC_C_SEQUENCE_SPEC
> #define LINK_GCC_C_SEQUENCE_SPEC \
>-  "%{static:--start-group} %G %L %{static:--end-group}%{!static:%G}"
>+  "%{static|static-pie:--start-group} %G %L \
>+   %{static|static-pie:--end-group}%{!static:%{!static-pie:%G}}"
> 
> /* Use --as-needed -lgcc_s for eh support.  */
> #ifdef HAVE_LD_AS_NEEDED
>diff --git a/gcc/config/i386/gnu-user.h b/gcc/config/i386/gnu-user.h
>index a4c88f1a848..8983dc9ecd7 100644
>--- a/gcc/config/i386/gnu-user.h
>+++ b/gcc/config/i386/gnu-user.h
>@@ -77,9 +77,10 @@ along with GCC; see the file COPYING3.  If not see
>#define GNU_USER_TARGET_LINK_SPEC "-m %(link_emulation)
>%{shared:-shared} \
>   %{!shared: \
>     %{!static: \
>-      %{rdynamic:-export-dynamic} \
>-      -dynamic-linker %(dynamic_linker)} \
>-      %{static:-static}}"
>+      %{!static-pie: \
>+	%{rdynamic:-export-dynamic} \
>+	-dynamic-linker %(dynamic_linker)}} \
>+      %{static:-static} %{static-pie:-static -pie --no-dynamic-linker
>-z text}}"
> 
> #undef	LINK_SPEC
> #define LINK_SPEC GNU_USER_TARGET_LINK_SPEC
>diff --git a/gcc/config/i386/gnu-user64.h
>b/gcc/config/i386/gnu-user64.h
>index 39f5ef6a68b..6fc9eae6f6b 100644
>--- a/gcc/config/i386/gnu-user64.h
>+++ b/gcc/config/i386/gnu-user64.h
>@@ -59,11 +59,12 @@ see the files COPYING3 and COPYING.RUNTIME
>respectively.  If not, see
>   %{shared:-shared} \
>   %{!shared: \
>     %{!static: \
>-      %{rdynamic:-export-dynamic} \
>-      %{" SPEC_32 ":-dynamic-linker " GNU_USER_DYNAMIC_LINKER32 "} \
>-      %{" SPEC_64 ":-dynamic-linker " GNU_USER_DYNAMIC_LINKER64 "} \
>-      %{" SPEC_X32 ":-dynamic-linker " GNU_USER_DYNAMIC_LINKERX32 "}}
>\
>-    %{static:-static}}"
>+      %{!static-static: \
>+	%{rdynamic:-export-dynamic} \
>+	%{" SPEC_32 ":-dynamic-linker " GNU_USER_DYNAMIC_LINKER32 "} \
>+	%{" SPEC_64 ":-dynamic-linker " GNU_USER_DYNAMIC_LINKER64 "} \
>+	%{" SPEC_X32 ":-dynamic-linker " GNU_USER_DYNAMIC_LINKERX32 "}}} \
>+    %{static:-static} %{static-pie:-static -pie --no-dynamic-linker -z
>text}}"
> 
> #undef	LINK_SPEC
> #define LINK_SPEC GNU_USER_TARGET_LINK_SPEC
>diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
>index cc0f5a00a4f..322bde9178f 100644
>--- a/gcc/doc/invoke.texi
>+++ b/gcc/doc/invoke.texi
>@@ -496,7 +496,7 @@ Objective-C and Objective-C++ Dialects}.
> @xref{Link Options,,Options for Linking}.
>@gccoptlist{@var{object-file-name}  -fuse-ld=@var{linker} 
>-l@var{library} @gol
>-nostartfiles  -nodefaultlibs  -nostdlib  -pie  -pthread  -rdynamic
>@gol
>--s  -static  -static-libgcc  -static-libstdc++ @gol
>+-s  -static -static-pie -static-libgcc  -static-libstdc++ @gol
>-static-libasan  -static-libtsan  -static-liblsan  -static-libubsan
>@gol
> -static-libmpx  -static-libmpxwrappers @gol
> -shared  -shared-libgcc  -symbolic @gol
>@@ -11780,6 +11780,15 @@ or model suboptions) when you specify this
>linker option.
> @opindex no-pie
> Don't produce a position independent executable.
> 
>+@item -static-pie
>+@opindex static-pie
>+Produce a static position independent executable on targets that
>support
>+it.  A static position independent executable is similar to static
>+executable, but can be loaded at any address without a dynamic linker.
>+For predictable results, you must also specify the same set of options
>+used for compilation (@option{-fpie}, @option{-fPIE}, or model
>+suboptions) when you specify this linker option.
>+
> @item -pthread
> @opindex pthread
> Link with the POSIX threads library.  This option is supported on 
>diff --git a/gcc/gcc.c b/gcc/gcc.c
>index 987eff55aa6..1b60d59726e 100644
>--- a/gcc/gcc.c
>+++ b/gcc/gcc.c
>@@ -1015,9 +1015,10 @@ proper position among the other output files. 
>*/
> #endif
> 
> /* -u* was put back because both BSD and SysV seem to support it.  */
>-/* %{static|no-pie:} simply prevents an error message:
>+/* %{static|no-pie|static-pie:} simply prevents an error message:
>    1. If the target machine doesn't handle -static.
>    2. If PIE isn't enabled by default.
>+   3. If the target machine doesn't handle -static-pie.
>  */
>/* We want %{T*} after %{L*} and %D so that it can be used to specify
>linker
>    scripts which exist in user specified directories, or in standard
>@@ -1035,7 +1036,7 @@ proper position among the other output files.  */
>    "%{fuse-ld=*:-fuse-ld=%*} " LINK_COMPRESS_DEBUG_SPEC \
>    "%X %{o*} %{e*} %{N} %{n} %{r}\
>     %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!nostartfiles:%S}} \
>-    %{static|no-pie:} %{L*} %(mfwrap) %(link_libgcc) " \
>+    %{static|no-pie|static-pie:} %{L*} %(mfwrap) %(link_libgcc) " \
> VTABLE_VERIFICATION_SPEC " " SANITIZER_EARLY_SPEC " %o " CHKP_SPEC " \
>     %{fopenacc|fopenmp|%:gt(%{ftree-parallelize-loops=*:%*} 1):\
> 	%:include(libgomp.spec)%(link_gomp)}\
>@@ -1670,17 +1671,19 @@ init_gcc_specs (struct obstack *obstack, const
>char *shared_name,
> {
>   char *buf;
> 
>-  buf = concat ("%{static|static-libgcc:", static_name, " ", eh_name,
>"}"
>-		"%{!static:%{!static-libgcc:"
> #if USE_LD_AS_NEEDED
>+  buf = concat ("%{static|static-libgcc|static-pie:", static_name, "
>", eh_name, "}"
>+		"%{!static:%{!static-libgcc:%{!static-pie:"
> 		"%{!shared-libgcc:",
> 		static_name, " " LD_AS_NEEDED_OPTION " ",
> 		shared_name, " " LD_NO_AS_NEEDED_OPTION
> 		"}"
> 		"%{shared-libgcc:",
> 		shared_name, "%{!shared: ", static_name, "}"
>-		"}"
>+		"}}"
> #else
>+  buf = concat ("%{static|static-libgcc:", static_name, " ", eh_name,
>"}"
>+		"%{!static:%{!static-libgcc:"
> 		"%{!shared:"
> 		"%{!shared-libgcc:", static_name, " ", eh_name, "}"
> 		"%{shared-libgcc:", shared_name, " ", static_name, "}"
>@@ -1788,8 +1791,8 @@ init_spec (void)
> 			    "-lgcc_eh"
> #ifdef USE_LIBUNWIND_EXCEPTIONS
> # ifdef HAVE_LD_STATIC_DYNAMIC
>-			    " %{!static:" LD_STATIC_OPTION "} -lunwind"
>-			    " %{!static:" LD_DYNAMIC_OPTION "}"
>+			    " %{!static:%{!static-pie:" LD_STATIC_OPTION "}} -lunwind"
>+			    " %{!static:%{!static-pie:" LD_DYNAMIC_OPTION "}}"
> # else
> 			    " -lunwind"
> # endif
H.J. Lu Aug. 9, 2017, 10:39 a.m.
On Tue, Aug 8, 2017 at 10:36 PM, Richard Biener
<richard.guenther@gmail.com> wrote:
> On August 9, 2017 12:18:41 AM GMT+02:00, "H.J. Lu" <hongjiu.lu@intel.com> wrote:
>>This patch adds -static-pie to GCC driver to create static PIE.  A
>>static
>>position independent executable (PIE) is similar to static executable,
>>but can be loaded at any address without a dynamic linker.  All linker
>>input files must be compiled with -fpie or -fPIE and linker must
>>support
>>--no-dynamic-linker to avoid linking with dynamic linker.  "-z text" is
>>also needed to prevent dynamic relocations in read-only segments.
>>
>>OK for trunk?
>
> What's wrong with -static -pie?
>

-static -pie behaved differently depending on if --enable-default-pie
was used:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81523

I just checked in a patch to make -static always  override -pie.

Patch hide | download patch | download mbox

diff --git a/gcc/common.opt b/gcc/common.opt
index 1cb1c83d306..246566168cc 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -353,6 +353,9 @@  Common Alias(pedantic-errors)
 -pie
 Driver Alias(pie)
 
+-static-pie
+Driver Alias(static-pie)
+
 -pipe
 Driver Alias(pipe)
 
@@ -3062,7 +3065,7 @@  x
 Driver Joined Separate
 
 shared
-Driver RejectNegative Negative(pie)
+Driver RejectNegative Negative(static-pie)
 Create a shared library.
 
 shared-libgcc
@@ -3114,6 +3117,10 @@  pie
 Driver RejectNegative Negative(no-pie)
 Create a position independent executable.
 
+static-pie
+Driver RejectNegative Negative(pie)
+Create a static position independent executable.
+
 z
 Driver Joined Separate
 
diff --git a/gcc/config/gnu-user.h b/gcc/config/gnu-user.h
index de605b0c466..a967b69a350 100644
--- a/gcc/config/gnu-user.h
+++ b/gcc/config/gnu-user.h
@@ -53,11 +53,11 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
   "%{shared:; \
      pg|p|profile:gcrt1.o%s; \
      static:crt1.o%s; \
-     " PIE_SPEC ":Scrt1.o%s; \
+     static-pie|" PIE_SPEC ":Scrt1.o%s; \
      :crt1.o%s} \
    crti.o%s \
    %{static:crtbeginT.o%s; \
-     shared|" PIE_SPEC ":crtbeginS.o%s; \
+     shared|static-pie|" PIE_SPEC ":crtbeginS.o%s; \
      :crtbegin.o%s} \
    %{fvtable-verify=none:%s; \
      fvtable-verify=preinit:vtv_start_preinit.o%s; \
@@ -70,7 +70,7 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      :crt1.o%s} \
    crti.o%s \
    %{static:crtbeginT.o%s; \
-     shared|pie:crtbeginS.o%s; \
+     shared|pie|static-pie:crtbeginS.o%s; \
      :crtbegin.o%s} \
    %{fvtable-verify=none:%s; \
      fvtable-verify=preinit:vtv_start_preinit.o%s; \
@@ -92,7 +92,7 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      fvtable-verify=preinit:vtv_end_preinit.o%s; \
      fvtable-verify=std:vtv_end.o%s} \
    %{static:crtend.o%s; \
-     shared|" PIE_SPEC ":crtendS.o%s; \
+     shared|static-pie|" PIE_SPEC ":crtendS.o%s; \
      :crtend.o%s} \
    crtn.o%s \
    " CRTOFFLOADEND
@@ -102,7 +102,7 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      fvtable-verify=preinit:vtv_end_preinit.o%s; \
      fvtable-verify=std:vtv_end.o%s} \
    %{static:crtend.o%s; \
-     shared|pie:crtendS.o%s; \
+     shared|pie|static-pie:crtendS.o%s; \
      :crtend.o%s} \
    crtn.o%s \
    " CRTOFFLOADEND
@@ -132,12 +132,13 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define LIB_SPEC GNU_USER_TARGET_LIB_SPEC
 
 #if defined(HAVE_LD_EH_FRAME_HDR)
-#define LINK_EH_SPEC "%{!static:--eh-frame-hdr} "
+#define LINK_EH_SPEC "%{!static|static-pie:--eh-frame-hdr} "
 #endif
 
 #undef LINK_GCC_C_SEQUENCE_SPEC
 #define LINK_GCC_C_SEQUENCE_SPEC \
-  "%{static:--start-group} %G %L %{static:--end-group}%{!static:%G}"
+  "%{static|static-pie:--start-group} %G %L \
+   %{static|static-pie:--end-group}%{!static:%{!static-pie:%G}}"
 
 /* Use --as-needed -lgcc_s for eh support.  */
 #ifdef HAVE_LD_AS_NEEDED
diff --git a/gcc/config/i386/gnu-user.h b/gcc/config/i386/gnu-user.h
index a4c88f1a848..8983dc9ecd7 100644
--- a/gcc/config/i386/gnu-user.h
+++ b/gcc/config/i386/gnu-user.h
@@ -77,9 +77,10 @@  along with GCC; see the file COPYING3.  If not see
 #define GNU_USER_TARGET_LINK_SPEC "-m %(link_emulation) %{shared:-shared} \
   %{!shared: \
     %{!static: \
-      %{rdynamic:-export-dynamic} \
-      -dynamic-linker %(dynamic_linker)} \
-      %{static:-static}}"
+      %{!static-pie: \
+	%{rdynamic:-export-dynamic} \
+	-dynamic-linker %(dynamic_linker)}} \
+      %{static:-static} %{static-pie:-static -pie --no-dynamic-linker -z text}}"
 
 #undef	LINK_SPEC
 #define LINK_SPEC GNU_USER_TARGET_LINK_SPEC
diff --git a/gcc/config/i386/gnu-user64.h b/gcc/config/i386/gnu-user64.h
index 39f5ef6a68b..6fc9eae6f6b 100644
--- a/gcc/config/i386/gnu-user64.h
+++ b/gcc/config/i386/gnu-user64.h
@@ -59,11 +59,12 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
   %{shared:-shared} \
   %{!shared: \
     %{!static: \
-      %{rdynamic:-export-dynamic} \
-      %{" SPEC_32 ":-dynamic-linker " GNU_USER_DYNAMIC_LINKER32 "} \
-      %{" SPEC_64 ":-dynamic-linker " GNU_USER_DYNAMIC_LINKER64 "} \
-      %{" SPEC_X32 ":-dynamic-linker " GNU_USER_DYNAMIC_LINKERX32 "}} \
-    %{static:-static}}"
+      %{!static-static: \
+	%{rdynamic:-export-dynamic} \
+	%{" SPEC_32 ":-dynamic-linker " GNU_USER_DYNAMIC_LINKER32 "} \
+	%{" SPEC_64 ":-dynamic-linker " GNU_USER_DYNAMIC_LINKER64 "} \
+	%{" SPEC_X32 ":-dynamic-linker " GNU_USER_DYNAMIC_LINKERX32 "}}} \
+    %{static:-static} %{static-pie:-static -pie --no-dynamic-linker -z text}}"
 
 #undef	LINK_SPEC
 #define LINK_SPEC GNU_USER_TARGET_LINK_SPEC
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index cc0f5a00a4f..322bde9178f 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -496,7 +496,7 @@  Objective-C and Objective-C++ Dialects}.
 @xref{Link Options,,Options for Linking}.
 @gccoptlist{@var{object-file-name}  -fuse-ld=@var{linker}  -l@var{library} @gol
 -nostartfiles  -nodefaultlibs  -nostdlib  -pie  -pthread  -rdynamic @gol
--s  -static  -static-libgcc  -static-libstdc++ @gol
+-s  -static -static-pie -static-libgcc  -static-libstdc++ @gol
 -static-libasan  -static-libtsan  -static-liblsan  -static-libubsan @gol
 -static-libmpx  -static-libmpxwrappers @gol
 -shared  -shared-libgcc  -symbolic @gol
@@ -11780,6 +11780,15 @@  or model suboptions) when you specify this linker option.
 @opindex no-pie
 Don't produce a position independent executable.
 
+@item -static-pie
+@opindex static-pie
+Produce a static position independent executable on targets that support
+it.  A static position independent executable is similar to static
+executable, but can be loaded at any address without a dynamic linker.
+For predictable results, you must also specify the same set of options
+used for compilation (@option{-fpie}, @option{-fPIE}, or model
+suboptions) when you specify this linker option.
+
 @item -pthread
 @opindex pthread
 Link with the POSIX threads library.  This option is supported on 
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 987eff55aa6..1b60d59726e 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -1015,9 +1015,10 @@  proper position among the other output files.  */
 #endif
 
 /* -u* was put back because both BSD and SysV seem to support it.  */
-/* %{static|no-pie:} simply prevents an error message:
+/* %{static|no-pie|static-pie:} simply prevents an error message:
    1. If the target machine doesn't handle -static.
    2. If PIE isn't enabled by default.
+   3. If the target machine doesn't handle -static-pie.
  */
 /* We want %{T*} after %{L*} and %D so that it can be used to specify linker
    scripts which exist in user specified directories, or in standard
@@ -1035,7 +1036,7 @@  proper position among the other output files.  */
    "%{fuse-ld=*:-fuse-ld=%*} " LINK_COMPRESS_DEBUG_SPEC \
    "%X %{o*} %{e*} %{N} %{n} %{r}\
     %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!nostartfiles:%S}} \
-    %{static|no-pie:} %{L*} %(mfwrap) %(link_libgcc) " \
+    %{static|no-pie|static-pie:} %{L*} %(mfwrap) %(link_libgcc) " \
     VTABLE_VERIFICATION_SPEC " " SANITIZER_EARLY_SPEC " %o " CHKP_SPEC " \
     %{fopenacc|fopenmp|%:gt(%{ftree-parallelize-loops=*:%*} 1):\
 	%:include(libgomp.spec)%(link_gomp)}\
@@ -1670,17 +1671,19 @@  init_gcc_specs (struct obstack *obstack, const char *shared_name,
 {
   char *buf;
 
-  buf = concat ("%{static|static-libgcc:", static_name, " ", eh_name, "}"
-		"%{!static:%{!static-libgcc:"
 #if USE_LD_AS_NEEDED
+  buf = concat ("%{static|static-libgcc|static-pie:", static_name, " ", eh_name, "}"
+		"%{!static:%{!static-libgcc:%{!static-pie:"
 		"%{!shared-libgcc:",
 		static_name, " " LD_AS_NEEDED_OPTION " ",
 		shared_name, " " LD_NO_AS_NEEDED_OPTION
 		"}"
 		"%{shared-libgcc:",
 		shared_name, "%{!shared: ", static_name, "}"
-		"}"
+		"}}"
 #else
+  buf = concat ("%{static|static-libgcc:", static_name, " ", eh_name, "}"
+		"%{!static:%{!static-libgcc:"
 		"%{!shared:"
 		"%{!shared-libgcc:", static_name, " ", eh_name, "}"
 		"%{shared-libgcc:", shared_name, " ", static_name, "}"
@@ -1788,8 +1791,8 @@  init_spec (void)
 			    "-lgcc_eh"
 #ifdef USE_LIBUNWIND_EXCEPTIONS
 # ifdef HAVE_LD_STATIC_DYNAMIC
-			    " %{!static:" LD_STATIC_OPTION "} -lunwind"
-			    " %{!static:" LD_DYNAMIC_OPTION "}"
+			    " %{!static:%{!static-pie:" LD_STATIC_OPTION "}} -lunwind"
+			    " %{!static:%{!static-pie:" LD_DYNAMIC_OPTION "}}"
 # else
 			    " -lunwind"
 # endif