diff --git a/Makeconfig b/Makeconfig
index 2514db35f6..59fbd9ebf9 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -543,12 +543,13 @@ endif  # +link
 # ARM, gcc always produces different debugging symbols when invoked with
 # a -O greater than 0 than when invoked with -O0, regardless of anything else
 # we're using to suppress optimizations.  Therefore, we need to explicitly pass
-# -O0 to it through CFLAGS.
+# -O0 to it through CFLAGS. By side effect, any fortification needs to be
+# disabled as it needs -O greater than 0.
 # Additionally, the build system will try to -include $(common-objpfx)/config.h
 # when compiling the tests, which will throw an error if some special macros
 # (such as __OPTIMIZE__ and IS_IN_build) aren't defined.  To avoid this, we
 # tell gcc to define IS_IN_build.
-CFLAGS-printers-tests := -O0 -ggdb3 -DIS_IN_build
+CFLAGS-printers-tests := -O0 -ggdb3 -DIS_IN_build $(no-fortify-source)
 
 ifeq (yes,$(build-shared))
 # These indicate whether to link using the built ld.so or the installed one.
@@ -901,6 +902,16 @@ define elide-stack-protector
 $(if $(filter $(@F),$(patsubst %,%$(1),$(2))), $(no-stack-protector))
 endef
 
+# We might want to compile with fortify-source
+ifneq ($(fortify-source),)
++fortify-source=$(fortify-source)
+endif
+
+# Some routine can't be fortified like the ones used by fortify
+define elide-fortify-source
+$(if $(filter $(@F),$(patsubst %,%$(1),$(2))), $(no-fortify-source))
+endef
+
 # The program that makes Emacs-style TAGS files.
 ETAGS	:= etags
 
@@ -961,6 +972,16 @@ endif	# $(+cflags) == ""
 	   $(+stack-protector) -fno-common
 +gcc-nowarn := -w
 
+# We must filter out elf because the early bootstrap of the dynamic loader
+# cannot be fortified. Likewise we exclude dlfcn because it is entangled
+# with the loader. We must filter out csu because early startup, like the
+# loader, cannot be fortified. Lastly debug is the fortification routines
+# themselves and they cannot be fortified.
+do-fortify = $(filter-out elf dlfcn csu debug,$(subdir))
+ifeq ($(do-fortify),$(subdir))
++cflags += $(+fortify-source)
+endif
+
 # Each sysdeps directory can contain header files that both will be
 # used to compile and will be installed.  Each can also contain an
 # include/ subdirectory, whose header files will be used to compile
@@ -1010,7 +1031,7 @@ module-cppflags = $(if $(filter %.mk.i %.v.i,$(@F)),,$(module-cppflags-real))
 # Note that we can't use -std=* in CPPFLAGS, because it overrides
 # the implicit -lang-asm and breaks cpp behavior for .S files--notably
 # it causes cpp to stop predefining __ASSEMBLER__.
-CPPFLAGS = $(config-extra-cppflags) $(CPPUNDEFS) $(CPPFLAGS-config) \
+CPPFLAGS = $(config-extra-cppflags) $(CPPFLAGS-config) \
 	   $($(subdir)-CPPFLAGS) \
 	   $(+includes) $(defines) $(module-cppflags) \
 	   -include $(..)include/libc-symbols.h $(sysdep-CPPFLAGS) \
@@ -1049,6 +1070,8 @@ object-suffixes :=
 CPPFLAGS-.o = $(pic-default)
 # libc.a must be compiled with -fPIE/-fpie for static PIE.
 CFLAGS-.o = $(filter %frame-pointer,$(+cflags)) $(pie-default)
+CFLAGS-.o += $(call elide-fortify-source,.o,$(routines_no_fortify))
+CFLAGS-.o += $(call elide-fortify-source,_chk.o,$(routines_no_fortify))
 libtype.o := lib%.a
 object-suffixes += .o
 ifeq (yes,$(build-shared))
@@ -1058,6 +1081,8 @@ object-suffixes += .os
 pic-cppflags = -DPIC -DSHARED
 CPPFLAGS-.os = $(pic-cppflags)
 CFLAGS-.os = $(filter %frame-pointer,$(+cflags)) $(pic-ccflag)
+CFLAGS-.os += $(call elide-fortify-source,.os,$(routines_no_fortify))
+CFLAGS-.os += $(call elide-fortify-source,_chk.os,$(routines_no_fortify))
 libtype.os := lib%_pic.a
 # This can be changed by a sysdep makefile
 pic-ccflag = -fPIC
@@ -1077,6 +1102,8 @@ object-suffixes += .op
 CPPFLAGS-.op = -DPROF $(pic-default)
 # libc_p.a must be compiled with -fPIE/-fpie for static PIE.
 CFLAGS-.op = -pg $(pie-default)
+CFLAGS-.op += $(call elide-fortify-source,.op,$(routines_no_fortify))
+CFLAGS-.op += $(call elide-fortify-source,_chk.op,$(routines_no_fortify))
 libtype.op = lib%_p.a
 endif
 
diff --git a/config.make.in b/config.make.in
index 4afd37feaf..d487a4f4e9 100644
--- a/config.make.in
+++ b/config.make.in
@@ -64,6 +64,8 @@ have-fpie = @libc_cv_fpie@
 have-ssp = @libc_cv_ssp@
 stack-protector = @stack_protector@
 no-stack-protector = @no_stack_protector@
+fortify-source = @fortify_source@
+no-fortify-source = @no_fortify_source@
 have-selinux = @have_selinux@
 have-libaudit = @have_libaudit@
 have-libcap = @have_libcap@
@@ -101,7 +103,6 @@ CXX = @CXX@
 BUILD_CC = @BUILD_CC@
 CFLAGS = @CFLAGS@
 CPPFLAGS-config = @CPPFLAGS@
-CPPUNDEFS = @CPPUNDEFS@
 extra-nonshared-cflags = @extra_nonshared_cflags@
 rtld-early-cflags = @rtld_early_cflags@
 ASFLAGS-config = @ASFLAGS_config@
diff --git a/configure.ac b/configure.ac
index 21879c933c..ec4de6e551 100644
--- a/configure.ac
+++ b/configure.ac
@@ -466,6 +466,17 @@ AC_ARG_ENABLE([scv],
 
 AS_IF([[test "$use_scv" != "no"]],[AC_DEFINE(USE_PPC_SCV)])
 
+dnl Build glibc with _FORTIFY_SOURCE
+AC_ARG_ENABLE(fortify-source,
+              AS_HELP_STRING([--enable-fortify-source@<:@=1|2|3@:>@],
+                             [Use -D_FORTIFY_SOURCE=[1|2|3] to control code hardening, defaults to highest possible value for your system]),
+              [enable_fortify_source=$enableval],
+              [enable_fortify_source=no])
+case "$enable_fortify_source" in
+1|2|3|no|yes) ;;
+*) AC_MSG_ERROR([Not a valid argument for --enable-fortify-source: "$enable_fortify_source"]);;
+esac
+
 # We keep the original values in `$config_*' and never modify them, so we
 # can write them unchanged into config.make.  Everything else uses
 # $machine, $vendor, and $os, and changes them whenever convenient.
@@ -1559,24 +1570,37 @@ if test "x$have_selinux" = xyes; then
 fi
 AC_SUBST(have_selinux)
 
-CPPUNDEFS=
-dnl Check for silly hacked compilers predefining _FORTIFY_SOURCE.
-dnl Since we are building the implementations of the fortified functions here,
-dnl having the macro defined interacts very badly.
-dnl _FORTIFY_SOURCE requires compiler optimization level 1 (gcc -O1)
-dnl and above (see "man FEATURE_TEST_MACROS").
-dnl So do NOT replace AC_COMPILE_IFELSE with AC_PREPROC_IFELSE.
-AC_CACHE_CHECK([for _FORTIFY_SOURCE predefine], libc_cv_predef_fortify_source,
-[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
-#ifdef _FORTIFY_SOURCE
-# error bogon
-#endif]])],
-		[libc_cv_predef_fortify_source=no],
-		[libc_cv_predef_fortify_source=yes])])
-if test $libc_cv_predef_fortify_source = yes; then
-  CPPUNDEFS="${CPPUNDEFS:+$CPPUNDEFS }-U_FORTIFY_SOURCE"
-fi
-AC_SUBST(CPPUNDEFS)
+dnl Check if we support the requested _FORTIFY_SOURCE level
+dnl If not, then don't use it.
+dnl Note that _FORTIFY_SOURCE may have been set through FLAGS too.
+dnl _FORTIFY_SOURCE value will be selectively disabled for function that can't
+dnl support it
+fortify_source=""
+no_fortify_source="-Wp,-U_FORTIFY_SOURCE"
+
+AC_CACHE_CHECK([for __builtin_dynamic_object_size], [libc_cv___builtin_dynamic_object_size], [
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([], [__builtin_dynamic_object_size("", 0)])],
+        [libc_cv___builtin_dynamic_object_size=yes
+         AS_IF([test "$enable_fortify_source" = yes], [enable_fortify_source=3])],
+        [libc_cv___builtin_dynamic_object_size=no
+         AS_IF([test "$enable_fortify_source" = yes], [enable_fortify_source=2])])
+])
+
+AS_CASE([$enable_fortify_source],
+        [1|2], [libc_cv_fortify_source=yes],
+        [3], [AS_IF([test "$libc_cv___builtin_dynamic_object_size" = yes],
+                    [libc_cv_fortify_source=yes],
+                    [AC_MSG_ERROR([Compiler doesn't provide necessary support for _FORTIFY_SOURCE=3])])],
+        [libc_cv_fortify_source=no])
+
+AS_IF([test "$libc_cv_fortify_source" = yes],
+      [fortify_source="${no_fortify_source},-D_FORTIFY_SOURCE=${enable_fortify_source}"]
+      )
+
+AC_SUBST(enable_fortify_source)
+AC_SUBST(libc_cv_fortify_source)
+AC_SUBST(no_fortify_source)
+AC_SUBST(fortify_source)
 
 dnl Starting with binutils 2.35, GAS can attach multiple symbol versions
 dnl to one symbol (PR 23840).
diff --git a/elf/rtld-Rules b/elf/rtld-Rules
index 56bc4543de..365a3408f3 100644
--- a/elf/rtld-Rules
+++ b/elf/rtld-Rules
@@ -144,6 +144,6 @@ cpp-srcs-left := $(rtld-modules:%.os=%)
 lib := rtld
 include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
 
-rtld-CFLAGS += $(no-stack-protector)
+rtld-CFLAGS += $(no-stack-protector) $(no-fortify-source)
 
 endif
