diff --git a/bfd/elf.c b/bfd/elf.c
index 380d64d699d..8e2ea1f2b36 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1775,6 +1775,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
 	    case DT_RELENT: name = "RELENT"; break;
 	    case DT_PLTREL: name = "PLTREL"; break;
 	    case DT_DEBUG: name = "DEBUG"; break;
+	    case DT_DEBUGSZ: name = "DEBUGSZ"; break;
 	    case DT_TEXTREL: name = "TEXTREL"; break;
 	    case DT_JMPREL: name = "JMPREL"; break;
 	    case DT_BIND_NOW: name = "BIND_NOW"; break;
diff --git a/bfd/elflink.c b/bfd/elflink.c
index c9d5da2dab4..94be0a0e69a 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -7241,6 +7241,11 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
   if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
     {
+      if (info->emit_dt_debugsz
+	  && bfd_link_executable (info)
+	  && !_bfd_elf_add_dynamic_entry (info, DT_DEBUGSZ, 0))
+	return false;
+
       if (elf_tdata (output_bfd)->cverdefs)
 	{
 	  unsigned int crefs = elf_tdata (output_bfd)->cverdefs;
diff --git a/binutils/readelf.c b/binutils/readelf.c
index bedd3893b59..92e696c5f0e 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -2198,6 +2198,7 @@ get_dynamic_type (Filedata * filedata, unsigned long type)
     case DT_RELENT:	return "RELENT";
     case DT_PLTREL:	return "PLTREL";
     case DT_DEBUG:	return "DEBUG";
+    case DT_DEBUGSZ:	return "DEBUGSZ";
     case DT_TEXTREL:	return "TEXTREL";
     case DT_JMPREL:	return "JMPREL";
     case DT_BIND_NOW:   return "BIND_NOW";
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 566529ee644..3f8606b11ad 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -429,6 +429,9 @@ struct bfd_link_info
   /* TRUE if .gnu.hash section should be created.  */
   unsigned int emit_gnu_hash: 1;
 
+  /* TRUE if DT_DEBUGSZ dynamic tag should be emitted.  */
+  unsigned int emit_dt_debugsz: 1;
+
   /* If TRUE reduce memory overheads, at the expense of speed. This will
      cause map file generation to use an O(N^2) algorithm and disable
      caching ELF symbol buffer.  */
diff --git a/include/elf/common.h b/include/elf/common.h
index 95ade894e98..f4f8467fe26 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -1125,6 +1125,7 @@
 #define DT_SYMINFO	0x6ffffeff
 #define DT_ADDRRNGHI	0x6ffffeff
 
+#define DT_DEBUGSZ	0x6ffffff8
 #define DT_RELACOUNT	0x6ffffff9
 #define DT_RELCOUNT	0x6ffffffa
 #define DT_FLAGS_1	0x6ffffffb
diff --git a/ld/NEWS b/ld/NEWS
index 6e0b56658d3..a8f4c026482 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* Add -z dt-debugsz and -z nodt-debugsz to ELF linker to control whether
+  DT_DEBUGSZ dynamic tag should be emitted.
+
 * Add -z indirect-extern-access/-z noindirect-extern-access to x86 ELF
   linker to control canonical function pointers and copy relocation.
 
diff --git a/ld/config.in b/ld/config.in
index 26d55a00d47..d5b2a1f948d 100644
--- a/ld/config.in
+++ b/ld/config.in
@@ -7,6 +7,10 @@
 #endif
 #define __CONFIG_H__ 1
 
+/* Define to 1 if you want to emit DT_DEBUGSZ dynamic tag in the ELF linker by
+   default. */
+#undef DEFAULT_EMIT_DT_DEBUGSZ
+
 /* Define to 1 if you want to emit gnu hash in the ELF linker by default. */
 #undef DEFAULT_EMIT_GNU_HASH
 
diff --git a/ld/configure b/ld/configure
index 33b7de33d1d..d4440f97857 100755
--- a/ld/configure
+++ b/ld/configure
@@ -838,6 +838,7 @@ enable_textrel_check
 enable_separate_code
 enable_error_handling_script
 enable_default_hash_style
+enable_dt_debugsz
 enable_initfini_array
 enable_libctf
 enable_werror
@@ -1513,6 +1514,7 @@ Optional Features:
                           --error-handling-script option
   --enable-default-hash-style={sysv,gnu,both}
                           use this default hash style
+  --disable-dt-debugsz    do not emit DT_DEBUGSZ dynamic tag
   --disable-initfini-array do not use .init_array/.fini_array sections
   --enable-libctf         Handle .ctf type-info sections [default=yes]
   --enable-werror         treat compile warnings as errors
@@ -11412,7 +11414,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11415 "configure"
+#line 11417 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11518,7 +11520,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11521 "configure"
+#line 11523 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -15363,6 +15365,27 @@ case "${enable_default_hash_style}" in
   *) ac_default_emit_gnu_hash=0 ;;
 esac
 
+# Check whether --enable-dt-debugsz was given.
+if test "${enable_dt_debugsz+set}" = set; then :
+  enableval=$enable_dt_debugsz; case "${enableval}" in
+ yes|no) ;;
+ *) as_fn_error $? "invalid --disable-dt-debugsz argument" "$LINENO" 5 ;;
+ esac
+else
+  emit_dt_debugsz=yes
+fi
+
+if test $emit_dt_debugsz = yes; then
+  ac_default_emit_dt_debugsz=1
+else
+  ac_default_emit_dt_debugsz=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_EMIT_DT_DEBUGSZ $ac_default_emit_dt_debugsz
+_ACEOF
+
+
 # Check whether --enable-initfini-array was given.
 if test "${enable_initfini_array+set}" = set; then :
   enableval=$enable_initfini_array; case "${enableval}" in
diff --git a/ld/configure.ac b/ld/configure.ac
index 8ea97c43cd4..09ee28474d5 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -243,6 +243,22 @@ case "${enable_default_hash_style}" in
   *) ac_default_emit_gnu_hash=0 ;;
 esac
 
+AC_ARG_ENABLE(dt-debugsz,
+AS_HELP_STRING([--disable-dt-debugsz],
+	       [do not emit DT_DEBUGSZ dynamic tag]),
+[case "${enableval}" in
+ yes|no) ;;
+ *) AC_MSG_ERROR([invalid --disable-dt-debugsz argument]) ;;
+ esac], [emit_dt_debugsz=yes])
+if test $emit_dt_debugsz = yes; then
+  ac_default_emit_dt_debugsz=1
+else
+  ac_default_emit_dt_debugsz=0
+fi
+AC_DEFINE_UNQUOTED([DEFAULT_EMIT_DT_DEBUGSZ],
+  [$ac_default_emit_dt_debugsz],
+  [Define to 1 if you want to emit DT_DEBUGSZ dynamic tag in the ELF linker by default.])
+
 AC_ARG_ENABLE(initfini-array,
 [  --disable-initfini-array do not use .init_array/.fini_array sections],
 [case "${enableval}" in
diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
index bfaf8130a3e..2e5ef68dc13 100644
--- a/ld/emultempl/elf.em
+++ b/ld/emultempl/elf.em
@@ -824,6 +824,10 @@ fragment <<EOF
 	link_info.combreloc = false;
       else if (strcmp (optarg, "nocopyreloc") == 0)
 	link_info.nocopyreloc = true;
+      else if (strcmp (optarg, "dt-debugsz") == 0)
+	link_info.emit_dt_debugsz = true;
+      else if (strcmp (optarg, "nodt-debugsz") == 0)
+	link_info.emit_dt_debugsz = false;
 EOF
 if test -n "$COMMONPAGESIZE"; then
 fragment <<EOF
diff --git a/ld/ld.texi b/ld/ld.texi
index 72b5c373ba1..0e02bcf72c0 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1258,6 +1258,10 @@ Report unresolved symbol references from regular object files.  This
 is done even if the linker is creating a non-symbolic shared library.
 This option is the inverse of @samp{-z undefs}.
 
+@item dt-debugsz
+@itemx nodt-debugsz
+Emit DT_DEBUGSZ dynamic tag when building executables.
+
 @item dynamic-undefined-weak
 @itemx nodynamic-undefined-weak
 Make undefined weak symbols dynamic when building a dynamic object,
diff --git a/ld/ldmain.c b/ld/ldmain.c
index 02029237e1a..900085f29c7 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -338,6 +338,7 @@ main (int argc, char **argv)
   link_info.textrel_check = DEFAULT_LD_TEXTREL_CHECK;
   link_info.emit_hash = DEFAULT_EMIT_SYSV_HASH;
   link_info.emit_gnu_hash = DEFAULT_EMIT_GNU_HASH;
+  link_info.emit_dt_debugsz = DEFAULT_EMIT_DT_DEBUGSZ;
   link_info.callbacks = &link_callbacks;
   link_info.input_bfds_tail = &link_info.input_bfds;
   /* SVR4 linkers seem to set DT_INIT and DT_FINI based on magic _init
diff --git a/ld/lexsup.c b/ld/lexsup.c
index c128fe3a96b..5203c302c93 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -2040,6 +2040,8 @@ elf_shlib_list_options (FILE *file)
   fprintf (file, _("\
   -z nocombreloc              Don't merge dynamic relocs into one section\n"));
   fprintf (file, _("\
+  -z dt-debugsz               Emit DT_DEBUGSZ dynamic tag\n"));
+  fprintf (file, _("\
   -z global                   Make symbols in DSO available for subsequently\n\
                                 loaded objects\n"));
   fprintf (file, _("\
@@ -2063,6 +2065,8 @@ elf_shlib_list_options (FILE *file)
   fprintf (file, _("\
   -z nodlopen                 Mark DSO not available to dlopen\n"));
   fprintf (file, _("\
+  -z nodt-debugsz             Don't emit DT_DEBUGSZ dynamic tag\n"));
+  fprintf (file, _("\
   -z nodump                   Mark DSO not available to dldump\n"));
   fprintf (file, _("\
   -z now                      Mark object non-lazy runtime binding\n"));
diff --git a/ld/testsuite/config/default.exp b/ld/testsuite/config/default.exp
index 0795ea81bfb..d2f2c2460b0 100644
--- a/ld/testsuite/config/default.exp
+++ b/ld/testsuite/config/default.exp
@@ -310,6 +310,9 @@ if ![info exists LDFLAGS] then {
     set LDFLAGS {}
 }
 
+# Don't emit DT_DEBUGSZ.
+append LDFLAGS " -z nodt-debugsz"
+
 # Set LD_CLASS to "64bit" for a 64-bit *host* linker.
 if { ![info exists LD_CLASS] } then {
     set REAL_LD [findfile $base_dir/.libs/ld-new .libs/ld-new $LD [transform ld]]
diff --git a/ld/testsuite/ld-elf/dt-debugsz-1.d b/ld/testsuite/ld-elf/dt-debugsz-1.d
new file mode 100644
index 00000000000..e74739dee42
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-debugsz-1.d
@@ -0,0 +1,9 @@
+#source: start.s
+#ld: -pie -z dt-debugsz
+#readelf : -dW
+#target: *-*-linux* *-*-gnu* *-*-solaris* arm*-*-uclinuxfdpiceabi
+#xfail: ![check_pie_support]
+
+#...
+ 0x0*6ffffff8 \(DEBUGSZ\) +0x0
+#pass
diff --git a/ld/testsuite/ld-elf/dt-debugsz-2.d b/ld/testsuite/ld-elf/dt-debugsz-2.d
new file mode 100644
index 00000000000..0fac6abbe6e
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-debugsz-2.d
@@ -0,0 +1,10 @@
+#source: start.s
+#ld: -shared -z dt-debugsz
+#readelf : -dW
+#target: *-*-linux* *-*-gnu* *-*-solaris* arm*-*-uclinuxfdpiceabi
+#xfail: ![check_shared_lib_support]
+
+#failif
+#...
+ 0x0*6ffffff8 \(DEBUGSZ\) +0x0
+#...
