public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v3] binutils, gdb: support zstd compressed debug sections
@ 2022-09-23  4:08 Fangrui Song
  2022-09-23 14:32 ` Simon Marchi
                   ` (4 more replies)
  0 siblings, 5 replies; 32+ messages in thread
From: Fangrui Song @ 2022-09-23  4:08 UTC (permalink / raw)
  To: Alan Modra, Jan Beulich, Nick Clifton, Simon Marchi
  Cc: binutils, gdb-patches, Fangrui Song

PR29397 PR29563: The new configure option --with-zstd defaults to auto.
If pkgconfig/libzstd.pc is found, define HAVE_ZSTD and support zstd
compressed debug sections for most tools.

* bfd: for addr2line, objdump --dwarf, gdb, etc
* gas: support --compress-debug-sections=zstd
* ld: support ELFCOMPRESS_ZSTD input and --compress-debug-sections=zstd
* objcopy: support ELFCOMPRESS_ZSTD input for
  --decompress-debug-sections and --compress-debug-sections=zstd
* gdb: support ELFCOMPRESS_ZSTD input.  The bfd change references zstd
  symbols, so gdb has to link against -lzstd in this patch.

If zstd is not supported, ELFCOMPRESS_ZSTD input triggers an error.  We
can avoid HAVE_ZSTD if binutils-gdb imports zstd/ like zlib/, but this
is too heavyweight, so don't do it for now.

```
% ld/ld-new a.o
ld/ld-new: a.o: section .debug_abbrev is compressed with zstd, but BFD is not built with zstd support
...

% ld/ld-new a.o --compress-debug-sections=zstd
ld/ld-new: --compress-debug-sections=zstd: ld is not built with zstd support

% binutils/objcopy --compress-debug-sections=zstd a.o b.o
binutils/objcopy: --compress-debug-sections=zstd: binutils is not built with zstd support

% binutils/objcopy b.o --decompress-debug-sections
binutils/objcopy: zstd.o: section .debug_abbrev is compressed with zstd, but BFD is not built with zstd support
...
```
---
Changes from v1:
* use PKG_CHECK_MODULES to check libzstd.pc

Changes from v2:
* Improve PKG_CHECK_MODULES, autoreconf -vf
* objcopy: check --compress-debug-sections=zstd in a !HAVE_ZSTD build
---
 bfd/Makefile.am                              |   4 +-
 bfd/Makefile.in                              |  13 +-
 bfd/aclocal.m4                               |   2 +
 bfd/bfd-in.h                                 |   3 +-
 bfd/bfd-in2.h                                |  11 +-
 bfd/bfd.c                                    |  26 +-
 bfd/compress.c                               |  72 +++-
 bfd/config.in                                |   3 +
 bfd/configure                                | 268 ++++++++++++-
 bfd/configure.ac                             |   3 +-
 bfd/elf.c                                    |  12 +
 bfd/elfxx-target.h                           |   6 +-
 bfd/section.c                                |   3 +-
 binutils/Makefile.in                         |   5 +-
 binutils/aclocal.m4                          |   1 +
 binutils/config.in                           |   3 +
 binutils/configure                           | 135 ++++++-
 binutils/configure.ac                        |   3 +-
 binutils/doc/binutils.texi                   |  16 +-
 binutils/objcopy.c                           |  19 +-
 binutils/testsuite/binutils-all/compress.exp |  44 +++
 config/zstd.m4                               |  24 ++
 configure                                    |  10 +
 configure.ac                                 |   3 +
 gas/Makefile.am                              |   4 +-
 gas/Makefile.in                              |  13 +-
 gas/aclocal.m4                               |   2 +
 gas/as.c                                     |  13 +-
 gas/compress-debug.c                         |  60 ++-
 gas/compress-debug.h                         |  10 +-
 gas/config.in                                |   3 +
 gas/configure                                | 268 ++++++++++++-
 gas/configure.ac                             |   3 +-
 gas/doc/as.texi                              |  11 +-
 gas/write.c                                  |  36 +-
 gdb/Makefile.in                              |   8 +-
 gdb/acinclude.m4                             |   3 +-
 gdb/config.in                                |   3 +
 gdb/configure                                | 136 ++++++-
 gdb/configure.ac                             |   4 +-
 ld/Makefile.am                               |   5 +-
 ld/Makefile.in                               |  11 +-
 ld/aclocal.m4                                |   1 +
 ld/config.in                                 |   3 +
 ld/configure                                 | 389 ++++++++++++-------
 ld/configure.ac                              |   7 +-
 ld/emultempl/elf.em                          |   9 +
 ld/ld.texi                                   |   5 +
 ld/ldmain.c                                  |   8 +-
 ld/lexsup.c                                  |   4 +-
 ld/testsuite/ld-elf/compress.exp             |  17 +
 51 files changed, 1470 insertions(+), 255 deletions(-)
 create mode 100644 config/zstd.m4

diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index c23dff6cac3..cfe903c63f0 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -57,7 +57,7 @@ ZLIBINC = @zlibinc@
 
 WARN_CFLAGS = @WARN_CFLAGS@
 NO_WERROR = @NO_WERROR@
-AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
+AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
 AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DLIBDIR='"$(libdir)"' @LARGEFILE_CPPFLAGS@
 if PLUGINS
 bfdinclude_HEADERS += $(INCDIR)/plugin-api.h
@@ -776,7 +776,7 @@ ofiles: stamp-ofiles ; @true
 libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
 EXTRA_libbfd_la_SOURCES = $(CFILES)
 libbfd_la_DEPENDENCIES = $(OFILES) ofiles
-libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB)
+libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS)
 libbfd_la_LDFLAGS += -release `cat libtool-soversion` @SHARED_LDFLAGS@
 
 # libtool will build .libs/libbfd.a.  We create libbfd.a in the build
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index 82843d2d61d..6be41a72a59 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -122,10 +122,12 @@ am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
 	$(top_srcdir)/../config/nls.m4 \
 	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/pkg.m4 \
 	$(top_srcdir)/../config/plugins.m4 \
 	$(top_srcdir)/../config/po.m4 \
 	$(top_srcdir)/../config/progtest.m4 \
-	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../config/zlib.m4 \
+	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
 	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
 	$(top_srcdir)/bfd.m4 $(top_srcdir)/warning.m4 \
@@ -399,6 +401,9 @@ PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
 PKGVERSION = @PKGVERSION@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
 POSUB = @POSUB@
 RANLIB = @RANLIB@
 REPORT_BUGS_TEXI = @REPORT_BUGS_TEXI@
@@ -416,6 +421,8 @@ WARN_CFLAGS = @WARN_CFLAGS@
 WARN_CFLAGS_FOR_BUILD = @WARN_CFLAGS_FOR_BUILD@
 WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
 XGETTEXT = @XGETTEXT@
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
@@ -520,7 +527,7 @@ libbfd_la_LDFLAGS = $(am__append_1) -release `cat libtool-soversion` \
 # case both are empty.
 ZLIB = @zlibdir@ -lz
 ZLIBINC = @zlibinc@
-AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
+AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
 AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DLIBDIR='"$(libdir)"' \
 	@LARGEFILE_CPPFLAGS@ @HDEFINES@ @COREFLAG@ @TDEFINES@ \
 	$(CSEARCH) $(CSWITCHES) $(HAVEVECS) @INCINTL@
@@ -1199,7 +1206,7 @@ OFILES = $(BFD_BACKENDS) $(BFD_MACHINES) @COREFILE@ @bfd64_libs@
 libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
 EXTRA_libbfd_la_SOURCES = $(CFILES)
 libbfd_la_DEPENDENCIES = $(OFILES) ofiles
-libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB)
+libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS)
 
 # libtool will build .libs/libbfd.a.  We create libbfd.a in the build
 # directory so that we don't have to convert all the programs that use
diff --git a/bfd/aclocal.m4 b/bfd/aclocal.m4
index 0f8aa1d4518..09b849dfc87 100644
--- a/bfd/aclocal.m4
+++ b/bfd/aclocal.m4
@@ -1176,10 +1176,12 @@ m4_include([../config/largefile.m4])
 m4_include([../config/lead-dot.m4])
 m4_include([../config/nls.m4])
 m4_include([../config/override.m4])
+m4_include([../config/pkg.m4])
 m4_include([../config/plugins.m4])
 m4_include([../config/po.m4])
 m4_include([../config/progtest.m4])
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index 8605056aefe..4765ea80536 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -342,7 +342,8 @@ enum compressed_debug_section_type
   COMPRESS_DEBUG_NONE = 0,
   COMPRESS_DEBUG = 1 << 0,
   COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1,
-  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2
+  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2,
+  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3
 };
 
 /* This structure is used to keep track of stabs in sections
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 79fcc4eb912..5c80956c79c 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -349,7 +349,8 @@ enum compressed_debug_section_type
   COMPRESS_DEBUG_NONE = 0,
   COMPRESS_DEBUG = 1 << 0,
   COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1,
-  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2
+  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2,
+  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3
 };
 
 /* This structure is used to keep track of stabs in sections
@@ -962,7 +963,8 @@ typedef struct bfd_section
   unsigned int compress_status : 2;
 #define COMPRESS_SECTION_NONE    0
 #define COMPRESS_SECTION_DONE    1
-#define DECOMPRESS_SECTION_SIZED 2
+#define DECOMPRESS_SECTION_ZLIB  2
+#define DECOMPRESS_SECTION_ZSTD  3
 
   /* The following flags are used by the ELF linker. */
 
@@ -6637,12 +6639,14 @@ struct bfd
 #define BFD_ARCHIVE_FULL_PATH  0x100000
 
 #define BFD_CLOSED_BY_CACHE    0x200000
+  /* Compress sections in this BFD with SHF_COMPRESSED zstd.  */
+#define BFD_COMPRESS_ZSTD      0x400000
 
   /* Flags bits to be saved in bfd_preserve_save.  */
 #define BFD_FLAGS_SAVED \
   (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
    | BFD_PLUGIN | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON \
-   | BFD_USE_ELF_STT_COMMON)
+   | BFD_USE_ELF_STT_COMMON | BFD_COMPRESS_ZSTD)
 
   /* Flags bits which are for BFD use only.  */
 #define BFD_FLAGS_FOR_BFD_USE_MASK \
@@ -7271,6 +7275,7 @@ void bfd_update_compression_header
 
 bool bfd_check_compression_header
    (bfd *abfd, bfd_byte *contents, asection *sec,
+    unsigned int *ch_type,
     bfd_size_type *uncompressed_size,
     unsigned int *uncompressed_alignment_power);
 
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 0a21db11fd6..5f2033bee7a 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -177,12 +177,15 @@ CODE_FRAGMENT
 .#define BFD_ARCHIVE_FULL_PATH  0x100000
 .
 .#define BFD_CLOSED_BY_CACHE    0x200000
+
+.  {* Compress sections in this BFD with SHF_COMPRESSED zstd.  *}
+.#define BFD_COMPRESS_ZSTD      0x400000
 .
 .  {* Flags bits to be saved in bfd_preserve_save.  *}
 .#define BFD_FLAGS_SAVED \
 .  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
 .   | BFD_PLUGIN | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON \
-.   | BFD_USE_ELF_STT_COMMON)
+.   | BFD_USE_ELF_STT_COMMON | BFD_COMPRESS_ZSTD)
 .
 .  {* Flags bits which are for BFD use only.  *}
 .#define BFD_FLAGS_FOR_BFD_USE_MASK \
@@ -2500,6 +2503,9 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
 	{
 	  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 	  struct bfd_elf_section_data * esd = elf_section_data (sec);
+	  const unsigned int ch_type = abfd->flags & BFD_COMPRESS_ZSTD
+					   ? ELFCOMPRESS_ZSTD
+					   : ELFCOMPRESS_ZLIB;
 
 	  /* Set the SHF_COMPRESSED bit.  */
 	  elf_section_flags (sec) |= SHF_COMPRESSED;
@@ -2507,7 +2513,7 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
 	  if (bed->s->elfclass == ELFCLASS32)
 	    {
 	      Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) contents;
-	      bfd_put_32 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+	      bfd_put_32 (abfd, ch_type, &echdr->ch_type);
 	      bfd_put_32 (abfd, sec->size, &echdr->ch_size);
 	      bfd_put_32 (abfd, 1u << sec->alignment_power,
 			  &echdr->ch_addralign);
@@ -2518,7 +2524,7 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
 	  else
 	    {
 	      Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) contents;
-	      bfd_put_32 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+	      bfd_put_32 (abfd, ch_type, &echdr->ch_type);
 	      bfd_put_32 (abfd, 0, &echdr->ch_reserved);
 	      bfd_put_64 (abfd, sec->size, &echdr->ch_size);
 	      bfd_put_64 (abfd, UINT64_C (1) << sec->alignment_power,
@@ -2553,14 +2559,15 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
    SYNOPSIS
 	bool bfd_check_compression_header
 	  (bfd *abfd, bfd_byte *contents, asection *sec,
+	  unsigned int *ch_type,
 	  bfd_size_type *uncompressed_size,
 	  unsigned int *uncompressed_alignment_power);
 
 DESCRIPTION
-	Check the compression header at CONTENTS of SEC in ABFD and
-	store the uncompressed size in UNCOMPRESSED_SIZE and the
-	uncompressed data alignment in UNCOMPRESSED_ALIGNMENT_POWER
-	if the compression header is valid.
+	Check the compression header at CONTENTS of SEC in ABFD and store the
+	ch_type in CH_TYPE, uncompressed size in UNCOMPRESSED_SIZE, and the
+	uncompressed data alignment in UNCOMPRESSED_ALIGNMENT_POWER if the
+	compression header is valid.
 
 RETURNS
 	Return TRUE if the compression header is valid.
@@ -2569,6 +2576,7 @@ RETURNS
 bool
 bfd_check_compression_header (bfd *abfd, bfd_byte *contents,
 			      asection *sec,
+			      unsigned int *ch_type,
 			      bfd_size_type *uncompressed_size,
 			      unsigned int *uncompressed_alignment_power)
 {
@@ -2591,7 +2599,9 @@ bfd_check_compression_header (bfd *abfd, bfd_byte *contents,
 	  chdr.ch_size = bfd_get_64 (abfd, &echdr->ch_size);
 	  chdr.ch_addralign = bfd_get_64 (abfd, &echdr->ch_addralign);
 	}
-      if (chdr.ch_type == ELFCOMPRESS_ZLIB
+      *ch_type = chdr.ch_type;
+      if ((chdr.ch_type == ELFCOMPRESS_ZLIB
+	   || chdr.ch_type == ELFCOMPRESS_ZSTD)
 	  && chdr.ch_addralign == (chdr.ch_addralign & -chdr.ch_addralign))
 	{
 	  *uncompressed_size = chdr.ch_size;
diff --git a/bfd/compress.c b/bfd/compress.c
index b2e39826e38..95c1f4c42d1 100644
--- a/bfd/compress.c
+++ b/bfd/compress.c
@@ -20,18 +20,31 @@
 
 #include "sysdep.h"
 #include <zlib.h>
+#ifdef HAVE_ZSTD
+#include <zstd.h>
+#endif
 #include "bfd.h"
+#include "elf-bfd.h"
 #include "libbfd.h"
 #include "safe-ctype.h"
 
 #define MAX_COMPRESSION_HEADER_SIZE 24
 
 static bool
-decompress_contents (bfd_byte *compressed_buffer,
+decompress_contents (bool is_zstd, bfd_byte *compressed_buffer,
 		     bfd_size_type compressed_size,
 		     bfd_byte *uncompressed_buffer,
 		     bfd_size_type uncompressed_size)
 {
+  if (is_zstd)
+    {
+#ifdef HAVE_ZSTD
+      size_t ret = ZSTD_decompress (uncompressed_buffer, uncompressed_size,
+				    compressed_buffer, compressed_size);
+      return !ZSTD_isError (ret);
+#endif
+    }
+
   z_stream strm;
   int rc;
 
@@ -69,7 +82,7 @@ decompress_contents (bfd_byte *compressed_buffer,
 }
 
 /* Compress data of the size specified in @var{uncompressed_size}
-   and pointed to by @var{uncompressed_buffer} using zlib and store
+   and pointed to by @var{uncompressed_buffer} using zlib/zstd and store
    as the contents field.  This function assumes the contents
    field was allocated using bfd_malloc() or equivalent.
 
@@ -150,9 +163,10 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
       sec->size = orig_uncompressed_size;
       if (decompress)
 	{
-	  if (!decompress_contents (uncompressed_buffer
-				    + orig_compression_header_size,
-				    zlib_size, buffer, buffer_size))
+	  if (!decompress_contents (
+		  sec->compress_status == DECOMPRESS_SECTION_ZSTD,
+		  uncompressed_buffer + orig_compression_header_size,
+		  zlib_size, buffer, buffer_size))
 	    {
 	      bfd_set_error (bfd_error_bad_value);
 	      bfd_release (abfd, buffer);
@@ -175,10 +189,23 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
     }
   else
     {
-      if (compress ((Bytef*) buffer + header_size,
-		    &compressed_size,
-		    (const Bytef*) uncompressed_buffer,
-		    uncompressed_size) != Z_OK)
+      if (abfd->flags & BFD_COMPRESS_ZSTD)
+	{
+#if HAVE_ZSTD
+	  compressed_size = ZSTD_compress (
+		  buffer + header_size, compressed_size, uncompressed_buffer,
+		  uncompressed_size, ZSTD_CLEVEL_DEFAULT);
+	  if (ZSTD_isError (compressed_size))
+	    {
+	      bfd_release (abfd, buffer);
+	      bfd_set_error (bfd_error_bad_value);
+	      return 0;
+	    }
+#endif
+	}
+      else if (compress ((Bytef *)buffer + header_size, &compressed_size,
+			 (const Bytef *)uncompressed_buffer, uncompressed_size)
+	       != Z_OK)
 	{
 	  bfd_release (abfd, buffer);
 	  bfd_set_error (bfd_error_bad_value);
@@ -237,6 +264,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
   bfd_size_type save_rawsize;
   bfd_byte *compressed_buffer;
   unsigned int compression_header_size;
+  const unsigned int compress_status = sec->compress_status;
 
   if (abfd->direction != write_direction && sec->rawsize != 0)
     sz = sec->rawsize;
@@ -248,7 +276,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
       return true;
     }
 
-  switch (sec->compress_status)
+  switch (compress_status)
     {
     case COMPRESS_SECTION_NONE:
       if (p == NULL)
@@ -298,7 +326,8 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
       *ptr = p;
       return true;
 
-    case DECOMPRESS_SECTION_SIZED:
+    case DECOMPRESS_SECTION_ZLIB:
+    case DECOMPRESS_SECTION_ZSTD:
       /* Read in the full compressed section contents.  */
       compressed_buffer = (bfd_byte *) bfd_malloc (sec->compressed_size);
       if (compressed_buffer == NULL)
@@ -316,7 +345,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
       /* Restore rawsize and size.  */
       sec->rawsize = save_rawsize;
       sec->size = save_size;
-      sec->compress_status = DECOMPRESS_SECTION_SIZED;
+      sec->compress_status = compress_status;
       if (!ret)
 	goto fail_compressed;
 
@@ -330,8 +359,10 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
 	/* Set header size to the zlib header size if it is a
 	   SHF_COMPRESSED section.  */
 	compression_header_size = 12;
-      if (!decompress_contents (compressed_buffer + compression_header_size,
-				sec->compressed_size - compression_header_size, p, sz))
+      if (!decompress_contents (compress_status == DECOMPRESS_SECTION_ZSTD,
+				compressed_buffer + compression_header_size,
+				sec->compressed_size - compression_header_size,
+				p, sz))
 	{
 	  bfd_set_error (bfd_error_bad_value);
 	  if (p != *ptr)
@@ -381,7 +412,8 @@ DESCRIPTION
 void
 bfd_cache_section_contents (asection *sec, void *contents)
 {
-  if (sec->compress_status == DECOMPRESS_SECTION_SIZED)
+  if (sec->compress_status == DECOMPRESS_SECTION_ZLIB
+      || sec->compress_status == DECOMPRESS_SECTION_ZSTD)
     sec->compress_status = COMPRESS_SECTION_DONE;
   sec->contents = contents;
   sec->flags |= SEC_IN_MEMORY;
@@ -418,6 +450,7 @@ bfd_is_section_compressed_with_header (bfd *abfd, sec_ptr sec,
   int compression_header_size;
   int header_size;
   unsigned int saved = sec->compress_status;
+  unsigned int ch_type;
   bool compressed;
 
   *uncompressed_align_pow_p = 0;
@@ -448,7 +481,7 @@ bfd_is_section_compressed_with_header (bfd *abfd, sec_ptr sec,
     {
       if (compression_header_size != 0)
 	{
-	  if (!bfd_check_compression_header (abfd, header, sec,
+	  if (!bfd_check_compression_header (abfd, header, sec, &ch_type,
 					     uncompressed_size_p,
 					     uncompressed_align_pow_p))
 	    compression_header_size = -1;
@@ -507,7 +540,7 @@ SYNOPSIS
 DESCRIPTION
 	Record compressed section size, update section size with
 	decompressed size and set compress_status to
-	DECOMPRESS_SECTION_SIZED.
+	DECOMPRESS_SECTION_{ZLIB,ZSTD}.
 
 	Return @code{FALSE} if the section is not a valid compressed
 	section.  Otherwise, return @code{TRUE}.
@@ -521,6 +554,7 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
   int header_size;
   bfd_size_type uncompressed_size;
   unsigned int uncompressed_alignment_power = 0;
+  unsigned int ch_type;
   z_stream strm;
 
   compression_header_size = bfd_get_compression_header_size (abfd, sec);
@@ -550,6 +584,7 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
       uncompressed_size = bfd_getb64 (header + 4);
     }
   else if (!bfd_check_compression_header (abfd, header, sec,
+					  &ch_type,
 					  &uncompressed_size,
 					  &uncompressed_alignment_power))
     {
@@ -569,7 +604,8 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
   sec->compressed_size = sec->size;
   sec->size = uncompressed_size;
   bfd_set_section_alignment (sec, uncompressed_alignment_power);
-  sec->compress_status = DECOMPRESS_SECTION_SIZED;
+  sec->compress_status = ch_type == ELFCOMPRESS_ZSTD ? DECOMPRESS_SECTION_ZSTD
+						     : DECOMPRESS_SECTION_ZLIB;
 
   return true;
 }
diff --git a/bfd/config.in b/bfd/config.in
index f54a3cacbea..a59304e0a66 100644
--- a/bfd/config.in
+++ b/bfd/config.in
@@ -232,6 +232,9 @@
 /* Define to 1 if you have the <windows.h> header file. */
 #undef HAVE_WINDOWS_H
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Define to the sub-directory in which libtool stores uninstalled libraries.
    */
 #undef LT_OBJDIR
diff --git a/bfd/configure b/bfd/configure
index 075d2ee0a1b..d905a7bf7a8 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -652,6 +652,11 @@ TDEFINES
 SHARED_LIBADD
 SHARED_LDFLAGS
 LIBM
+ZSTD_LIBS
+ZSTD_CFLAGS
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
 zlibinc
 zlibdir
 EXEEXT_FOR_BUILD
@@ -839,6 +844,7 @@ enable_maintainer_mode
 enable_install_libbfd
 enable_nls
 with_system_zlib
+with_zstd
 '
       ac_precious_vars='build_alias
 host_alias
@@ -848,7 +854,12 @@ CFLAGS
 LDFLAGS
 LIBS
 CPPFLAGS
-CPP'
+CPP
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
+ZSTD_CFLAGS
+ZSTD_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1511,6 +1522,8 @@ Optional Packages:
                           Binutils"
   --with-bugurl=URL       Direct users to URL to report a bug
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
 
 Some influential environment variables:
   CC          C compiler command
@@ -1521,6 +1534,13 @@ Some influential environment variables:
   CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
               you have headers in a nonstandard directory <include dir>
   CPP         C preprocessor
+  PKG_CONFIG  path to pkg-config utility
+  PKG_CONFIG_PATH
+              directories to add to pkg-config's search path
+  PKG_CONFIG_LIBDIR
+              path overriding pkg-config's built-in search path
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -11086,7 +11106,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11089 "configure"
+#line 11109 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11192,7 +11212,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11195 "configure"
+#line 11215 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12995,7 +13015,7 @@ $as_echo "#define USE_BINARY_FOPEN 1" >>confdefs.h
  ;;
 esac
 
-# Link in zlib if we can.  This allows us to read compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to read compressed debug sections.
 # This is used only by compress.c.
 
   # Use the system's zlib library.
@@ -13015,6 +13035,246 @@ fi
 
 
 
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=0.9.0
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	else
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		PKG_CONFIG=""
+	fi
+fi
+
+
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if test "$with_zstd" != no; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+fi
+
+
 save_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS -Werror"
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking compiler support for hidden visibility" >&5
diff --git a/bfd/configure.ac b/bfd/configure.ac
index 28f3d1afce6..d1b2f76b31a 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -230,9 +230,10 @@ AC_CHECK_DECLS([basename, ffs, stpcpy, asprintf, vasprintf, strnlen])
 
 BFD_BINARY_FOPEN
 
-# Link in zlib if we can.  This allows us to read compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to read compressed debug sections.
 # This is used only by compress.c.
 AM_ZLIB
+AM_ZSTD
 
 save_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS -Werror"
diff --git a/bfd/elf.c b/bfd/elf.c
index 16cea4f8aeb..e52fa458a5a 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1260,6 +1260,18 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
 		 abfd, name);
 	      return false;
 	    }
+#ifndef HAVE_ZSTD
+	  if (newsect->compress_status == DECOMPRESS_SECTION_ZSTD)
+	    {
+	      _bfd_error_handler
+		  /* xgettext:c-format */
+		  (_ ("%pB: section %s is compressed with zstd, but BFD "
+		      "is not built with zstd support"),
+		   abfd, name);
+	      newsect->compress_status = COMPRESS_SECTION_NONE;
+	      return false;
+	    }
+#endif
 	}
 
       if (abfd->is_linker_input)
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index feaba84bf2e..ca600bb5ddf 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -989,7 +989,8 @@ const bfd_target TARGET_BIG_SYM =
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS
    | DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS
-   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON),
+   | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD | BFD_CONVERT_ELF_COMMON
+   | BFD_USE_ELF_STT_COMMON),
 
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY
@@ -1093,7 +1094,8 @@ const bfd_target TARGET_LITTLE_SYM =
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS
    | DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS
-   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON),
+   | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD | BFD_CONVERT_ELF_COMMON
+   | BFD_USE_ELF_STT_COMMON),
 
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY
diff --git a/bfd/section.c b/bfd/section.c
index c7a02d729f2..614570e976e 100644
--- a/bfd/section.c
+++ b/bfd/section.c
@@ -392,7 +392,8 @@ CODE_FRAGMENT
 .  unsigned int compress_status : 2;
 .#define COMPRESS_SECTION_NONE    0
 .#define COMPRESS_SECTION_DONE    1
-.#define DECOMPRESS_SECTION_SIZED 2
+.#define DECOMPRESS_SECTION_ZLIB  2
+.#define DECOMPRESS_SECTION_ZSTD  3
 .
 .  {* The following flags are used by the ELF linker. *}
 .
diff --git a/binutils/Makefile.in b/binutils/Makefile.in
index 78d32b350e3..6de4e239408 100644
--- a/binutils/Makefile.in
+++ b/binutils/Makefile.in
@@ -156,7 +156,8 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/plugins.m4 \
 	$(top_srcdir)/../config/po.m4 \
 	$(top_srcdir)/../config/progtest.m4 \
-	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../config/zlib.m4 \
+	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
 	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
 	$(top_srcdir)/../bfd/version.m4 \
@@ -575,6 +576,8 @@ WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
 XGETTEXT = @XGETTEXT@
 YACC = `if [ -f ../bison/bison ]; then echo ../bison/bison -y -L$(srcdir)/../bison/; else echo @YACC@; fi`
 YFLAGS = -d
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
diff --git a/binutils/aclocal.m4 b/binutils/aclocal.m4
index a877fa7f873..28271f56279 100644
--- a/binutils/aclocal.m4
+++ b/binutils/aclocal.m4
@@ -1205,6 +1205,7 @@ m4_include([../config/plugins.m4])
 m4_include([../config/po.m4])
 m4_include([../config/progtest.m4])
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/binutils/config.in b/binutils/config.in
index c5fb919aa95..bee8c07e2f7 100644
--- a/binutils/config.in
+++ b/binutils/config.in
@@ -157,6 +157,9 @@
 /* Define to 1 if you have the <windows.h> header file. */
 #undef HAVE_WINDOWS_H
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Define as const if the declaration of iconv() needs const. */
 #undef ICONV_CONST
 
diff --git a/binutils/configure b/binutils/configure
index 1c518227f57..54d0f184da1 100755
--- a/binutils/configure
+++ b/binutils/configure
@@ -650,6 +650,8 @@ LTLIBICONV
 LIBICONV
 MSGPACK_LIBS
 MSGPACK_CFLAGS
+ZSTD_LIBS
+ZSTD_CFLAGS
 zlibinc
 zlibdir
 DEMANGLER_NAME
@@ -832,6 +834,7 @@ enable_build_warnings
 enable_nls
 enable_maintainer_mode
 with_system_zlib
+with_zstd
 with_msgpack
 enable_rpath
 with_libiconv_prefix
@@ -853,6 +856,8 @@ DEBUGINFOD_CFLAGS
 DEBUGINFOD_LIBS
 YACC
 YFLAGS
+ZSTD_CFLAGS
+ZSTD_LIBS
 MSGPACK_CFLAGS
 MSGPACK_LIBS'
 
@@ -1517,6 +1522,8 @@ Optional Packages:
   --with-debuginfod       Enable debuginfo lookups with debuginfod
                           (auto/yes/no)
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
   --with-msgpack          Enable msgpack support (auto/yes/no)
   --with-gnu-ld           assume the C compiler uses GNU ld default=no
   --with-libiconv-prefix[=DIR]  search for libiconv in DIR/include and DIR/lib
@@ -1547,6 +1554,8 @@ Some influential environment variables:
   YFLAGS      The list of arguments that will be passed by default to $YACC.
               This script will default YFLAGS to the empty string to avoid a
               default value of `-d' given by some make applications.
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
   MSGPACK_CFLAGS
               C compiler flags for MSGPACK, overriding pkg-config
   MSGPACK_LIBS
@@ -10804,7 +10813,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10807 "configure"
+#line 10816 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10910,7 +10919,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10913 "configure"
+#line 10922 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13468,7 +13477,7 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-# Link in zlib if we can.  This allows us to read compressed debug
+# Link in zlib/zstd if we can.  This allows us to read compressed debug
 # sections.  This is used only by readelf.c (objdump uses bfd for
 # reading compressed sections).
 
@@ -13490,6 +13499,126 @@ fi
 
 
 
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if test "$with_zstd" != no; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+fi
+
+
+
 case "${host}" in
 *-*-msdos* | *-*-go32* | *-*-mingw32* | *-*-cygwin* | *-*-windows*)
 
diff --git a/binutils/configure.ac b/binutils/configure.ac
index ec002d3f88f..c152b7f6733 100644
--- a/binutils/configure.ac
+++ b/binutils/configure.ac
@@ -265,10 +265,11 @@ fi
 
 AC_CHECK_DECLS([asprintf, environ, getc_unlocked, stpcpy, strnlen])
 
-# Link in zlib if we can.  This allows us to read compressed debug
+# Link in zlib/zstd if we can.  This allows us to read compressed debug
 # sections.  This is used only by readelf.c (objdump uses bfd for
 # reading compressed sections).
 AM_ZLIB
+AM_ZSTD
 
 BFD_BINARY_FOPEN
 
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 1499db5728c..34a4164eb94 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -2159,21 +2159,23 @@ ELF ABI.  Note - if compression would actually make a section
 @itemx --compress-debug-sections=zlib
 @itemx --compress-debug-sections=zlib-gnu
 @itemx --compress-debug-sections=zlib-gabi
+@itemx --compress-debug-sections=zstd
 For ELF files, these options control how DWARF debug sections are
 compressed.  @option{--compress-debug-sections=none} is equivalent
 to @option{--decompress-debug-sections}.
 @option{--compress-debug-sections=zlib} and
 @option{--compress-debug-sections=zlib-gabi} are equivalent to
 @option{--compress-debug-sections}.
-@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug
-sections using zlib.  The debug sections are renamed to begin with
-@samp{.zdebug} instead of @samp{.debug}.  Note - if compression would
-actually make a section @emph{larger}, then it is not compressed nor
-renamed.
+@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug sections
+using the obsoleted zlib-gnu format.  The debug sections are renamed to begin
+with @samp{.zdebug}.
+@option{--compress-debug-sections=zstd} compresses DWARF debug
+sections using zstd.  Note - if compression would actually make a section
+@emph{larger}, then it is not compressed nor renamed.
 
 @item --decompress-debug-sections
-Decompress DWARF debug sections using zlib.  The original section
-names of the compressed sections are restored.
+Decompress DWARF debug sections.  For a @samp{.zdebug} section, the original
+name is restored.
 
 @item --elf-stt-common=yes
 @itemx --elf-stt-common=no
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index 43261756a42..fc668f00bbc 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -232,7 +232,8 @@ static enum
   compress_zlib = compress | 1 << 1,
   compress_gnu_zlib = compress | 1 << 2,
   compress_gabi_zlib = compress | 1 << 3,
-  decompress = 1 << 4
+  compress_zstd = compress | 1 << 4,
+  decompress = 1 << 5
 } do_debug_sections = nothing;
 
 /* Whether to generate ELF common symbols with the STT_COMMON type.  */
@@ -678,8 +679,8 @@ copy_usage (FILE *stream, int exit_status)
                                    <commit>\n\
      --subsystem <name>[:<version>]\n\
                                    Set PE subsystem to <name> [& <version>]\n\
-     --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
-                                   Compress DWARF debug sections using zlib\n\
+     --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
+				   Compress DWARF debug sections\n\
      --decompress-debug-sections   Decompress DWARF debug sections using zlib\n\
      --elf-stt-common=[yes|no]     Generate ELF common symbols with STT_COMMON\n\
                                      type\n\
@@ -2659,7 +2660,8 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
       if ((do_debug_sections & compress) != 0
 	  && do_debug_sections != compress)
 	{
-	  non_fatal (_("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi] is unsupported on `%s'"),
+	  non_fatal (_ ("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi|"
+			"zstd] is unsupported on `%s'"),
 		     bfd_get_archive_filename (ibfd));
 	  return false;
 	}
@@ -3807,6 +3809,13 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
       if (do_debug_sections != compress_gnu_zlib)
 	ibfd->flags |= BFD_COMPRESS_GABI;
       break;
+    case compress_zstd:
+      ibfd->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD;
+#ifndef HAVE_ZSTD
+      fatal (_ ("--compress-debug-sections=zstd: binutils is not built with "
+		"zstd support"));
+#endif
+      break;
     case decompress:
       ibfd->flags |= BFD_DECOMPRESS;
       break;
@@ -5469,6 +5478,8 @@ copy_main (int argc, char *argv[])
 		do_debug_sections = compress_gnu_zlib;
 	      else if (strcasecmp (optarg, "zlib-gabi") == 0)
 		do_debug_sections = compress_gabi_zlib;
+	      else if (strcasecmp (optarg, "zstd") == 0)
+		do_debug_sections = compress_zstd;
 	      else
 		fatal (_("unrecognized --compress-debug-sections type `%s'"),
 		       optarg);
diff --git a/binutils/testsuite/binutils-all/compress.exp b/binutils/testsuite/binutils-all/compress.exp
index c88da74a987..4e74c824664 100644
--- a/binutils/testsuite/binutils-all/compress.exp
+++ b/binutils/testsuite/binutils-all/compress.exp
@@ -576,6 +576,50 @@ if { [regexp_diff objdump.out $srcdir/$subdir/dw2-3gabi.W] } then {
     pass "$testname"
 }
 
+if { [binutils_assemble_flags $srcdir/$subdir/dw2-1.S ${compressedfile}zstd.o --compress-debug-sections=zstd] } then {
+    set testname "objcopy compress debug sections with zstd"
+    set got [binutils_run $OBJCOPY "--compress-debug-sections=zstd ${testfile}.o ${copyfile}zstd.o"]
+    if ![string match "" $got] then {
+	fail "objcopy ($testname)"
+	return
+    }
+    send_log "cmp ${compressedfile}zstd.o ${copyfile}zstd.o\n"
+    verbose "cmp ${compressedfile}zstd.o ${copyfile}zstd.o"
+    set src1 ${compressedfile}zstd.o
+    set src2 ${copyfile}zstd.o
+    set status [remote_exec build cmp "${src1} ${src2}"]
+    set exec_output [lindex $status 1]
+    set exec_output [prune_warnings $exec_output]
+    if ![string match "" $exec_output] then {
+	send_log "$exec_output\n"
+	verbose "$exec_output" 1
+	fail "objcopy ($testname)"
+    } else {
+	pass "objcopy ($testname)"
+    }
+
+    set testname "objcopy decompress compressed debug sections with zstd"
+    set got [binutils_run $OBJCOPY "--decompress-debug-sections ${compressedfile}zstd.o ${copyfile}zstd.o"]
+    if ![string match "" $got] then {
+	fail "objcopy ($testname)"
+	return
+    }
+    send_log "cmp ${testfile}.o ${copyfile}zstd.o\n"
+    verbose "cmp ${testfile}.o ${copyfile}zstd.o"
+    set src1 ${testfile}.o
+    set src2 ${copyfile}zstd.o
+    set status [remote_exec build cmp "${src1} ${src2}"]
+    set exec_output [lindex $status 1]
+    set exec_output [prune_warnings $exec_output]
+    if ![string match "" $exec_output] then {
+	send_log "$exec_output\n"
+	verbose "$exec_output" 1
+	fail "objcopy ($testname)"
+    } else {
+	pass "objcopy ($testname)"
+    }
+}
+
 proc convert_test { testname  as_flags  objcop_flags } {
     global srcdir
     global subdir
diff --git a/config/zstd.m4 b/config/zstd.m4
new file mode 100644
index 00000000000..93ae17b89d3
--- /dev/null
+++ b/config/zstd.m4
@@ -0,0 +1,24 @@
+dnl Copyright (C) 2022 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl Enable features using the zstd library.
+AC_DEFUN([AM_ZSTD],
+[
+AC_ARG_WITH(zstd,
+  [AS_HELP_STRING([--with-zstd], [support zstd compressed debug sections (default=auto)])],
+  [], [with_zstd=auto])
+
+if test "$with_zstd" != no; then
+  PKG_CHECK_MODULES(ZSTD, [libzstd], [
+    AC_DEFINE(HAVE_ZSTD, 1, [Define to 1 if zstd is enabled.])
+  ], [
+    if test "$with_zstd" = yes; then
+      AC_MSG_ERROR([--with-zstd was given, but pkgconfig/libzstd.pc is not found])
+    fi
+  ])
+fi
+])
diff --git a/configure b/configure
index d75f47a1e95..f14e0efd675 100755
--- a/configure
+++ b/configure
@@ -785,6 +785,7 @@ ac_user_opts='
 enable_option_checking
 with_build_libsubdir
 with_system_zlib
+with_zstd
 enable_as_accelerator_for
 enable_offload_targets
 enable_gold
@@ -1567,6 +1568,8 @@ Optional Packages:
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
   --with-build-libsubdir=DIR  Directory where to find libraries for build system
   --with-system-zlib      use installed libz
+  --with-zstd             Support zstd compressed debug sections
+                          (default=auto)
   --with-mpc=PATH         specify prefix directory for installed MPC package.
                           Equivalent to --with-mpc-include=PATH/include plus
                           --with-mpc-lib=PATH/lib
@@ -2925,6 +2928,13 @@ if test x$with_system_zlib = xyes ; then
   noconfigdirs="$noconfigdirs zlib"
 fi
 
+
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+fi
+
+
 # Don't compile the bundled readline/libreadline.a if --with-system-readline
 # is provided.
 if test x$with_system_readline = xyes ; then
diff --git a/configure.ac b/configure.ac
index ae18d436aca..0152c69292e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -246,6 +246,9 @@ if test x$with_system_zlib = xyes ; then
   noconfigdirs="$noconfigdirs zlib"
 fi
 
+AC_ARG_WITH(zstd,
+[AS_HELP_STRING([--with-zstd], [Support zstd compressed debug sections (default=auto)])])
+
 # Don't compile the bundled readline/libreadline.a if --with-system-readline
 # is provided.
 if test x$with_system_readline = xyes ; then
diff --git a/gas/Makefile.am b/gas/Makefile.am
index bd597398671..5f0f24abf8d 100644
--- a/gas/Makefile.am
+++ b/gas/Makefile.am
@@ -42,7 +42,7 @@ am__skipyacc =
 
 WARN_CFLAGS = @WARN_CFLAGS@ @WARN_WRITE_STRINGS@
 NO_WERROR = @NO_WERROR@
-AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
+AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
 
 TARG_CPU = @target_cpu_type@
 TARG_CPU_C = $(srcdir)/config/tc-@target_cpu_type@.c
@@ -407,7 +407,7 @@ STAGESTUFF = *.@OBJEXT@ $(noinst_PROGRAMS)
 
 as_new_SOURCES = $(GAS_CFILES)
 as_new_LDADD = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
-	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB)
+	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB) $(ZSTD_LIBS)
 as_new_DEPENDENCIES = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
 	$(extra_objects) $(GASLIBS) $(LIBINTL_DEP)
 EXTRA_as_new_SOURCES = $(CFILES) $(HFILES) $(TARGET_CPU_CFILES) \
diff --git a/gas/Makefile.in b/gas/Makefile.in
index c57d78f82c4..5a4dd702252 100644
--- a/gas/Makefile.in
+++ b/gas/Makefile.in
@@ -140,10 +140,12 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
 	$(top_srcdir)/../config/nls.m4 \
 	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/pkg.m4 \
 	$(top_srcdir)/../config/plugins.m4 \
 	$(top_srcdir)/../config/po.m4 \
 	$(top_srcdir)/../config/progtest.m4 \
-	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../config/zlib.m4 \
+	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
 	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
 	$(top_srcdir)/acinclude.m4 $(top_srcdir)/../bfd/version.m4 \
@@ -429,6 +431,9 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
 PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
 POSUB = @POSUB@
 RANLIB = @RANLIB@
 SED = @SED@
@@ -443,6 +448,8 @@ WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
 XGETTEXT = @XGETTEXT@
 YACC = `if [ -f ../bison/bison ] ; then echo ../bison/bison -y -L../bison/bison ; else echo @YACC@ ; fi`
 YFLAGS = @YFLAGS@
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
@@ -524,7 +531,7 @@ ZLIBINC = @zlibinc@
 # maintainer mode is disabled.  Avoid this.
 am__skiplex = 
 am__skipyacc = 
-AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
+AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
 TARG_CPU = @target_cpu_type@
 TARG_CPU_C = $(srcdir)/config/tc-@target_cpu_type@.c
 TARG_CPU_O = config/tc-@target_cpu_type@.@OBJEXT@
@@ -874,7 +881,7 @@ GASLIBS = @OPCODES_LIB@ ../bfd/libbfd.la ../libiberty/libiberty.a
 STAGESTUFF = *.@OBJEXT@ $(noinst_PROGRAMS)
 as_new_SOURCES = $(GAS_CFILES)
 as_new_LDADD = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
-	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB)
+	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB) $(ZSTD_LIBS)
 
 as_new_DEPENDENCIES = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
 	$(extra_objects) $(GASLIBS) $(LIBINTL_DEP)
diff --git a/gas/aclocal.m4 b/gas/aclocal.m4
index 70183124da7..722030c776f 100644
--- a/gas/aclocal.m4
+++ b/gas/aclocal.m4
@@ -1196,10 +1196,12 @@ m4_include([../config/lcmessage.m4])
 m4_include([../config/lead-dot.m4])
 m4_include([../config/nls.m4])
 m4_include([../config/override.m4])
+m4_include([../config/pkg.m4])
 m4_include([../config/plugins.m4])
 m4_include([../config/po.m4])
 m4_include([../config/progtest.m4])
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/gas/as.c b/gas/as.c
index 6268779cf90..35ad6b3ab3b 100644
--- a/gas/as.c
+++ b/gas/as.c
@@ -252,14 +252,14 @@ Options:\n\
   --alternate             initially turn on alternate macro syntax\n"));
 #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
   fprintf (stream, _("\
-  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
+  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
                           compress DWARF debug sections using zlib [default]\n"));
   fprintf (stream, _("\
   --nocompress-debug-sections\n\
                           don't compress DWARF debug sections\n"));
 #else
   fprintf (stream, _("\
-  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
+  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
                           compress DWARF debug sections using zlib\n"));
   fprintf (stream, _("\
   --nocompress-debug-sections\n\
@@ -736,6 +736,15 @@ This program has absolutely no warranty.\n"));
 		flag_compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
 	      else if (strcasecmp (optarg, "zlib-gabi") == 0)
 		flag_compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
+	      else if (strcasecmp (optarg, "zstd") == 0)
+		{
+#ifdef HAVE_ZSTD
+		  flag_compress_debug = COMPRESS_DEBUG_ZSTD;
+#else
+		  as_fatal (_ ("--compress-debug-sections=zstd: gas is not "
+			       "built with zstd support"));
+#endif
+		}
 	      else
 		as_fatal (_("Invalid --compress-debug-sections option: `%s'"),
 			  optarg);
diff --git a/gas/compress-debug.c b/gas/compress-debug.c
index c80dbeec4e7..3cd175f6e57 100644
--- a/gas/compress-debug.c
+++ b/gas/compress-debug.c
@@ -21,14 +21,23 @@
 #include "config.h"
 #include <stdio.h>
 #include <zlib.h>
+#if HAVE_ZSTD
+#include <zstd.h>
+#endif
 #include "ansidecl.h"
 #include "compress-debug.h"
 
 /* Initialize the compression engine.  */
 
-struct z_stream_s *
-compress_init (void)
+void *
+compress_init (bool use_zstd)
 {
+  if (use_zstd) {
+#if HAVE_ZSTD
+    return ZSTD_createCCtx ();
+#endif
+  }
+
   static struct z_stream_s strm;
 
   strm.zalloc = NULL;
@@ -42,22 +51,37 @@ compress_init (void)
    from the engine goes into the current frag on the obstack.  */
 
 int
-compress_data (struct z_stream_s *strm, const char **next_in,
-	       int *avail_in, char **next_out, int *avail_out)
+compress_data (bool use_zstd, void *ctx, const char **next_in, int *avail_in,
+	       char **next_out, int *avail_out)
 {
-  int out_size = 0;
-  int x;
+  if (use_zstd)
+    {
+#if HAVE_ZSTD
+      ZSTD_outBuffer ob = { *next_out, *avail_out, 0 };
+      ZSTD_inBuffer ib = { *next_in, *avail_in, 0 };
+      size_t ret = ZSTD_compressStream2 (ctx, &ob, &ib, ZSTD_e_continue);
+      *next_in += ib.pos;
+      *avail_in -= ib.pos;
+      *next_out += ob.pos;
+      *avail_out -= ob.pos;
+      if (ZSTD_isError (ret))
+	return -1;
+      return (int)ob.pos;
+#endif
+    }
+
+  struct z_stream_s *strm = ctx;
 
   strm->next_in = (Bytef *) (*next_in);
   strm->avail_in = *avail_in;
   strm->next_out = (Bytef *) (*next_out);
   strm->avail_out = *avail_out;
 
-  x = deflate (strm, Z_NO_FLUSH);
+  int x = deflate (strm, Z_NO_FLUSH);
   if (x != Z_OK)
     return -1;
 
-  out_size = *avail_out - strm->avail_out;
+  int out_size = *avail_out - strm->avail_out;
   *next_in = (char *) (strm->next_in);
   *avail_in = strm->avail_in;
   *next_out = (char *) (strm->next_out);
@@ -71,10 +95,28 @@ compress_data (struct z_stream_s *strm, const char **next_in,
    needed.  */
 
 int
-compress_finish (struct z_stream_s *strm, char **next_out,
+compress_finish (bool use_zstd, void *ctx, char **next_out,
 		 int *avail_out, int *out_size)
 {
+  if (use_zstd)
+    {
+#if HAVE_ZSTD
+      ZSTD_outBuffer ob = { *next_out, *avail_out, 0 };
+      ZSTD_inBuffer ib = { 0 };
+      size_t ret = ZSTD_compressStream2 (ctx, &ob, &ib, ZSTD_e_end);
+      *out_size = ob.pos;
+      *next_out += ob.pos;
+      *avail_out -= ob.pos;
+      if (ZSTD_isError (ret))
+	return -1;
+      if (ret == 0)
+	ZSTD_freeCCtx (ctx);
+      return ret ? 1 : 0;
+#endif
+    }
+
   int x;
+  struct z_stream_s *strm = ctx;
 
   strm->avail_in = 0;
   strm->next_out = (Bytef *) (*next_out);
diff --git a/gas/compress-debug.h b/gas/compress-debug.h
index 0183e269fef..87de0f8444e 100644
--- a/gas/compress-debug.h
+++ b/gas/compress-debug.h
@@ -21,19 +21,19 @@
 #ifndef COMPRESS_DEBUG_H
 #define COMPRESS_DEBUG_H
 
+#include <stdbool.h>
+
 struct z_stream_s;
 
 /* Initialize the compression engine.  */
-extern struct z_stream_s *
-compress_init (void);
+extern void *compress_init (bool);
 
 /* Stream the contents of a frag to the compression engine.  Output
    from the engine goes into the current frag on the obstack.  */
-extern int
-compress_data (struct z_stream_s *, const char **, int *, char **, int *);
+extern int compress_data (bool, void *, const char **, int *, char **, int *);
 
 /* Finish the compression and consume the remaining compressed output.  */
 extern int
-compress_finish (struct z_stream_s *, char **, int *, int *);
+compress_finish (bool, void *, char **, int *, int *);
 
 #endif /* COMPRESS_DEBUG_H */
diff --git a/gas/config.in b/gas/config.in
index e243fd277ee..0d1668a3eac 100644
--- a/gas/config.in
+++ b/gas/config.in
@@ -134,6 +134,9 @@
 /* Define to 1 if you have the <windows.h> header file. */
 #undef HAVE_WINDOWS_H
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Using i386 COFF? */
 #undef I386COFF
 
diff --git a/gas/configure b/gas/configure
index d0449a1d7ab..1833adffaa8 100755
--- a/gas/configure
+++ b/gas/configure
@@ -633,6 +633,11 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+ZSTD_LIBS
+ZSTD_CFLAGS
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
 zlibinc
 zlibdir
 LIBM
@@ -817,6 +822,7 @@ with_cpu
 enable_nls
 enable_maintainer_mode
 with_system_zlib
+with_zstd
 '
       ac_precious_vars='build_alias
 host_alias
@@ -828,7 +834,12 @@ LIBS
 CPPFLAGS
 CPP
 YACC
-YFLAGS'
+YFLAGS
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
+ZSTD_CFLAGS
+ZSTD_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1493,6 +1504,8 @@ Optional Packages:
   --with-cpu=CPU          default cpu variant is CPU (currently only supported
                           on ARC)
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
 
 Some influential environment variables:
   CC          C compiler command
@@ -1509,6 +1522,13 @@ Some influential environment variables:
   YFLAGS      The list of arguments that will be passed by default to $YACC.
               This script will default YFLAGS to the empty string to avoid a
               default value of `-d' given by some make applications.
+  PKG_CONFIG  path to pkg-config utility
+  PKG_CONFIG_PATH
+              directories to add to pkg-config's search path
+  PKG_CONFIG_LIBDIR
+              path overriding pkg-config's built-in search path
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -10702,7 +10722,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10705 "configure"
+#line 10725 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10808,7 +10828,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10811 "configure"
+#line 10831 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13945,7 +13965,7 @@ $as_echo "#define USE_BINARY_FOPEN 1" >>confdefs.h
  ;;
 esac
 
-# Link in zlib if we can.  This allows us to write compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to write compressed debug sections.
 
   # Use the system's zlib library.
   zlibdir="-L\$(top_builddir)/../zlib"
@@ -13964,6 +13984,246 @@ fi
 
 
 
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=0.9.0
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	else
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		PKG_CONFIG=""
+	fi
+fi
+
+
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if test "$with_zstd" != no; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+fi
+
+
 # Support for VMS timestamps via cross compile
 
 if test "$ac_cv_header_time_h" = yes; then
diff --git a/gas/configure.ac b/gas/configure.ac
index 21795a82bdd..8750ea21381 100644
--- a/gas/configure.ac
+++ b/gas/configure.ac
@@ -1004,8 +1004,9 @@ AC_CHECK_DECLS([asprintf, mempcpy, stpcpy])
 
 BFD_BINARY_FOPEN
 
-# Link in zlib if we can.  This allows us to write compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to write compressed debug sections.
 AM_ZLIB
+AM_ZSTD
 
 # Support for VMS timestamps via cross compile
 
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index e915893da86..01f49434021 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -711,16 +711,19 @@ given section @emph{larger} then it is not compressed.
 @itemx --compress-debug-sections=zlib
 @itemx --compress-debug-sections=zlib-gnu
 @itemx --compress-debug-sections=zlib-gabi
+@itemx --compress-debug-sections=zstd
 These options control how DWARF debug sections are compressed.
 @option{--compress-debug-sections=none} is equivalent to
 @option{--nocompress-debug-sections}.
 @option{--compress-debug-sections=zlib} and
 @option{--compress-debug-sections=zlib-gabi} are equivalent to
 @option{--compress-debug-sections}.
-@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug
-sections using zlib.  The debug sections are renamed to begin with
-@samp{.zdebug}.  Note if compression would make a given section
-@emph{larger} then it is not compressed nor renamed.
+@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug sections
+using the obsoleted zlib-gnu format.  The debug sections are renamed to begin
+with @samp{.zdebug}.
+@option{--compress-debug-sections=zstd} compresses DWARF debug
+sections using zstd.  Note - if compression would actually make a section
+@emph{larger}, then it is not compressed nor renamed.
 
 @end ifset
 
diff --git a/gas/write.c b/gas/write.c
index f76bbdb706e..0e49df7c03f 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -1413,7 +1413,7 @@ write_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
 }
 
 static int
-compress_frag (struct z_stream_s *strm, const char *contents, int in_size,
+compress_frag (bool use_zstd, void *ctx, const char *contents, int in_size,
 	       fragS **last_newf, struct obstack *ob)
 {
   int out_size;
@@ -1442,10 +1442,10 @@ compress_frag (struct z_stream_s *strm, const char *contents, int in_size,
 	as_fatal (_("can't extend frag"));
       next_out = obstack_next_free (ob);
       obstack_blank_fast (ob, avail_out);
-      out_size = compress_data (strm, &contents, &in_size,
-				&next_out, &avail_out);
+      out_size = compress_data (use_zstd, ctx, &contents, &in_size, &next_out,
+				&avail_out);
       if (out_size < 0)
-        return -1;
+	return -1;
 
       f->fr_fix += out_size;
       total_out_size += out_size;
@@ -1471,7 +1471,6 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   const char *section_name;
   char *compressed_name;
   char *header;
-  struct z_stream_s *strm;
   int x;
   flagword flags = bfd_section_flags (sec);
   unsigned int header_size, compression_header_size;
@@ -1485,21 +1484,22 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   if (!startswith (section_name, ".debug_"))
     return;
 
-  strm = compress_init ();
-  if (strm == NULL)
+  bool use_zstd = abfd->flags & BFD_COMPRESS_ZSTD;
+  void *ctx = compress_init (use_zstd);
+  if (ctx == NULL)
     return;
 
-  if (flag_compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
+  if (flag_compress_debug == COMPRESS_DEBUG_GNU_ZLIB)
+    {
+      compression_header_size = 0;
+      header_size = 12;
+    }
+  else
     {
       compression_header_size
 	= bfd_get_compression_header_size (stdoutput, NULL);
       header_size = compression_header_size;
     }
-  else
-    {
-      compression_header_size = 0;
-      header_size = 12;
-    }
 
   /* Create a new frag to contain the compression header.  */
   first_newf = frag_alloc (ob);
@@ -1531,7 +1531,7 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
       gas_assert (f->fr_type == rs_fill);
       if (f->fr_fix)
 	{
-	  out_size = compress_frag (strm, f->fr_literal, f->fr_fix,
+	  out_size = compress_frag (use_zstd, ctx, f->fr_literal, f->fr_fix,
 				    &last_newf, ob);
 	  if (out_size < 0)
 	    return;
@@ -1545,8 +1545,8 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
 	{
 	  while (count--)
 	    {
-	      out_size = compress_frag (strm, fill_literal, (int) fill_size,
-				        &last_newf, ob);
+	      out_size = compress_frag (use_zstd, ctx, fill_literal,
+					(int)fill_size, &last_newf, ob);
 	      if (out_size < 0)
 		return;
 	      compressed_size += out_size;
@@ -1579,7 +1579,7 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
 	as_fatal (_("can't extend frag"));
       next_out = obstack_next_free (ob);
       obstack_blank_fast (ob, avail_out);
-      x = compress_finish (strm, &next_out, &avail_out, &out_size);
+      x = compress_finish (use_zstd, ctx, &next_out, &avail_out, &out_size);
       if (x < 0)
 	return;
 
@@ -2540,6 +2540,8 @@ write_object_file (void)
     {
       if (flag_compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
 	stdoutput->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI;
+      else if (flag_compress_debug == COMPRESS_DEBUG_ZSTD)
+	stdoutput->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD;
       else
 	stdoutput->flags |= BFD_COMPRESS;
       bfd_map_over_sections (stdoutput, compress_debug, (char *) 0);
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2598b81d205..c528ee5aa80 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -173,6 +173,9 @@ BFD_CFLAGS = -I$(BFD_DIR) -I$(BFD_SRC)
 ZLIB = @zlibdir@ -lz
 ZLIBINC = @zlibinc@
 
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
+
 # Where is the decnumber library?  Typically in ../libdecnumber.
 LIBDECNUMBER_DIR = ../libdecnumber
 LIBDECNUMBER = $(LIBDECNUMBER_DIR)/libdecnumber.a
@@ -625,7 +628,7 @@ INTERNAL_CPPFLAGS = $(CPPFLAGS) @GUILE_CPPFLAGS@ @PYTHON_CPPFLAGS@ \
 INTERNAL_CFLAGS_BASE = \
 	$(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \
 	$(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) $(ZLIBINC) \
-	$(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
+	$(ZSTD_CFLAGS) $(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
 	$(INTL_CFLAGS) $(INCGNU) $(INCSUPPORT) $(LIBBACKTRACE_INC) \
 	$(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) $(SRCHIGH_CFLAGS) \
 	$(TOP_CFLAGS) $(PTHREAD_CFLAGS) $(DEBUGINFOD_CFLAGS)
@@ -647,7 +650,7 @@ INTERNAL_LDFLAGS = \
 # Libraries and corresponding dependencies for compiling gdb.
 # XM_CLIBS, defined in *config files, have host-dependent libs.
 # LIBIBERTY appears twice on purpose.
-CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) \
+CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) $(ZSTD_LIBS) \
         $(LIBSUPPORT) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
 	$(XM_CLIBS) $(GDBTKLIBS)  $(LIBBACKTRACE_LIB) \
 	@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
@@ -2298,6 +2301,7 @@ aclocal_m4_deps = \
 	../config/lcmessage.m4 \
 	../config/codeset.m4 \
 	../config/zlib.m4 \
+	../config/zstd.m4 \
 	../config/ax_pthread.m4
 
 $(srcdir)/aclocal.m4: @MAINTAINER_MODE_TRUE@ $(aclocal_m4_deps)
diff --git a/gdb/acinclude.m4 b/gdb/acinclude.m4
index 95ff2b6f35e..28846119dcb 100644
--- a/gdb/acinclude.m4
+++ b/gdb/acinclude.m4
@@ -43,6 +43,7 @@ m4_include([../config/lib-link.m4])
 m4_include([../config/iconv.m4])
 
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 
 m4_include([../gdbsupport/common.m4])
 
@@ -233,7 +234,7 @@ AC_DEFUN([GDB_AC_CHECK_BFD], [
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
   LIBS="-lbfd -liberty -lz $intl $LIBS"
   AC_CACHE_CHECK(
diff --git a/gdb/config.in b/gdb/config.in
index a4975c68aad..e13a409ec2d 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -589,6 +589,9 @@
 /* Define to 1 if you have the `XML_StopParser' function. */
 #undef HAVE_XML_STOPPARSER
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Define to 1 if your system has the _etext variable. */
 #undef HAVE__ETEXT
 
diff --git a/gdb/configure b/gdb/configure
index 4dbd0c3b13c..57cd165088a 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -747,6 +747,8 @@ READLINE_DEPS
 READLINE
 LTLIBICONV
 LIBICONV
+ZSTD_LIBS
+ZSTD_CFLAGS
 zlibinc
 zlibdir
 MIG
@@ -893,6 +895,7 @@ enable_codesign
 with_pkgversion
 with_bugurl
 with_system_zlib
+with_zstd
 with_gnu_ld
 enable_rpath
 with_libiconv_prefix
@@ -961,6 +964,8 @@ DEBUGINFOD_CFLAGS
 DEBUGINFOD_LIBS
 YACC
 YFLAGS
+ZSTD_CFLAGS
+ZSTD_LIBS
 XMKMF'
 ac_subdirs_all='testsuite
 gdbtk'
@@ -1641,6 +1646,8 @@ Optional Packages:
   --with-pkgversion=PKG   Use PKG in the version string in place of "GDB"
   --with-bugurl=URL       Direct users to URL to report a bug
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
   --with-gnu-ld           assume the C compiler uses GNU ld default=no
   --with-libiconv-prefix[=DIR]  search for libiconv in DIR/include and DIR/lib
   --without-libiconv-prefix     don't search for libiconv in includedir and libdir
@@ -1721,6 +1728,8 @@ Some influential environment variables:
   YFLAGS      The list of arguments that will be passed by default to $YACC.
               This script will default YFLAGS to the empty string to avoid a
               default value of `-d' given by some make applications.
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
   XMKMF       Path to xmkmf, Makefile generator for X Window System
 
 Use these variables to override the choices made by `configure' or to help
@@ -8242,7 +8251,8 @@ if test "$ac_res" != no; then :
 fi
 
 
-# Link in zlib if we can.  This allows us to read compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to read compressed debug
+# sections.
 
   # Use the system's zlib library.
   zlibdir="-L\$(top_builddir)/../zlib"
@@ -8262,6 +8272,126 @@ fi
 
 
 
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if test "$with_zstd" != no; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+fi
+
+
+
       if test "X$prefix" = "XNONE"; then
     acl_final_prefix="$ac_default_prefix"
   else
@@ -17281,7 +17411,7 @@ WIN32LIBS="$WIN32LIBS $WIN32APILIBS"
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
   LIBS="-lbfd -liberty -lz $intl $LIBS"
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ELF support in BFD" >&5
@@ -17396,7 +17526,7 @@ fi
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
   LIBS="-lbfd -liberty -lz $intl $LIBS"
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Mach-O support in BFD" >&5
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 215a91c5b27..e8cf808d280 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -460,8 +460,10 @@ AC_SEARCH_LIBS(gethostbyname, nsl)
 # Some systems (e.g. Solaris) have `socketpair' in libsocket.
 AC_SEARCH_LIBS(socketpair, socket)
 
-# Link in zlib if we can.  This allows us to read compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to read compressed debug
+# sections.
 AM_ZLIB
+AM_ZSTD
 
 AM_ICONV
 
diff --git a/ld/Makefile.am b/ld/Makefile.am
index d31021c13e2..bbe25f3aca2 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -45,7 +45,7 @@ ELF_CLFAGS=-DELF_LIST_OPTIONS=@elf_list_options@ \
 	   -DELF_PLT_UNWIND_LIST_OPTIONS=@elf_plt_unwind_list_options@
 WARN_CFLAGS = @WARN_CFLAGS@
 NO_WERROR = @NO_WERROR@
-AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS)
+AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS) $(ZSTD_CFLAGS)
 
 # We put the scripts in the directory $(scriptdir)/ldscripts.
 # We can't put the scripts in $(datadir) because the SEARCH_DIR
@@ -959,7 +959,8 @@ ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmai
 	ldbuildid.c
 ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) \
 		      $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL_DEP) $(JANSSON_LIBS)
-ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(JANSSON_LIBS)
+ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) \
+	       $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(ZSTD_LIBS) $(JANSSON_LIBS)
 
 # Dependency tracking for the generated emulation files.
 EXTRA_ld_new_SOURCES += $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES)
diff --git a/ld/Makefile.in b/ld/Makefile.in
index ee0c98f65b0..400eed2717e 100644
--- a/ld/Makefile.in
+++ b/ld/Makefile.in
@@ -126,7 +126,8 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/plugins.m4 \
 	$(top_srcdir)/../config/po.m4 \
 	$(top_srcdir)/../config/progtest.m4 \
-	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../config/zlib.m4 \
+	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
 	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
 	$(top_srcdir)/../bfd/version.m4 $(top_srcdir)/configure.ac
@@ -477,6 +478,8 @@ WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
 XGETTEXT = @XGETTEXT@
 YACC = `if [ -f ../bison/bison ]; then echo ../bison/bison -y -L$(srcdir)/../bison/; else echo @YACC@; fi`
 YFLAGS = -d
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
@@ -564,7 +567,7 @@ ELF_CLFAGS = -DELF_LIST_OPTIONS=@elf_list_options@ \
 	   -DELF_SHLIB_LIST_OPTIONS=@elf_shlib_list_options@ \
 	   -DELF_PLT_UNWIND_LIST_OPTIONS=@elf_plt_unwind_list_options@
 
-AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS)
+AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS) $(ZSTD_CFLAGS)
 
 # We put the scripts in the directory $(scriptdir)/ldscripts.
 # We can't put the scripts in $(datadir) because the SEARCH_DIR
@@ -1011,7 +1014,9 @@ ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmai
 ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) \
 		      $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL_DEP) $(JANSSON_LIBS)
 
-ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(JANSSON_LIBS)
+ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) \
+	       $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(ZSTD_LIBS) $(JANSSON_LIBS)
+
 #
 #
 # Build a dummy plugin using libtool.
diff --git a/ld/aclocal.m4 b/ld/aclocal.m4
index d20c542eed5..893e973e4f2 100644
--- a/ld/aclocal.m4
+++ b/ld/aclocal.m4
@@ -1203,6 +1203,7 @@ m4_include([../config/plugins.m4])
 m4_include([../config/po.m4])
 m4_include([../config/progtest.m4])
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/ld/config.in b/ld/config.in
index 0ccd79d59cd..3916740eee4 100644
--- a/ld/config.in
+++ b/ld/config.in
@@ -162,6 +162,9 @@
 /* Define to 1 if you have the <windows.h> header file. */
 #undef HAVE_WINDOWS_H
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Define to the sub-directory in which libtool stores uninstalled libraries.
    */
 #undef LT_OBJDIR
diff --git a/ld/configure b/ld/configure
index a1a07005400..175dd995b2b 100755
--- a/ld/configure
+++ b/ld/configure
@@ -646,6 +646,8 @@ elf_plt_unwind_list_options
 elf_shlib_list_options
 elf_list_options
 STRINGIFY
+ZSTD_LIBS
+ZSTD_CFLAGS
 zlibinc
 zlibdir
 NATIVE_LIB_DIRS
@@ -679,9 +681,6 @@ WARN_CFLAGS_FOR_BUILD
 WARN_CFLAGS
 JANSSON_LIBS
 JANSSON_CFLAGS
-PKG_CONFIG_LIBDIR
-PKG_CONFIG_PATH
-PKG_CONFIG
 enable_libctf
 ENABLE_LIBCTF_FALSE
 ENABLE_LIBCTF_TRUE
@@ -711,6 +710,9 @@ LD
 FGREP
 SED
 LIBTOOL
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
 EGREP
 CPP
 GREP
@@ -855,6 +857,7 @@ enable_werror
 enable_build_warnings
 enable_nls
 with_system_zlib
+with_zstd
 '
       ac_precious_vars='build_alias
 host_alias
@@ -868,14 +871,16 @@ CXX
 CXXFLAGS
 CCC
 CPP
-CXXCPP
 PKG_CONFIG
 PKG_CONFIG_PATH
 PKG_CONFIG_LIBDIR
+CXXCPP
 JANSSON_CFLAGS
 JANSSON_LIBS
 YACC
-YFLAGS'
+YFLAGS
+ZSTD_CFLAGS
+ZSTD_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1552,6 +1557,8 @@ Optional Packages:
   --with-lib-path=dir1:dir2...  set default LIB_PATH
   --with-sysroot=DIR Search for usr/lib et al within DIR.
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
 
 Some influential environment variables:
   CC          C compiler command
@@ -1564,12 +1571,12 @@ Some influential environment variables:
   CXX         C++ compiler command
   CXXFLAGS    C++ compiler flags
   CPP         C preprocessor
-  CXXCPP      C++ preprocessor
   PKG_CONFIG  path to pkg-config utility
   PKG_CONFIG_PATH
               directories to add to pkg-config's search path
   PKG_CONFIG_LIBDIR
               path overriding pkg-config's built-in search path
+  CXXCPP      C++ preprocessor
   JANSSON_CFLAGS
               C compiler flags for JANSSON, overriding pkg-config
   JANSSON_LIBS
@@ -1580,6 +1587,8 @@ Some influential environment variables:
   YFLAGS      The list of arguments that will be passed by default to $YACC.
               This script will default YFLAGS to the empty string to avoid a
               default value of `-d' given by some make applications.
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -5388,6 +5397,126 @@ $as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
 
 
 
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=0.9.0
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	else
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		PKG_CONFIG=""
+	fi
+fi
+
 case `pwd` in
   *\ * | *\	*)
     { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
@@ -11491,7 +11620,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11494 "configure"
+#line 11623 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11597,7 +11726,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11600 "configure"
+#line 11729 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -15586,126 +15715,6 @@ fi
 
 
 if test "x$enable_jansson" != "xno"; then
-
-
-
-
-
-
-
-if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
-	if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
-set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PKG_CONFIG+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $PKG_CONFIG in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-PKG_CONFIG=$ac_cv_path_PKG_CONFIG
-if test -n "$PKG_CONFIG"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
-$as_echo "$PKG_CONFIG" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_path_PKG_CONFIG"; then
-  ac_pt_PKG_CONFIG=$PKG_CONFIG
-  # Extract the first word of "pkg-config", so it can be a program name with args.
-set dummy pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $ac_pt_PKG_CONFIG in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
-if test -n "$ac_pt_PKG_CONFIG"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
-$as_echo "$ac_pt_PKG_CONFIG" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_pt_PKG_CONFIG" = x; then
-    PKG_CONFIG=""
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    PKG_CONFIG=$ac_pt_PKG_CONFIG
-  fi
-else
-  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
-fi
-
-fi
-if test -n "$PKG_CONFIG"; then
-	_pkg_min_version=0.9.0
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
-$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
-	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-	else
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-		PKG_CONFIG=""
-	fi
-fi
   if test -n "$PKG_CONFIG"; then :
 
 
@@ -17052,8 +17061,8 @@ $as_echo "#define HAVE_DECL_GETOPT 1" >>confdefs.h
 
 fi
 
-# Link in zlib if we can.  This allows us to read and write
-# compressed CTF sections.
+# Link in zlib/zstd if we can.  This allows us to read and write
+# compressed debug sections.
 
   # Use the system's zlib library.
   zlibdir="-L\$(top_builddir)/../zlib"
@@ -17072,6 +17081,126 @@ fi
 
 
 
+
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if test "$with_zstd" != no; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+fi
+
+
 # When converting linker scripts into strings for use in emulation
 # files, use astring.sed if the compiler supports ANSI string
 # concatenation, or ostring.sed otherwise.  This is to support the
diff --git a/ld/configure.ac b/ld/configure.ac
index eb55904c090..a491f9f1116 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -34,6 +34,7 @@ AC_PROG_GREP
 AC_GNU_SOURCE
 AC_USE_SYSTEM_EXTENSIONS
 AC_PROG_INSTALL
+PKG_PROG_PKG_CONFIG
 
 LT_INIT
 ACX_LARGEFILE
@@ -297,7 +298,6 @@ AC_ARG_ENABLE([jansson],
   [enable_jansson="no"])
 
 if test "x$enable_jansson" != "xno"; then
-  PKG_PROG_PKG_CONFIG
   AS_IF([test -n "$PKG_CONFIG"],
     [
       PKG_CHECK_MODULES(JANSSON, [jansson],
@@ -386,9 +386,10 @@ if test $ld_cv_decl_getopt_unistd_h = yes; then
 	    [Is the prototype for getopt in <unistd.h> in the expected format?])
 fi
 
-# Link in zlib if we can.  This allows us to read and write
-# compressed CTF sections.
+# Link in zlib/zstd if we can.  This allows us to read and write
+# compressed debug sections.
 AM_ZLIB
+AM_ZSTD
 
 # When converting linker scripts into strings for use in emulation
 # files, use astring.sed if the compiler supports ANSI string
diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
index c52484f35d3..acd66f907d1 100644
--- a/ld/emultempl/elf.em
+++ b/ld/emultempl/elf.em
@@ -668,6 +668,15 @@ gld${EMULATION_NAME}_handle_option (int optc)
 	link_info.compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
       else if (strcasecmp (optarg, "zlib-gabi") == 0)
 	link_info.compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
+      else if (strcasecmp (optarg, "zstd") == 0)
+	{
+#ifdef HAVE_ZSTD
+	  link_info.compress_debug = COMPRESS_DEBUG_ZSTD;
+#else
+	  einfo (_ ("%F%P: --compress-debug-sections=zstd: ld is not built "
+		    "with zstd support\n"));
+#endif
+	}
       else
 	einfo (_("%F%P: invalid --compress-debug-sections option: \`%s'\n"),
 	       optarg);
diff --git a/ld/ld.texi b/ld/ld.texi
index eabbec8faa9..9daed2e7e9f 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -2863,10 +2863,12 @@ but for most Linux based systems it will be @code{both}.
 @kindex --compress-debug-sections=zlib
 @kindex --compress-debug-sections=zlib-gnu
 @kindex --compress-debug-sections=zlib-gabi
+@kindex --compress-debug-sections=zstd
 @item --compress-debug-sections=none
 @itemx --compress-debug-sections=zlib
 @itemx --compress-debug-sections=zlib-gnu
 @itemx --compress-debug-sections=zlib-gabi
+@itemx --compress-debug-sections=zstd
 On ELF platforms, these options control how DWARF debug sections are
 compressed using zlib.
 
@@ -2880,6 +2882,9 @@ sets the SHF_COMPRESSED flag in the sections' headers.
 The @option{--compress-debug-sections=zlib} option is an alias for
 @option{--compress-debug-sections=zlib-gabi}.
 
+@option{--compress-debug-sections=zstd} compresses DWARF debug sections using
+zstd.
+
 Note that this option overrides any compression in input debug
 sections, so if a binary is linked with @option{--compress-debug-sections=none}
 for example, then any compressed debug sections in input files will be
diff --git a/ld/ldmain.c b/ld/ldmain.c
index 1bbddaaad32..71af5935b74 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -506,8 +506,12 @@ main (int argc, char **argv)
   if ((link_info.compress_debug & COMPRESS_DEBUG))
     {
       link_info.output_bfd->flags |= BFD_COMPRESS;
-      if (link_info.compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
-	link_info.output_bfd->flags |= BFD_COMPRESS_GABI;
+      if (link_info.compress_debug != COMPRESS_DEBUG_GNU_ZLIB)
+	{
+	  link_info.output_bfd->flags |= BFD_COMPRESS_GABI;
+	  if (link_info.compress_debug == COMPRESS_DEBUG_ZSTD)
+	    link_info.output_bfd->flags |= BFD_COMPRESS_ZSTD;
+	}
     }
 
   ldwrite ();
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 9225f71b3ce..299371fb775 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -2146,8 +2146,8 @@ elf_static_list_options (FILE *file)
   fprintf (file, _("\
   --package-metadata[=JSON]   Generate package metadata note\n"));
   fprintf (file, _("\
-  --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi]\n\
-                              Compress DWARF debug sections using zlib\n"));
+  --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi|zstd]\n\
+			      Compress DWARF debug sections\n"));
 #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
   fprintf (file, _("\
                                 Default: zlib-gabi\n"));
diff --git a/ld/testsuite/ld-elf/compress.exp b/ld/testsuite/ld-elf/compress.exp
index cfdd767b8ab..7b8a31cc41d 100644
--- a/ld/testsuite/ld-elf/compress.exp
+++ b/ld/testsuite/ld-elf/compress.exp
@@ -254,3 +254,20 @@ if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rt] } then {
 } else {
     pass "$test_name"
 }
+
+if { ![ld_assemble $as "--compress-debug-sections=zstd $srcdir/$subdir/empty.s" tmpdir/emptyzstd.o ] } {
+    return
+}
+set build_tests {
+  {"Build libzstdfoo.so with zstd compressed debug sections"
+   "-shared" "-fPIC -g -Wa,--compress-debug-sections=zstd -Wl,--compress-debug-sections=zstd"
+   {foo.c} {} "libzstdfoo.so"}
+}
+set run_tests {
+    {"Run zstdnormal with libzstdfoo.so with zstd compressed debug sections"
+     "tmpdir/begin.o tmpdir/libzstdfoo.so tmpdir/end.o -Wl,--compress-debug-sections=zstd" ""
+     {main.c} "zstdnormal" "normal.out" "-Wa,--compress-debug-sections=zstd"}
+}
+
+run_cc_link_tests $build_tests
+run_ld_link_exec_tests $run_tests
-- 
2.37.3.998.g577e59143f-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-23  4:08 [PATCH v3] binutils, gdb: support zstd compressed debug sections Fangrui Song
@ 2022-09-23 14:32 ` Simon Marchi
  2022-09-26  5:12   ` Alan Modra
  2022-09-23 15:45 ` Nick Clifton
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 32+ messages in thread
From: Simon Marchi @ 2022-09-23 14:32 UTC (permalink / raw)
  To: Fangrui Song, Alan Modra, Jan Beulich, Nick Clifton; +Cc: binutils, gdb-patches



On 2022-09-23 00:08, Fangrui Song wrote:
> PR29397 PR29563: The new configure option --with-zstd defaults to auto.
> If pkgconfig/libzstd.pc is found, define HAVE_ZSTD and support zstd
> compressed debug sections for most tools.
> 
> * bfd: for addr2line, objdump --dwarf, gdb, etc
> * gas: support --compress-debug-sections=zstd
> * ld: support ELFCOMPRESS_ZSTD input and --compress-debug-sections=zstd
> * objcopy: support ELFCOMPRESS_ZSTD input for
>   --decompress-debug-sections and --compress-debug-sections=zstd
> * gdb: support ELFCOMPRESS_ZSTD input.  The bfd change references zstd
>   symbols, so gdb has to link against -lzstd in this patch.
> 
> If zstd is not supported, ELFCOMPRESS_ZSTD input triggers an error.  We
> can avoid HAVE_ZSTD if binutils-gdb imports zstd/ like zlib/, but this
> is too heavyweight, so don't do it for now.
> 
> ```
> % ld/ld-new a.o
> ld/ld-new: a.o: section .debug_abbrev is compressed with zstd, but BFD is not built with zstd support
> ...
> 
> % ld/ld-new a.o --compress-debug-sections=zstd
> ld/ld-new: --compress-debug-sections=zstd: ld is not built with zstd support
> 
> % binutils/objcopy --compress-debug-sections=zstd a.o b.o
> binutils/objcopy: --compress-debug-sections=zstd: binutils is not built with zstd support
> 
> % binutils/objcopy b.o --decompress-debug-sections
> binutils/objcopy: zstd.o: section .debug_abbrev is compressed with zstd, but BFD is not built with zstd support
> ...
> ```
> ---
> Changes from v1:
> * use PKG_CHECK_MODULES to check libzstd.pc
> 
> Changes from v2:
> * Improve PKG_CHECK_MODULES, autoreconf -vf
> * objcopy: check --compress-debug-sections=zstd in a !HAVE_ZSTD build

Just one question: you moved PKG_PROG_PKG_CONFIG up in ld/configure.ac,
which I think is ok.  But what about the other configure.ac files, don't
they need PKG_PROG_PKG_CONFIG too?  gdb/configure.ac, for instance, uses
pkg-config for debuginfod.  So if the user passes --without-debuginfod
--with-zstd, I expect things to fail, as the pkg-config will be skipped.
binutils/configure.ac probably has the same problem, since it uses
PKG_CHECK_MODULES for msgpack.

I would suggest using PKG_PROG_PKG_CONFIG at the top of all configure.ac
that use AM_ZSTD, out of precaution.

Simon

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-23  4:08 [PATCH v3] binutils, gdb: support zstd compressed debug sections Fangrui Song
  2022-09-23 14:32 ` Simon Marchi
@ 2022-09-23 15:45 ` Nick Clifton
  2022-09-23 15:58   ` Simon Marchi
  2022-09-24  6:53 ` Enze Li
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 32+ messages in thread
From: Nick Clifton @ 2022-09-23 15:45 UTC (permalink / raw)
  To: Fangrui Song, Alan Modra, Jan Beulich, Simon Marchi; +Cc: binutils, gdb-patches

Hi Fangrui,

> PR29397 PR29563: The new configure option --with-zstd defaults to auto.
> If pkgconfig/libzstd.pc is found, define HAVE_ZSTD and support zstd
> compressed debug sections for most tools.

One small, but important point.  Please could you add entries to the gas/NEWS
binutils/NEWS and ld/NEWS files giving a brief description of this new feature.

Cheers
   Nick



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-23 15:45 ` Nick Clifton
@ 2022-09-23 15:58   ` Simon Marchi
  2022-09-23 18:20     ` Fangrui Song
  0 siblings, 1 reply; 32+ messages in thread
From: Simon Marchi @ 2022-09-23 15:58 UTC (permalink / raw)
  To: Nick Clifton, Fangrui Song, Alan Modra, Jan Beulich; +Cc: binutils, gdb-patches



On 2022-09-23 11:45, Nick Clifton wrote:
> Hi Fangrui,
> 
>> PR29397 PR29563: The new configure option --with-zstd defaults to auto.
>> If pkgconfig/libzstd.pc is found, define HAVE_ZSTD and support zstd
>> compressed debug sections for most tools.
> 
> One small, but important point.  Please could you add entries to the gas/NEWS
> binutils/NEWS and ld/NEWS files giving a brief description of this new feature.

I guess to gdb/NEWS, while at it :).

Simon

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-23 15:58   ` Simon Marchi
@ 2022-09-23 18:20     ` Fangrui Song
  2022-09-23 18:57       ` Simon Marchi
  0 siblings, 1 reply; 32+ messages in thread
From: Fangrui Song @ 2022-09-23 18:20 UTC (permalink / raw)
  To: Simon Marchi, Nick Clifton; +Cc: Alan Modra, Jan Beulich, binutils, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 4302 bytes --]

On 2022-09-23, Simon Marchi wrote:
>
>
>On 2022-09-23 11:45, Nick Clifton wrote:
>> Hi Fangrui,
>>
>>> PR29397 PR29563: The new configure option --with-zstd defaults to auto.
>>> If pkgconfig/libzstd.pc is found, define HAVE_ZSTD and support zstd
>>> compressed debug sections for most tools.

Hi Simon and Nick,

I have checked that `make all-gdb` works in a --enable-gdb --without-debuginfod build.

I then inspected the 2020 commits adding AC_DEBUGINFOD to
gdb/configure.ac and binutils/configure.ac. They come with no
PKG_PROG_PKG_CONFIG and config/debuginfod.m4 does not have
PKG_PROG_PKG_CONFIG, but they still work.  So I think AC_ZSTD doesn't
need PKG_PROG_PKG_CONFIG, either. Though I have no insight why it
behaves that way:)

>> One small, but important point.  Please could you add entries to the gas/NEWS
>> binutils/NEWS and ld/NEWS files giving a brief description of this new feature.
>
>I guess to gdb/NEWS, while at it :).
>
>Simon

Here are the NEWS entries :)
(As usual, it's available as the latest https://gitlab.com/MaskRay/binutils-gdb/-/commits/zstd)

----
   bfd/Makefile.am                              |   4 +-
@@ -58,2 +51,3 @@
   binutils/Makefile.in                         |   5 +-
+ binutils/NEWS                                |   6 +
   binutils/aclocal.m4                          |   1 +
@@ -70,2 +64,3 @@
   gas/Makefile.in                              |  13 +-
+ gas/NEWS                                     |   3 +
   gas/aclocal.m4                               |   2 +
@@ -80,2 +75,3 @@
   gdb/Makefile.in                              |   8 +-
+ gdb/NEWS                                     |   2 +
   gdb/acinclude.m4                             |   3 +-
@@ -86,2 +82,3 @@
   ld/Makefile.in                               |  11 +-
+ ld/NEWS                                      |   3 +
   ld/aclocal.m4                                |   1 +
@@ -95,3 +92,3 @@
   ld/testsuite/ld-elf/compress.exp             |  17 +
- 51 files changed, 1470 insertions(+), 255 deletions(-)
+ 55 files changed, 1484 insertions(+), 255 deletions(-)
   create mode 100644 config/zstd.m4
@@ -990,2 +987,18 @@
   abs_top_builddir = @abs_top_builddir@
+diff --git a/binutils/NEWS b/binutils/NEWS
+index 8c2c416c17e..073e9bc4647 100644
+--- a/binutils/NEWS
++++ b/binutils/NEWS
+@@ -1,5 +1,11 @@
+ -*- text -*-
+ 
++* objcopy --decompress-debug-sections now supports zstd compressed debug
++  sections.  The new option --compress-debug-sections=zstd compresses debug
++  sections with zstd.
++
++* addr2line and objdump --dwarf now support zstd compressed debug sections.
++
+ * The dlltool program now accepts --deterministic-libraries and
+   --non-deterministic-libraries as command line options to control whether or
+   not it generates deterministic output libraries.  If neither of these options
  diff --git a/binutils/aclocal.m4 b/binutils/aclocal.m4
@@ -1539,2 +1552,15 @@
   	$(extra_objects) $(GASLIBS) $(LIBINTL_DEP)
+diff --git a/gas/NEWS b/gas/NEWS
+index d61cdb9edd4..9a8b726b942 100644
+--- a/gas/NEWS
++++ b/gas/NEWS
+@@ -1,5 +1,8 @@
+ -*- text -*-
+ 
++* gas now supports --compress-debug-sections=zstd to compress
++  debug sections with zstd.
++
+ Changes in 2.39:
+ 
+ * Remove (rudimentary) support for the x86-64 sub-architectures Intel L1OM and
  diff --git a/gas/aclocal.m4 b/gas/aclocal.m4
@@ -2262,2 +2288,15 @@
   $(srcdir)/aclocal.m4: @MAINTAINER_MODE_TRUE@ $(aclocal_m4_deps)
+diff --git a/gdb/NEWS b/gdb/NEWS
+index 9619842bc03..1457c99ff04 100644
+--- a/gdb/NEWS
++++ b/gdb/NEWS
+@@ -57,6 +57,8 @@
+ 
+ * The Windows native target now supports target async.
+ 
++* gdb now supports zstd compressed debug sections (ELFCOMPRESS_ZSTD) for ELF.
++
+ * New commands
+ 
+ maintenance set ignore-prologue-end-flag on|off
  diff --git a/gdb/acinclude.m4 b/gdb/acinclude.m4
@@ -2582,2 +2621,15 @@
   # Build a dummy plugin using libtool.
+diff --git a/ld/NEWS b/ld/NEWS
+index 355752e6b24..dfe2690d9f2 100644
+--- a/ld/NEWS
++++ b/ld/NEWS
+@@ -1,5 +1,8 @@
+ -*- text -*-
+ 
++* ld now supports zstd compressed debug sections.  The new option
++  --compress-debug-sections=zstd compresses debug sections with zstd.
++
+ Changes in 2.39:
+ 
+ * The ELF linker will now generate a warning message if the stack is made
  diff --git a/ld/aclocal.m4 b/ld/aclocal.m4

[-- Attachment #2: v4-0001-binutils-gdb-support-zstd-compressed-debug-sectio.patch --]
[-- Type: text/x-diff, Size: 110131 bytes --]

From 5e60b8fac5190059c0c253a8241ddf9a9763afa0 Mon Sep 17 00:00:00 2001
From: Fangrui Song <maskray@google.com>
Date: Fri, 23 Sep 2022 11:18:36 -0700
Subject: [PATCH v4] binutils, gdb: support zstd compressed debug sections

PR29397 PR29563: The new configure option --with-zstd defaults to auto.
If pkgconfig/libzstd.pc is found, define HAVE_ZSTD and support zstd
compressed debug sections for most tools.

* bfd: for addr2line, objdump --dwarf, gdb, etc
* gas: support --compress-debug-sections=zstd
* ld: support ELFCOMPRESS_ZSTD input and --compress-debug-sections=zstd
* objcopy: support ELFCOMPRESS_ZSTD input for
  --decompress-debug-sections and --compress-debug-sections=zstd
* gdb: support ELFCOMPRESS_ZSTD input.  The bfd change references zstd
  symbols, so gdb has to link against -lzstd in this patch.

If zstd is not supported, ELFCOMPRESS_ZSTD input triggers an error.  We
can avoid HAVE_ZSTD if binutils-gdb imports zstd/ like zlib/, but this
is too heavyweight, so don't do it for now.

```
% ld/ld-new a.o
ld/ld-new: a.o: section .debug_abbrev is compressed with zstd, but BFD is not built with zstd support
...

% ld/ld-new a.o --compress-debug-sections=zstd
ld/ld-new: --compress-debug-sections=zstd: ld is not built with zstd support

% binutils/objcopy --compress-debug-sections=zstd a.o b.o
binutils/objcopy: --compress-debug-sections=zstd: binutils is not built with zstd support

% binutils/objcopy b.o --decompress-debug-sections
binutils/objcopy: zstd.o: section .debug_abbrev is compressed with zstd, but BFD is not built with zstd support
...
```
---
 bfd/Makefile.am                              |   4 +-
 bfd/Makefile.in                              |  13 +-
 bfd/aclocal.m4                               |   2 +
 bfd/bfd-in.h                                 |   3 +-
 bfd/bfd-in2.h                                |  11 +-
 bfd/bfd.c                                    |  26 +-
 bfd/compress.c                               |  72 +++-
 bfd/config.in                                |   3 +
 bfd/configure                                | 268 ++++++++++++-
 bfd/configure.ac                             |   3 +-
 bfd/elf.c                                    |  12 +
 bfd/elfxx-target.h                           |   6 +-
 bfd/section.c                                |   3 +-
 binutils/Makefile.in                         |   5 +-
 binutils/NEWS                                |   6 +
 binutils/aclocal.m4                          |   1 +
 binutils/config.in                           |   3 +
 binutils/configure                           | 135 ++++++-
 binutils/configure.ac                        |   3 +-
 binutils/doc/binutils.texi                   |  16 +-
 binutils/objcopy.c                           |  19 +-
 binutils/testsuite/binutils-all/compress.exp |  44 +++
 config/zstd.m4                               |  24 ++
 configure                                    |  10 +
 configure.ac                                 |   3 +
 gas/Makefile.am                              |   4 +-
 gas/Makefile.in                              |  13 +-
 gas/NEWS                                     |   3 +
 gas/aclocal.m4                               |   2 +
 gas/as.c                                     |  13 +-
 gas/compress-debug.c                         |  60 ++-
 gas/compress-debug.h                         |  10 +-
 gas/config.in                                |   3 +
 gas/configure                                | 268 ++++++++++++-
 gas/configure.ac                             |   3 +-
 gas/doc/as.texi                              |  11 +-
 gas/write.c                                  |  36 +-
 gdb/Makefile.in                              |   8 +-
 gdb/NEWS                                     |   2 +
 gdb/acinclude.m4                             |   3 +-
 gdb/config.in                                |   3 +
 gdb/configure                                | 136 ++++++-
 gdb/configure.ac                             |   4 +-
 ld/Makefile.am                               |   5 +-
 ld/Makefile.in                               |  11 +-
 ld/NEWS                                      |   3 +
 ld/aclocal.m4                                |   1 +
 ld/config.in                                 |   3 +
 ld/configure                                 | 389 ++++++++++++-------
 ld/configure.ac                              |   7 +-
 ld/emultempl/elf.em                          |   9 +
 ld/ld.texi                                   |   5 +
 ld/ldmain.c                                  |   8 +-
 ld/lexsup.c                                  |   4 +-
 ld/testsuite/ld-elf/compress.exp             |  17 +
 55 files changed, 1484 insertions(+), 255 deletions(-)
 create mode 100644 config/zstd.m4

diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index c23dff6cac3..cfe903c63f0 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -57,7 +57,7 @@ ZLIBINC = @zlibinc@
 
 WARN_CFLAGS = @WARN_CFLAGS@
 NO_WERROR = @NO_WERROR@
-AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
+AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
 AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DLIBDIR='"$(libdir)"' @LARGEFILE_CPPFLAGS@
 if PLUGINS
 bfdinclude_HEADERS += $(INCDIR)/plugin-api.h
@@ -776,7 +776,7 @@ ofiles: stamp-ofiles ; @true
 libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
 EXTRA_libbfd_la_SOURCES = $(CFILES)
 libbfd_la_DEPENDENCIES = $(OFILES) ofiles
-libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB)
+libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS)
 libbfd_la_LDFLAGS += -release `cat libtool-soversion` @SHARED_LDFLAGS@
 
 # libtool will build .libs/libbfd.a.  We create libbfd.a in the build
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index 82843d2d61d..6be41a72a59 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -122,10 +122,12 @@ am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
 	$(top_srcdir)/../config/nls.m4 \
 	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/pkg.m4 \
 	$(top_srcdir)/../config/plugins.m4 \
 	$(top_srcdir)/../config/po.m4 \
 	$(top_srcdir)/../config/progtest.m4 \
-	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../config/zlib.m4 \
+	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
 	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
 	$(top_srcdir)/bfd.m4 $(top_srcdir)/warning.m4 \
@@ -399,6 +401,9 @@ PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
 PKGVERSION = @PKGVERSION@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
 POSUB = @POSUB@
 RANLIB = @RANLIB@
 REPORT_BUGS_TEXI = @REPORT_BUGS_TEXI@
@@ -416,6 +421,8 @@ WARN_CFLAGS = @WARN_CFLAGS@
 WARN_CFLAGS_FOR_BUILD = @WARN_CFLAGS_FOR_BUILD@
 WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
 XGETTEXT = @XGETTEXT@
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
@@ -520,7 +527,7 @@ libbfd_la_LDFLAGS = $(am__append_1) -release `cat libtool-soversion` \
 # case both are empty.
 ZLIB = @zlibdir@ -lz
 ZLIBINC = @zlibinc@
-AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
+AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
 AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DLIBDIR='"$(libdir)"' \
 	@LARGEFILE_CPPFLAGS@ @HDEFINES@ @COREFLAG@ @TDEFINES@ \
 	$(CSEARCH) $(CSWITCHES) $(HAVEVECS) @INCINTL@
@@ -1199,7 +1206,7 @@ OFILES = $(BFD_BACKENDS) $(BFD_MACHINES) @COREFILE@ @bfd64_libs@
 libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
 EXTRA_libbfd_la_SOURCES = $(CFILES)
 libbfd_la_DEPENDENCIES = $(OFILES) ofiles
-libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB)
+libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS)
 
 # libtool will build .libs/libbfd.a.  We create libbfd.a in the build
 # directory so that we don't have to convert all the programs that use
diff --git a/bfd/aclocal.m4 b/bfd/aclocal.m4
index 0f8aa1d4518..09b849dfc87 100644
--- a/bfd/aclocal.m4
+++ b/bfd/aclocal.m4
@@ -1176,10 +1176,12 @@ m4_include([../config/largefile.m4])
 m4_include([../config/lead-dot.m4])
 m4_include([../config/nls.m4])
 m4_include([../config/override.m4])
+m4_include([../config/pkg.m4])
 m4_include([../config/plugins.m4])
 m4_include([../config/po.m4])
 m4_include([../config/progtest.m4])
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index 8605056aefe..4765ea80536 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -342,7 +342,8 @@ enum compressed_debug_section_type
   COMPRESS_DEBUG_NONE = 0,
   COMPRESS_DEBUG = 1 << 0,
   COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1,
-  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2
+  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2,
+  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3
 };
 
 /* This structure is used to keep track of stabs in sections
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 79fcc4eb912..5c80956c79c 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -349,7 +349,8 @@ enum compressed_debug_section_type
   COMPRESS_DEBUG_NONE = 0,
   COMPRESS_DEBUG = 1 << 0,
   COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1,
-  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2
+  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2,
+  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3
 };
 
 /* This structure is used to keep track of stabs in sections
@@ -962,7 +963,8 @@ typedef struct bfd_section
   unsigned int compress_status : 2;
 #define COMPRESS_SECTION_NONE    0
 #define COMPRESS_SECTION_DONE    1
-#define DECOMPRESS_SECTION_SIZED 2
+#define DECOMPRESS_SECTION_ZLIB  2
+#define DECOMPRESS_SECTION_ZSTD  3
 
   /* The following flags are used by the ELF linker. */
 
@@ -6637,12 +6639,14 @@ struct bfd
 #define BFD_ARCHIVE_FULL_PATH  0x100000
 
 #define BFD_CLOSED_BY_CACHE    0x200000
+  /* Compress sections in this BFD with SHF_COMPRESSED zstd.  */
+#define BFD_COMPRESS_ZSTD      0x400000
 
   /* Flags bits to be saved in bfd_preserve_save.  */
 #define BFD_FLAGS_SAVED \
   (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
    | BFD_PLUGIN | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON \
-   | BFD_USE_ELF_STT_COMMON)
+   | BFD_USE_ELF_STT_COMMON | BFD_COMPRESS_ZSTD)
 
   /* Flags bits which are for BFD use only.  */
 #define BFD_FLAGS_FOR_BFD_USE_MASK \
@@ -7271,6 +7275,7 @@ void bfd_update_compression_header
 
 bool bfd_check_compression_header
    (bfd *abfd, bfd_byte *contents, asection *sec,
+    unsigned int *ch_type,
     bfd_size_type *uncompressed_size,
     unsigned int *uncompressed_alignment_power);
 
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 0a21db11fd6..5f2033bee7a 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -177,12 +177,15 @@ CODE_FRAGMENT
 .#define BFD_ARCHIVE_FULL_PATH  0x100000
 .
 .#define BFD_CLOSED_BY_CACHE    0x200000
+
+.  {* Compress sections in this BFD with SHF_COMPRESSED zstd.  *}
+.#define BFD_COMPRESS_ZSTD      0x400000
 .
 .  {* Flags bits to be saved in bfd_preserve_save.  *}
 .#define BFD_FLAGS_SAVED \
 .  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
 .   | BFD_PLUGIN | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON \
-.   | BFD_USE_ELF_STT_COMMON)
+.   | BFD_USE_ELF_STT_COMMON | BFD_COMPRESS_ZSTD)
 .
 .  {* Flags bits which are for BFD use only.  *}
 .#define BFD_FLAGS_FOR_BFD_USE_MASK \
@@ -2500,6 +2503,9 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
 	{
 	  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 	  struct bfd_elf_section_data * esd = elf_section_data (sec);
+	  const unsigned int ch_type = abfd->flags & BFD_COMPRESS_ZSTD
+					   ? ELFCOMPRESS_ZSTD
+					   : ELFCOMPRESS_ZLIB;
 
 	  /* Set the SHF_COMPRESSED bit.  */
 	  elf_section_flags (sec) |= SHF_COMPRESSED;
@@ -2507,7 +2513,7 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
 	  if (bed->s->elfclass == ELFCLASS32)
 	    {
 	      Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) contents;
-	      bfd_put_32 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+	      bfd_put_32 (abfd, ch_type, &echdr->ch_type);
 	      bfd_put_32 (abfd, sec->size, &echdr->ch_size);
 	      bfd_put_32 (abfd, 1u << sec->alignment_power,
 			  &echdr->ch_addralign);
@@ -2518,7 +2524,7 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
 	  else
 	    {
 	      Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) contents;
-	      bfd_put_32 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+	      bfd_put_32 (abfd, ch_type, &echdr->ch_type);
 	      bfd_put_32 (abfd, 0, &echdr->ch_reserved);
 	      bfd_put_64 (abfd, sec->size, &echdr->ch_size);
 	      bfd_put_64 (abfd, UINT64_C (1) << sec->alignment_power,
@@ -2553,14 +2559,15 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
    SYNOPSIS
 	bool bfd_check_compression_header
 	  (bfd *abfd, bfd_byte *contents, asection *sec,
+	  unsigned int *ch_type,
 	  bfd_size_type *uncompressed_size,
 	  unsigned int *uncompressed_alignment_power);
 
 DESCRIPTION
-	Check the compression header at CONTENTS of SEC in ABFD and
-	store the uncompressed size in UNCOMPRESSED_SIZE and the
-	uncompressed data alignment in UNCOMPRESSED_ALIGNMENT_POWER
-	if the compression header is valid.
+	Check the compression header at CONTENTS of SEC in ABFD and store the
+	ch_type in CH_TYPE, uncompressed size in UNCOMPRESSED_SIZE, and the
+	uncompressed data alignment in UNCOMPRESSED_ALIGNMENT_POWER if the
+	compression header is valid.
 
 RETURNS
 	Return TRUE if the compression header is valid.
@@ -2569,6 +2576,7 @@ RETURNS
 bool
 bfd_check_compression_header (bfd *abfd, bfd_byte *contents,
 			      asection *sec,
+			      unsigned int *ch_type,
 			      bfd_size_type *uncompressed_size,
 			      unsigned int *uncompressed_alignment_power)
 {
@@ -2591,7 +2599,9 @@ bfd_check_compression_header (bfd *abfd, bfd_byte *contents,
 	  chdr.ch_size = bfd_get_64 (abfd, &echdr->ch_size);
 	  chdr.ch_addralign = bfd_get_64 (abfd, &echdr->ch_addralign);
 	}
-      if (chdr.ch_type == ELFCOMPRESS_ZLIB
+      *ch_type = chdr.ch_type;
+      if ((chdr.ch_type == ELFCOMPRESS_ZLIB
+	   || chdr.ch_type == ELFCOMPRESS_ZSTD)
 	  && chdr.ch_addralign == (chdr.ch_addralign & -chdr.ch_addralign))
 	{
 	  *uncompressed_size = chdr.ch_size;
diff --git a/bfd/compress.c b/bfd/compress.c
index b2e39826e38..95c1f4c42d1 100644
--- a/bfd/compress.c
+++ b/bfd/compress.c
@@ -20,18 +20,31 @@
 
 #include "sysdep.h"
 #include <zlib.h>
+#ifdef HAVE_ZSTD
+#include <zstd.h>
+#endif
 #include "bfd.h"
+#include "elf-bfd.h"
 #include "libbfd.h"
 #include "safe-ctype.h"
 
 #define MAX_COMPRESSION_HEADER_SIZE 24
 
 static bool
-decompress_contents (bfd_byte *compressed_buffer,
+decompress_contents (bool is_zstd, bfd_byte *compressed_buffer,
 		     bfd_size_type compressed_size,
 		     bfd_byte *uncompressed_buffer,
 		     bfd_size_type uncompressed_size)
 {
+  if (is_zstd)
+    {
+#ifdef HAVE_ZSTD
+      size_t ret = ZSTD_decompress (uncompressed_buffer, uncompressed_size,
+				    compressed_buffer, compressed_size);
+      return !ZSTD_isError (ret);
+#endif
+    }
+
   z_stream strm;
   int rc;
 
@@ -69,7 +82,7 @@ decompress_contents (bfd_byte *compressed_buffer,
 }
 
 /* Compress data of the size specified in @var{uncompressed_size}
-   and pointed to by @var{uncompressed_buffer} using zlib and store
+   and pointed to by @var{uncompressed_buffer} using zlib/zstd and store
    as the contents field.  This function assumes the contents
    field was allocated using bfd_malloc() or equivalent.
 
@@ -150,9 +163,10 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
       sec->size = orig_uncompressed_size;
       if (decompress)
 	{
-	  if (!decompress_contents (uncompressed_buffer
-				    + orig_compression_header_size,
-				    zlib_size, buffer, buffer_size))
+	  if (!decompress_contents (
+		  sec->compress_status == DECOMPRESS_SECTION_ZSTD,
+		  uncompressed_buffer + orig_compression_header_size,
+		  zlib_size, buffer, buffer_size))
 	    {
 	      bfd_set_error (bfd_error_bad_value);
 	      bfd_release (abfd, buffer);
@@ -175,10 +189,23 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
     }
   else
     {
-      if (compress ((Bytef*) buffer + header_size,
-		    &compressed_size,
-		    (const Bytef*) uncompressed_buffer,
-		    uncompressed_size) != Z_OK)
+      if (abfd->flags & BFD_COMPRESS_ZSTD)
+	{
+#if HAVE_ZSTD
+	  compressed_size = ZSTD_compress (
+		  buffer + header_size, compressed_size, uncompressed_buffer,
+		  uncompressed_size, ZSTD_CLEVEL_DEFAULT);
+	  if (ZSTD_isError (compressed_size))
+	    {
+	      bfd_release (abfd, buffer);
+	      bfd_set_error (bfd_error_bad_value);
+	      return 0;
+	    }
+#endif
+	}
+      else if (compress ((Bytef *)buffer + header_size, &compressed_size,
+			 (const Bytef *)uncompressed_buffer, uncompressed_size)
+	       != Z_OK)
 	{
 	  bfd_release (abfd, buffer);
 	  bfd_set_error (bfd_error_bad_value);
@@ -237,6 +264,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
   bfd_size_type save_rawsize;
   bfd_byte *compressed_buffer;
   unsigned int compression_header_size;
+  const unsigned int compress_status = sec->compress_status;
 
   if (abfd->direction != write_direction && sec->rawsize != 0)
     sz = sec->rawsize;
@@ -248,7 +276,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
       return true;
     }
 
-  switch (sec->compress_status)
+  switch (compress_status)
     {
     case COMPRESS_SECTION_NONE:
       if (p == NULL)
@@ -298,7 +326,8 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
       *ptr = p;
       return true;
 
-    case DECOMPRESS_SECTION_SIZED:
+    case DECOMPRESS_SECTION_ZLIB:
+    case DECOMPRESS_SECTION_ZSTD:
       /* Read in the full compressed section contents.  */
       compressed_buffer = (bfd_byte *) bfd_malloc (sec->compressed_size);
       if (compressed_buffer == NULL)
@@ -316,7 +345,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
       /* Restore rawsize and size.  */
       sec->rawsize = save_rawsize;
       sec->size = save_size;
-      sec->compress_status = DECOMPRESS_SECTION_SIZED;
+      sec->compress_status = compress_status;
       if (!ret)
 	goto fail_compressed;
 
@@ -330,8 +359,10 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
 	/* Set header size to the zlib header size if it is a
 	   SHF_COMPRESSED section.  */
 	compression_header_size = 12;
-      if (!decompress_contents (compressed_buffer + compression_header_size,
-				sec->compressed_size - compression_header_size, p, sz))
+      if (!decompress_contents (compress_status == DECOMPRESS_SECTION_ZSTD,
+				compressed_buffer + compression_header_size,
+				sec->compressed_size - compression_header_size,
+				p, sz))
 	{
 	  bfd_set_error (bfd_error_bad_value);
 	  if (p != *ptr)
@@ -381,7 +412,8 @@ DESCRIPTION
 void
 bfd_cache_section_contents (asection *sec, void *contents)
 {
-  if (sec->compress_status == DECOMPRESS_SECTION_SIZED)
+  if (sec->compress_status == DECOMPRESS_SECTION_ZLIB
+      || sec->compress_status == DECOMPRESS_SECTION_ZSTD)
     sec->compress_status = COMPRESS_SECTION_DONE;
   sec->contents = contents;
   sec->flags |= SEC_IN_MEMORY;
@@ -418,6 +450,7 @@ bfd_is_section_compressed_with_header (bfd *abfd, sec_ptr sec,
   int compression_header_size;
   int header_size;
   unsigned int saved = sec->compress_status;
+  unsigned int ch_type;
   bool compressed;
 
   *uncompressed_align_pow_p = 0;
@@ -448,7 +481,7 @@ bfd_is_section_compressed_with_header (bfd *abfd, sec_ptr sec,
     {
       if (compression_header_size != 0)
 	{
-	  if (!bfd_check_compression_header (abfd, header, sec,
+	  if (!bfd_check_compression_header (abfd, header, sec, &ch_type,
 					     uncompressed_size_p,
 					     uncompressed_align_pow_p))
 	    compression_header_size = -1;
@@ -507,7 +540,7 @@ SYNOPSIS
 DESCRIPTION
 	Record compressed section size, update section size with
 	decompressed size and set compress_status to
-	DECOMPRESS_SECTION_SIZED.
+	DECOMPRESS_SECTION_{ZLIB,ZSTD}.
 
 	Return @code{FALSE} if the section is not a valid compressed
 	section.  Otherwise, return @code{TRUE}.
@@ -521,6 +554,7 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
   int header_size;
   bfd_size_type uncompressed_size;
   unsigned int uncompressed_alignment_power = 0;
+  unsigned int ch_type;
   z_stream strm;
 
   compression_header_size = bfd_get_compression_header_size (abfd, sec);
@@ -550,6 +584,7 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
       uncompressed_size = bfd_getb64 (header + 4);
     }
   else if (!bfd_check_compression_header (abfd, header, sec,
+					  &ch_type,
 					  &uncompressed_size,
 					  &uncompressed_alignment_power))
     {
@@ -569,7 +604,8 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
   sec->compressed_size = sec->size;
   sec->size = uncompressed_size;
   bfd_set_section_alignment (sec, uncompressed_alignment_power);
-  sec->compress_status = DECOMPRESS_SECTION_SIZED;
+  sec->compress_status = ch_type == ELFCOMPRESS_ZSTD ? DECOMPRESS_SECTION_ZSTD
+						     : DECOMPRESS_SECTION_ZLIB;
 
   return true;
 }
diff --git a/bfd/config.in b/bfd/config.in
index f54a3cacbea..a59304e0a66 100644
--- a/bfd/config.in
+++ b/bfd/config.in
@@ -232,6 +232,9 @@
 /* Define to 1 if you have the <windows.h> header file. */
 #undef HAVE_WINDOWS_H
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Define to the sub-directory in which libtool stores uninstalled libraries.
    */
 #undef LT_OBJDIR
diff --git a/bfd/configure b/bfd/configure
index 075d2ee0a1b..d905a7bf7a8 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -652,6 +652,11 @@ TDEFINES
 SHARED_LIBADD
 SHARED_LDFLAGS
 LIBM
+ZSTD_LIBS
+ZSTD_CFLAGS
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
 zlibinc
 zlibdir
 EXEEXT_FOR_BUILD
@@ -839,6 +844,7 @@ enable_maintainer_mode
 enable_install_libbfd
 enable_nls
 with_system_zlib
+with_zstd
 '
       ac_precious_vars='build_alias
 host_alias
@@ -848,7 +854,12 @@ CFLAGS
 LDFLAGS
 LIBS
 CPPFLAGS
-CPP'
+CPP
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
+ZSTD_CFLAGS
+ZSTD_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1511,6 +1522,8 @@ Optional Packages:
                           Binutils"
   --with-bugurl=URL       Direct users to URL to report a bug
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
 
 Some influential environment variables:
   CC          C compiler command
@@ -1521,6 +1534,13 @@ Some influential environment variables:
   CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
               you have headers in a nonstandard directory <include dir>
   CPP         C preprocessor
+  PKG_CONFIG  path to pkg-config utility
+  PKG_CONFIG_PATH
+              directories to add to pkg-config's search path
+  PKG_CONFIG_LIBDIR
+              path overriding pkg-config's built-in search path
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -11086,7 +11106,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11089 "configure"
+#line 11109 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11192,7 +11212,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11195 "configure"
+#line 11215 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12995,7 +13015,7 @@ $as_echo "#define USE_BINARY_FOPEN 1" >>confdefs.h
  ;;
 esac
 
-# Link in zlib if we can.  This allows us to read compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to read compressed debug sections.
 # This is used only by compress.c.
 
   # Use the system's zlib library.
@@ -13015,6 +13035,246 @@ fi
 
 
 
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=0.9.0
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	else
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		PKG_CONFIG=""
+	fi
+fi
+
+
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if test "$with_zstd" != no; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+fi
+
+
 save_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS -Werror"
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking compiler support for hidden visibility" >&5
diff --git a/bfd/configure.ac b/bfd/configure.ac
index 28f3d1afce6..d1b2f76b31a 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -230,9 +230,10 @@ AC_CHECK_DECLS([basename, ffs, stpcpy, asprintf, vasprintf, strnlen])
 
 BFD_BINARY_FOPEN
 
-# Link in zlib if we can.  This allows us to read compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to read compressed debug sections.
 # This is used only by compress.c.
 AM_ZLIB
+AM_ZSTD
 
 save_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS -Werror"
diff --git a/bfd/elf.c b/bfd/elf.c
index 16cea4f8aeb..e52fa458a5a 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1260,6 +1260,18 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
 		 abfd, name);
 	      return false;
 	    }
+#ifndef HAVE_ZSTD
+	  if (newsect->compress_status == DECOMPRESS_SECTION_ZSTD)
+	    {
+	      _bfd_error_handler
+		  /* xgettext:c-format */
+		  (_ ("%pB: section %s is compressed with zstd, but BFD "
+		      "is not built with zstd support"),
+		   abfd, name);
+	      newsect->compress_status = COMPRESS_SECTION_NONE;
+	      return false;
+	    }
+#endif
 	}
 
       if (abfd->is_linker_input)
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index feaba84bf2e..ca600bb5ddf 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -989,7 +989,8 @@ const bfd_target TARGET_BIG_SYM =
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS
    | DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS
-   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON),
+   | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD | BFD_CONVERT_ELF_COMMON
+   | BFD_USE_ELF_STT_COMMON),
 
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY
@@ -1093,7 +1094,8 @@ const bfd_target TARGET_LITTLE_SYM =
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS
    | DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS
-   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON),
+   | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD | BFD_CONVERT_ELF_COMMON
+   | BFD_USE_ELF_STT_COMMON),
 
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY
diff --git a/bfd/section.c b/bfd/section.c
index c7a02d729f2..614570e976e 100644
--- a/bfd/section.c
+++ b/bfd/section.c
@@ -392,7 +392,8 @@ CODE_FRAGMENT
 .  unsigned int compress_status : 2;
 .#define COMPRESS_SECTION_NONE    0
 .#define COMPRESS_SECTION_DONE    1
-.#define DECOMPRESS_SECTION_SIZED 2
+.#define DECOMPRESS_SECTION_ZLIB  2
+.#define DECOMPRESS_SECTION_ZSTD  3
 .
 .  {* The following flags are used by the ELF linker. *}
 .
diff --git a/binutils/Makefile.in b/binutils/Makefile.in
index 78d32b350e3..6de4e239408 100644
--- a/binutils/Makefile.in
+++ b/binutils/Makefile.in
@@ -156,7 +156,8 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/plugins.m4 \
 	$(top_srcdir)/../config/po.m4 \
 	$(top_srcdir)/../config/progtest.m4 \
-	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../config/zlib.m4 \
+	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
 	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
 	$(top_srcdir)/../bfd/version.m4 \
@@ -575,6 +576,8 @@ WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
 XGETTEXT = @XGETTEXT@
 YACC = `if [ -f ../bison/bison ]; then echo ../bison/bison -y -L$(srcdir)/../bison/; else echo @YACC@; fi`
 YFLAGS = -d
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
diff --git a/binutils/NEWS b/binutils/NEWS
index 8c2c416c17e..073e9bc4647 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -1,5 +1,11 @@
 -*- text -*-
 
+* objcopy --decompress-debug-sections now support zstd compressed debug
+  sections.  The new option --compress-debug-sections=zstd compresses debug
+  sections with zstd.
+
+* addr2line and objdump --dwarf now support zstd compressed debug sections.
+
 * The dlltool program now accepts --deterministic-libraries and
   --non-deterministic-libraries as command line options to control whether or
   not it generates deterministic output libraries.  If neither of these options
diff --git a/binutils/aclocal.m4 b/binutils/aclocal.m4
index a877fa7f873..28271f56279 100644
--- a/binutils/aclocal.m4
+++ b/binutils/aclocal.m4
@@ -1205,6 +1205,7 @@ m4_include([../config/plugins.m4])
 m4_include([../config/po.m4])
 m4_include([../config/progtest.m4])
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/binutils/config.in b/binutils/config.in
index c5fb919aa95..bee8c07e2f7 100644
--- a/binutils/config.in
+++ b/binutils/config.in
@@ -157,6 +157,9 @@
 /* Define to 1 if you have the <windows.h> header file. */
 #undef HAVE_WINDOWS_H
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Define as const if the declaration of iconv() needs const. */
 #undef ICONV_CONST
 
diff --git a/binutils/configure b/binutils/configure
index 1c518227f57..54d0f184da1 100755
--- a/binutils/configure
+++ b/binutils/configure
@@ -650,6 +650,8 @@ LTLIBICONV
 LIBICONV
 MSGPACK_LIBS
 MSGPACK_CFLAGS
+ZSTD_LIBS
+ZSTD_CFLAGS
 zlibinc
 zlibdir
 DEMANGLER_NAME
@@ -832,6 +834,7 @@ enable_build_warnings
 enable_nls
 enable_maintainer_mode
 with_system_zlib
+with_zstd
 with_msgpack
 enable_rpath
 with_libiconv_prefix
@@ -853,6 +856,8 @@ DEBUGINFOD_CFLAGS
 DEBUGINFOD_LIBS
 YACC
 YFLAGS
+ZSTD_CFLAGS
+ZSTD_LIBS
 MSGPACK_CFLAGS
 MSGPACK_LIBS'
 
@@ -1517,6 +1522,8 @@ Optional Packages:
   --with-debuginfod       Enable debuginfo lookups with debuginfod
                           (auto/yes/no)
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
   --with-msgpack          Enable msgpack support (auto/yes/no)
   --with-gnu-ld           assume the C compiler uses GNU ld default=no
   --with-libiconv-prefix[=DIR]  search for libiconv in DIR/include and DIR/lib
@@ -1547,6 +1554,8 @@ Some influential environment variables:
   YFLAGS      The list of arguments that will be passed by default to $YACC.
               This script will default YFLAGS to the empty string to avoid a
               default value of `-d' given by some make applications.
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
   MSGPACK_CFLAGS
               C compiler flags for MSGPACK, overriding pkg-config
   MSGPACK_LIBS
@@ -10804,7 +10813,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10807 "configure"
+#line 10816 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10910,7 +10919,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10913 "configure"
+#line 10922 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13468,7 +13477,7 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-# Link in zlib if we can.  This allows us to read compressed debug
+# Link in zlib/zstd if we can.  This allows us to read compressed debug
 # sections.  This is used only by readelf.c (objdump uses bfd for
 # reading compressed sections).
 
@@ -13490,6 +13499,126 @@ fi
 
 
 
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if test "$with_zstd" != no; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+fi
+
+
+
 case "${host}" in
 *-*-msdos* | *-*-go32* | *-*-mingw32* | *-*-cygwin* | *-*-windows*)
 
diff --git a/binutils/configure.ac b/binutils/configure.ac
index ec002d3f88f..c152b7f6733 100644
--- a/binutils/configure.ac
+++ b/binutils/configure.ac
@@ -265,10 +265,11 @@ fi
 
 AC_CHECK_DECLS([asprintf, environ, getc_unlocked, stpcpy, strnlen])
 
-# Link in zlib if we can.  This allows us to read compressed debug
+# Link in zlib/zstd if we can.  This allows us to read compressed debug
 # sections.  This is used only by readelf.c (objdump uses bfd for
 # reading compressed sections).
 AM_ZLIB
+AM_ZSTD
 
 BFD_BINARY_FOPEN
 
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 1499db5728c..34a4164eb94 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -2159,21 +2159,23 @@ ELF ABI.  Note - if compression would actually make a section
 @itemx --compress-debug-sections=zlib
 @itemx --compress-debug-sections=zlib-gnu
 @itemx --compress-debug-sections=zlib-gabi
+@itemx --compress-debug-sections=zstd
 For ELF files, these options control how DWARF debug sections are
 compressed.  @option{--compress-debug-sections=none} is equivalent
 to @option{--decompress-debug-sections}.
 @option{--compress-debug-sections=zlib} and
 @option{--compress-debug-sections=zlib-gabi} are equivalent to
 @option{--compress-debug-sections}.
-@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug
-sections using zlib.  The debug sections are renamed to begin with
-@samp{.zdebug} instead of @samp{.debug}.  Note - if compression would
-actually make a section @emph{larger}, then it is not compressed nor
-renamed.
+@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug sections
+using the obsoleted zlib-gnu format.  The debug sections are renamed to begin
+with @samp{.zdebug}.
+@option{--compress-debug-sections=zstd} compresses DWARF debug
+sections using zstd.  Note - if compression would actually make a section
+@emph{larger}, then it is not compressed nor renamed.
 
 @item --decompress-debug-sections
-Decompress DWARF debug sections using zlib.  The original section
-names of the compressed sections are restored.
+Decompress DWARF debug sections.  For a @samp{.zdebug} section, the original
+name is restored.
 
 @item --elf-stt-common=yes
 @itemx --elf-stt-common=no
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index 43261756a42..fc668f00bbc 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -232,7 +232,8 @@ static enum
   compress_zlib = compress | 1 << 1,
   compress_gnu_zlib = compress | 1 << 2,
   compress_gabi_zlib = compress | 1 << 3,
-  decompress = 1 << 4
+  compress_zstd = compress | 1 << 4,
+  decompress = 1 << 5
 } do_debug_sections = nothing;
 
 /* Whether to generate ELF common symbols with the STT_COMMON type.  */
@@ -678,8 +679,8 @@ copy_usage (FILE *stream, int exit_status)
                                    <commit>\n\
      --subsystem <name>[:<version>]\n\
                                    Set PE subsystem to <name> [& <version>]\n\
-     --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
-                                   Compress DWARF debug sections using zlib\n\
+     --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
+				   Compress DWARF debug sections\n\
      --decompress-debug-sections   Decompress DWARF debug sections using zlib\n\
      --elf-stt-common=[yes|no]     Generate ELF common symbols with STT_COMMON\n\
                                      type\n\
@@ -2659,7 +2660,8 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
       if ((do_debug_sections & compress) != 0
 	  && do_debug_sections != compress)
 	{
-	  non_fatal (_("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi] is unsupported on `%s'"),
+	  non_fatal (_ ("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi|"
+			"zstd] is unsupported on `%s'"),
 		     bfd_get_archive_filename (ibfd));
 	  return false;
 	}
@@ -3807,6 +3809,13 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
       if (do_debug_sections != compress_gnu_zlib)
 	ibfd->flags |= BFD_COMPRESS_GABI;
       break;
+    case compress_zstd:
+      ibfd->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD;
+#ifndef HAVE_ZSTD
+      fatal (_ ("--compress-debug-sections=zstd: binutils is not built with "
+		"zstd support"));
+#endif
+      break;
     case decompress:
       ibfd->flags |= BFD_DECOMPRESS;
       break;
@@ -5469,6 +5478,8 @@ copy_main (int argc, char *argv[])
 		do_debug_sections = compress_gnu_zlib;
 	      else if (strcasecmp (optarg, "zlib-gabi") == 0)
 		do_debug_sections = compress_gabi_zlib;
+	      else if (strcasecmp (optarg, "zstd") == 0)
+		do_debug_sections = compress_zstd;
 	      else
 		fatal (_("unrecognized --compress-debug-sections type `%s'"),
 		       optarg);
diff --git a/binutils/testsuite/binutils-all/compress.exp b/binutils/testsuite/binutils-all/compress.exp
index c88da74a987..4e74c824664 100644
--- a/binutils/testsuite/binutils-all/compress.exp
+++ b/binutils/testsuite/binutils-all/compress.exp
@@ -576,6 +576,50 @@ if { [regexp_diff objdump.out $srcdir/$subdir/dw2-3gabi.W] } then {
     pass "$testname"
 }
 
+if { [binutils_assemble_flags $srcdir/$subdir/dw2-1.S ${compressedfile}zstd.o --compress-debug-sections=zstd] } then {
+    set testname "objcopy compress debug sections with zstd"
+    set got [binutils_run $OBJCOPY "--compress-debug-sections=zstd ${testfile}.o ${copyfile}zstd.o"]
+    if ![string match "" $got] then {
+	fail "objcopy ($testname)"
+	return
+    }
+    send_log "cmp ${compressedfile}zstd.o ${copyfile}zstd.o\n"
+    verbose "cmp ${compressedfile}zstd.o ${copyfile}zstd.o"
+    set src1 ${compressedfile}zstd.o
+    set src2 ${copyfile}zstd.o
+    set status [remote_exec build cmp "${src1} ${src2}"]
+    set exec_output [lindex $status 1]
+    set exec_output [prune_warnings $exec_output]
+    if ![string match "" $exec_output] then {
+	send_log "$exec_output\n"
+	verbose "$exec_output" 1
+	fail "objcopy ($testname)"
+    } else {
+	pass "objcopy ($testname)"
+    }
+
+    set testname "objcopy decompress compressed debug sections with zstd"
+    set got [binutils_run $OBJCOPY "--decompress-debug-sections ${compressedfile}zstd.o ${copyfile}zstd.o"]
+    if ![string match "" $got] then {
+	fail "objcopy ($testname)"
+	return
+    }
+    send_log "cmp ${testfile}.o ${copyfile}zstd.o\n"
+    verbose "cmp ${testfile}.o ${copyfile}zstd.o"
+    set src1 ${testfile}.o
+    set src2 ${copyfile}zstd.o
+    set status [remote_exec build cmp "${src1} ${src2}"]
+    set exec_output [lindex $status 1]
+    set exec_output [prune_warnings $exec_output]
+    if ![string match "" $exec_output] then {
+	send_log "$exec_output\n"
+	verbose "$exec_output" 1
+	fail "objcopy ($testname)"
+    } else {
+	pass "objcopy ($testname)"
+    }
+}
+
 proc convert_test { testname  as_flags  objcop_flags } {
     global srcdir
     global subdir
diff --git a/config/zstd.m4 b/config/zstd.m4
new file mode 100644
index 00000000000..93ae17b89d3
--- /dev/null
+++ b/config/zstd.m4
@@ -0,0 +1,24 @@
+dnl Copyright (C) 2022 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl Enable features using the zstd library.
+AC_DEFUN([AM_ZSTD],
+[
+AC_ARG_WITH(zstd,
+  [AS_HELP_STRING([--with-zstd], [support zstd compressed debug sections (default=auto)])],
+  [], [with_zstd=auto])
+
+if test "$with_zstd" != no; then
+  PKG_CHECK_MODULES(ZSTD, [libzstd], [
+    AC_DEFINE(HAVE_ZSTD, 1, [Define to 1 if zstd is enabled.])
+  ], [
+    if test "$with_zstd" = yes; then
+      AC_MSG_ERROR([--with-zstd was given, but pkgconfig/libzstd.pc is not found])
+    fi
+  ])
+fi
+])
diff --git a/configure b/configure
index d75f47a1e95..f14e0efd675 100755
--- a/configure
+++ b/configure
@@ -785,6 +785,7 @@ ac_user_opts='
 enable_option_checking
 with_build_libsubdir
 with_system_zlib
+with_zstd
 enable_as_accelerator_for
 enable_offload_targets
 enable_gold
@@ -1567,6 +1568,8 @@ Optional Packages:
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
   --with-build-libsubdir=DIR  Directory where to find libraries for build system
   --with-system-zlib      use installed libz
+  --with-zstd             Support zstd compressed debug sections
+                          (default=auto)
   --with-mpc=PATH         specify prefix directory for installed MPC package.
                           Equivalent to --with-mpc-include=PATH/include plus
                           --with-mpc-lib=PATH/lib
@@ -2925,6 +2928,13 @@ if test x$with_system_zlib = xyes ; then
   noconfigdirs="$noconfigdirs zlib"
 fi
 
+
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+fi
+
+
 # Don't compile the bundled readline/libreadline.a if --with-system-readline
 # is provided.
 if test x$with_system_readline = xyes ; then
diff --git a/configure.ac b/configure.ac
index ae18d436aca..0152c69292e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -246,6 +246,9 @@ if test x$with_system_zlib = xyes ; then
   noconfigdirs="$noconfigdirs zlib"
 fi
 
+AC_ARG_WITH(zstd,
+[AS_HELP_STRING([--with-zstd], [Support zstd compressed debug sections (default=auto)])])
+
 # Don't compile the bundled readline/libreadline.a if --with-system-readline
 # is provided.
 if test x$with_system_readline = xyes ; then
diff --git a/gas/Makefile.am b/gas/Makefile.am
index bd597398671..5f0f24abf8d 100644
--- a/gas/Makefile.am
+++ b/gas/Makefile.am
@@ -42,7 +42,7 @@ am__skipyacc =
 
 WARN_CFLAGS = @WARN_CFLAGS@ @WARN_WRITE_STRINGS@
 NO_WERROR = @NO_WERROR@
-AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
+AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
 
 TARG_CPU = @target_cpu_type@
 TARG_CPU_C = $(srcdir)/config/tc-@target_cpu_type@.c
@@ -407,7 +407,7 @@ STAGESTUFF = *.@OBJEXT@ $(noinst_PROGRAMS)
 
 as_new_SOURCES = $(GAS_CFILES)
 as_new_LDADD = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
-	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB)
+	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB) $(ZSTD_LIBS)
 as_new_DEPENDENCIES = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
 	$(extra_objects) $(GASLIBS) $(LIBINTL_DEP)
 EXTRA_as_new_SOURCES = $(CFILES) $(HFILES) $(TARGET_CPU_CFILES) \
diff --git a/gas/Makefile.in b/gas/Makefile.in
index c57d78f82c4..5a4dd702252 100644
--- a/gas/Makefile.in
+++ b/gas/Makefile.in
@@ -140,10 +140,12 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
 	$(top_srcdir)/../config/nls.m4 \
 	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/pkg.m4 \
 	$(top_srcdir)/../config/plugins.m4 \
 	$(top_srcdir)/../config/po.m4 \
 	$(top_srcdir)/../config/progtest.m4 \
-	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../config/zlib.m4 \
+	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
 	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
 	$(top_srcdir)/acinclude.m4 $(top_srcdir)/../bfd/version.m4 \
@@ -429,6 +431,9 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
 PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
 POSUB = @POSUB@
 RANLIB = @RANLIB@
 SED = @SED@
@@ -443,6 +448,8 @@ WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
 XGETTEXT = @XGETTEXT@
 YACC = `if [ -f ../bison/bison ] ; then echo ../bison/bison -y -L../bison/bison ; else echo @YACC@ ; fi`
 YFLAGS = @YFLAGS@
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
@@ -524,7 +531,7 @@ ZLIBINC = @zlibinc@
 # maintainer mode is disabled.  Avoid this.
 am__skiplex = 
 am__skipyacc = 
-AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
+AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
 TARG_CPU = @target_cpu_type@
 TARG_CPU_C = $(srcdir)/config/tc-@target_cpu_type@.c
 TARG_CPU_O = config/tc-@target_cpu_type@.@OBJEXT@
@@ -874,7 +881,7 @@ GASLIBS = @OPCODES_LIB@ ../bfd/libbfd.la ../libiberty/libiberty.a
 STAGESTUFF = *.@OBJEXT@ $(noinst_PROGRAMS)
 as_new_SOURCES = $(GAS_CFILES)
 as_new_LDADD = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
-	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB)
+	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB) $(ZSTD_LIBS)
 
 as_new_DEPENDENCIES = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
 	$(extra_objects) $(GASLIBS) $(LIBINTL_DEP)
diff --git a/gas/NEWS b/gas/NEWS
index d61cdb9edd4..9a8b726b942 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* gas now supports --compress-debug-sections=zstd to compress
+  debug sections with zstd.
+
 Changes in 2.39:
 
 * Remove (rudimentary) support for the x86-64 sub-architectures Intel L1OM and
diff --git a/gas/aclocal.m4 b/gas/aclocal.m4
index 70183124da7..722030c776f 100644
--- a/gas/aclocal.m4
+++ b/gas/aclocal.m4
@@ -1196,10 +1196,12 @@ m4_include([../config/lcmessage.m4])
 m4_include([../config/lead-dot.m4])
 m4_include([../config/nls.m4])
 m4_include([../config/override.m4])
+m4_include([../config/pkg.m4])
 m4_include([../config/plugins.m4])
 m4_include([../config/po.m4])
 m4_include([../config/progtest.m4])
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/gas/as.c b/gas/as.c
index 6268779cf90..35ad6b3ab3b 100644
--- a/gas/as.c
+++ b/gas/as.c
@@ -252,14 +252,14 @@ Options:\n\
   --alternate             initially turn on alternate macro syntax\n"));
 #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
   fprintf (stream, _("\
-  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
+  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
                           compress DWARF debug sections using zlib [default]\n"));
   fprintf (stream, _("\
   --nocompress-debug-sections\n\
                           don't compress DWARF debug sections\n"));
 #else
   fprintf (stream, _("\
-  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
+  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
                           compress DWARF debug sections using zlib\n"));
   fprintf (stream, _("\
   --nocompress-debug-sections\n\
@@ -736,6 +736,15 @@ This program has absolutely no warranty.\n"));
 		flag_compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
 	      else if (strcasecmp (optarg, "zlib-gabi") == 0)
 		flag_compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
+	      else if (strcasecmp (optarg, "zstd") == 0)
+		{
+#ifdef HAVE_ZSTD
+		  flag_compress_debug = COMPRESS_DEBUG_ZSTD;
+#else
+		  as_fatal (_ ("--compress-debug-sections=zstd: gas is not "
+			       "built with zstd support"));
+#endif
+		}
 	      else
 		as_fatal (_("Invalid --compress-debug-sections option: `%s'"),
 			  optarg);
diff --git a/gas/compress-debug.c b/gas/compress-debug.c
index c80dbeec4e7..3cd175f6e57 100644
--- a/gas/compress-debug.c
+++ b/gas/compress-debug.c
@@ -21,14 +21,23 @@
 #include "config.h"
 #include <stdio.h>
 #include <zlib.h>
+#if HAVE_ZSTD
+#include <zstd.h>
+#endif
 #include "ansidecl.h"
 #include "compress-debug.h"
 
 /* Initialize the compression engine.  */
 
-struct z_stream_s *
-compress_init (void)
+void *
+compress_init (bool use_zstd)
 {
+  if (use_zstd) {
+#if HAVE_ZSTD
+    return ZSTD_createCCtx ();
+#endif
+  }
+
   static struct z_stream_s strm;
 
   strm.zalloc = NULL;
@@ -42,22 +51,37 @@ compress_init (void)
    from the engine goes into the current frag on the obstack.  */
 
 int
-compress_data (struct z_stream_s *strm, const char **next_in,
-	       int *avail_in, char **next_out, int *avail_out)
+compress_data (bool use_zstd, void *ctx, const char **next_in, int *avail_in,
+	       char **next_out, int *avail_out)
 {
-  int out_size = 0;
-  int x;
+  if (use_zstd)
+    {
+#if HAVE_ZSTD
+      ZSTD_outBuffer ob = { *next_out, *avail_out, 0 };
+      ZSTD_inBuffer ib = { *next_in, *avail_in, 0 };
+      size_t ret = ZSTD_compressStream2 (ctx, &ob, &ib, ZSTD_e_continue);
+      *next_in += ib.pos;
+      *avail_in -= ib.pos;
+      *next_out += ob.pos;
+      *avail_out -= ob.pos;
+      if (ZSTD_isError (ret))
+	return -1;
+      return (int)ob.pos;
+#endif
+    }
+
+  struct z_stream_s *strm = ctx;
 
   strm->next_in = (Bytef *) (*next_in);
   strm->avail_in = *avail_in;
   strm->next_out = (Bytef *) (*next_out);
   strm->avail_out = *avail_out;
 
-  x = deflate (strm, Z_NO_FLUSH);
+  int x = deflate (strm, Z_NO_FLUSH);
   if (x != Z_OK)
     return -1;
 
-  out_size = *avail_out - strm->avail_out;
+  int out_size = *avail_out - strm->avail_out;
   *next_in = (char *) (strm->next_in);
   *avail_in = strm->avail_in;
   *next_out = (char *) (strm->next_out);
@@ -71,10 +95,28 @@ compress_data (struct z_stream_s *strm, const char **next_in,
    needed.  */
 
 int
-compress_finish (struct z_stream_s *strm, char **next_out,
+compress_finish (bool use_zstd, void *ctx, char **next_out,
 		 int *avail_out, int *out_size)
 {
+  if (use_zstd)
+    {
+#if HAVE_ZSTD
+      ZSTD_outBuffer ob = { *next_out, *avail_out, 0 };
+      ZSTD_inBuffer ib = { 0 };
+      size_t ret = ZSTD_compressStream2 (ctx, &ob, &ib, ZSTD_e_end);
+      *out_size = ob.pos;
+      *next_out += ob.pos;
+      *avail_out -= ob.pos;
+      if (ZSTD_isError (ret))
+	return -1;
+      if (ret == 0)
+	ZSTD_freeCCtx (ctx);
+      return ret ? 1 : 0;
+#endif
+    }
+
   int x;
+  struct z_stream_s *strm = ctx;
 
   strm->avail_in = 0;
   strm->next_out = (Bytef *) (*next_out);
diff --git a/gas/compress-debug.h b/gas/compress-debug.h
index 0183e269fef..87de0f8444e 100644
--- a/gas/compress-debug.h
+++ b/gas/compress-debug.h
@@ -21,19 +21,19 @@
 #ifndef COMPRESS_DEBUG_H
 #define COMPRESS_DEBUG_H
 
+#include <stdbool.h>
+
 struct z_stream_s;
 
 /* Initialize the compression engine.  */
-extern struct z_stream_s *
-compress_init (void);
+extern void *compress_init (bool);
 
 /* Stream the contents of a frag to the compression engine.  Output
    from the engine goes into the current frag on the obstack.  */
-extern int
-compress_data (struct z_stream_s *, const char **, int *, char **, int *);
+extern int compress_data (bool, void *, const char **, int *, char **, int *);
 
 /* Finish the compression and consume the remaining compressed output.  */
 extern int
-compress_finish (struct z_stream_s *, char **, int *, int *);
+compress_finish (bool, void *, char **, int *, int *);
 
 #endif /* COMPRESS_DEBUG_H */
diff --git a/gas/config.in b/gas/config.in
index e243fd277ee..0d1668a3eac 100644
--- a/gas/config.in
+++ b/gas/config.in
@@ -134,6 +134,9 @@
 /* Define to 1 if you have the <windows.h> header file. */
 #undef HAVE_WINDOWS_H
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Using i386 COFF? */
 #undef I386COFF
 
diff --git a/gas/configure b/gas/configure
index d0449a1d7ab..1833adffaa8 100755
--- a/gas/configure
+++ b/gas/configure
@@ -633,6 +633,11 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+ZSTD_LIBS
+ZSTD_CFLAGS
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
 zlibinc
 zlibdir
 LIBM
@@ -817,6 +822,7 @@ with_cpu
 enable_nls
 enable_maintainer_mode
 with_system_zlib
+with_zstd
 '
       ac_precious_vars='build_alias
 host_alias
@@ -828,7 +834,12 @@ LIBS
 CPPFLAGS
 CPP
 YACC
-YFLAGS'
+YFLAGS
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
+ZSTD_CFLAGS
+ZSTD_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1493,6 +1504,8 @@ Optional Packages:
   --with-cpu=CPU          default cpu variant is CPU (currently only supported
                           on ARC)
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
 
 Some influential environment variables:
   CC          C compiler command
@@ -1509,6 +1522,13 @@ Some influential environment variables:
   YFLAGS      The list of arguments that will be passed by default to $YACC.
               This script will default YFLAGS to the empty string to avoid a
               default value of `-d' given by some make applications.
+  PKG_CONFIG  path to pkg-config utility
+  PKG_CONFIG_PATH
+              directories to add to pkg-config's search path
+  PKG_CONFIG_LIBDIR
+              path overriding pkg-config's built-in search path
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -10702,7 +10722,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10705 "configure"
+#line 10725 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10808,7 +10828,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10811 "configure"
+#line 10831 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13945,7 +13965,7 @@ $as_echo "#define USE_BINARY_FOPEN 1" >>confdefs.h
  ;;
 esac
 
-# Link in zlib if we can.  This allows us to write compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to write compressed debug sections.
 
   # Use the system's zlib library.
   zlibdir="-L\$(top_builddir)/../zlib"
@@ -13964,6 +13984,246 @@ fi
 
 
 
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=0.9.0
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	else
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		PKG_CONFIG=""
+	fi
+fi
+
+
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if test "$with_zstd" != no; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+fi
+
+
 # Support for VMS timestamps via cross compile
 
 if test "$ac_cv_header_time_h" = yes; then
diff --git a/gas/configure.ac b/gas/configure.ac
index 21795a82bdd..8750ea21381 100644
--- a/gas/configure.ac
+++ b/gas/configure.ac
@@ -1004,8 +1004,9 @@ AC_CHECK_DECLS([asprintf, mempcpy, stpcpy])
 
 BFD_BINARY_FOPEN
 
-# Link in zlib if we can.  This allows us to write compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to write compressed debug sections.
 AM_ZLIB
+AM_ZSTD
 
 # Support for VMS timestamps via cross compile
 
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index e915893da86..01f49434021 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -711,16 +711,19 @@ given section @emph{larger} then it is not compressed.
 @itemx --compress-debug-sections=zlib
 @itemx --compress-debug-sections=zlib-gnu
 @itemx --compress-debug-sections=zlib-gabi
+@itemx --compress-debug-sections=zstd
 These options control how DWARF debug sections are compressed.
 @option{--compress-debug-sections=none} is equivalent to
 @option{--nocompress-debug-sections}.
 @option{--compress-debug-sections=zlib} and
 @option{--compress-debug-sections=zlib-gabi} are equivalent to
 @option{--compress-debug-sections}.
-@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug
-sections using zlib.  The debug sections are renamed to begin with
-@samp{.zdebug}.  Note if compression would make a given section
-@emph{larger} then it is not compressed nor renamed.
+@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug sections
+using the obsoleted zlib-gnu format.  The debug sections are renamed to begin
+with @samp{.zdebug}.
+@option{--compress-debug-sections=zstd} compresses DWARF debug
+sections using zstd.  Note - if compression would actually make a section
+@emph{larger}, then it is not compressed nor renamed.
 
 @end ifset
 
diff --git a/gas/write.c b/gas/write.c
index f76bbdb706e..0e49df7c03f 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -1413,7 +1413,7 @@ write_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
 }
 
 static int
-compress_frag (struct z_stream_s *strm, const char *contents, int in_size,
+compress_frag (bool use_zstd, void *ctx, const char *contents, int in_size,
 	       fragS **last_newf, struct obstack *ob)
 {
   int out_size;
@@ -1442,10 +1442,10 @@ compress_frag (struct z_stream_s *strm, const char *contents, int in_size,
 	as_fatal (_("can't extend frag"));
       next_out = obstack_next_free (ob);
       obstack_blank_fast (ob, avail_out);
-      out_size = compress_data (strm, &contents, &in_size,
-				&next_out, &avail_out);
+      out_size = compress_data (use_zstd, ctx, &contents, &in_size, &next_out,
+				&avail_out);
       if (out_size < 0)
-        return -1;
+	return -1;
 
       f->fr_fix += out_size;
       total_out_size += out_size;
@@ -1471,7 +1471,6 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   const char *section_name;
   char *compressed_name;
   char *header;
-  struct z_stream_s *strm;
   int x;
   flagword flags = bfd_section_flags (sec);
   unsigned int header_size, compression_header_size;
@@ -1485,21 +1484,22 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   if (!startswith (section_name, ".debug_"))
     return;
 
-  strm = compress_init ();
-  if (strm == NULL)
+  bool use_zstd = abfd->flags & BFD_COMPRESS_ZSTD;
+  void *ctx = compress_init (use_zstd);
+  if (ctx == NULL)
     return;
 
-  if (flag_compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
+  if (flag_compress_debug == COMPRESS_DEBUG_GNU_ZLIB)
+    {
+      compression_header_size = 0;
+      header_size = 12;
+    }
+  else
     {
       compression_header_size
 	= bfd_get_compression_header_size (stdoutput, NULL);
       header_size = compression_header_size;
     }
-  else
-    {
-      compression_header_size = 0;
-      header_size = 12;
-    }
 
   /* Create a new frag to contain the compression header.  */
   first_newf = frag_alloc (ob);
@@ -1531,7 +1531,7 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
       gas_assert (f->fr_type == rs_fill);
       if (f->fr_fix)
 	{
-	  out_size = compress_frag (strm, f->fr_literal, f->fr_fix,
+	  out_size = compress_frag (use_zstd, ctx, f->fr_literal, f->fr_fix,
 				    &last_newf, ob);
 	  if (out_size < 0)
 	    return;
@@ -1545,8 +1545,8 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
 	{
 	  while (count--)
 	    {
-	      out_size = compress_frag (strm, fill_literal, (int) fill_size,
-				        &last_newf, ob);
+	      out_size = compress_frag (use_zstd, ctx, fill_literal,
+					(int)fill_size, &last_newf, ob);
 	      if (out_size < 0)
 		return;
 	      compressed_size += out_size;
@@ -1579,7 +1579,7 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
 	as_fatal (_("can't extend frag"));
       next_out = obstack_next_free (ob);
       obstack_blank_fast (ob, avail_out);
-      x = compress_finish (strm, &next_out, &avail_out, &out_size);
+      x = compress_finish (use_zstd, ctx, &next_out, &avail_out, &out_size);
       if (x < 0)
 	return;
 
@@ -2540,6 +2540,8 @@ write_object_file (void)
     {
       if (flag_compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
 	stdoutput->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI;
+      else if (flag_compress_debug == COMPRESS_DEBUG_ZSTD)
+	stdoutput->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD;
       else
 	stdoutput->flags |= BFD_COMPRESS;
       bfd_map_over_sections (stdoutput, compress_debug, (char *) 0);
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2598b81d205..c528ee5aa80 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -173,6 +173,9 @@ BFD_CFLAGS = -I$(BFD_DIR) -I$(BFD_SRC)
 ZLIB = @zlibdir@ -lz
 ZLIBINC = @zlibinc@
 
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
+
 # Where is the decnumber library?  Typically in ../libdecnumber.
 LIBDECNUMBER_DIR = ../libdecnumber
 LIBDECNUMBER = $(LIBDECNUMBER_DIR)/libdecnumber.a
@@ -625,7 +628,7 @@ INTERNAL_CPPFLAGS = $(CPPFLAGS) @GUILE_CPPFLAGS@ @PYTHON_CPPFLAGS@ \
 INTERNAL_CFLAGS_BASE = \
 	$(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \
 	$(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) $(ZLIBINC) \
-	$(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
+	$(ZSTD_CFLAGS) $(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
 	$(INTL_CFLAGS) $(INCGNU) $(INCSUPPORT) $(LIBBACKTRACE_INC) \
 	$(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) $(SRCHIGH_CFLAGS) \
 	$(TOP_CFLAGS) $(PTHREAD_CFLAGS) $(DEBUGINFOD_CFLAGS)
@@ -647,7 +650,7 @@ INTERNAL_LDFLAGS = \
 # Libraries and corresponding dependencies for compiling gdb.
 # XM_CLIBS, defined in *config files, have host-dependent libs.
 # LIBIBERTY appears twice on purpose.
-CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) \
+CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) $(ZSTD_LIBS) \
         $(LIBSUPPORT) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
 	$(XM_CLIBS) $(GDBTKLIBS)  $(LIBBACKTRACE_LIB) \
 	@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
@@ -2298,6 +2301,7 @@ aclocal_m4_deps = \
 	../config/lcmessage.m4 \
 	../config/codeset.m4 \
 	../config/zlib.m4 \
+	../config/zstd.m4 \
 	../config/ax_pthread.m4
 
 $(srcdir)/aclocal.m4: @MAINTAINER_MODE_TRUE@ $(aclocal_m4_deps)
diff --git a/gdb/NEWS b/gdb/NEWS
index 9619842bc03..1457c99ff04 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -57,6 +57,8 @@
 
 * The Windows native target now supports target async.
 
+* gdb now supports zstd compressed debug sections (ELFCOMPRESS_ZSTD) for ELF.
+
 * New commands
 
 maintenance set ignore-prologue-end-flag on|off
diff --git a/gdb/acinclude.m4 b/gdb/acinclude.m4
index 95ff2b6f35e..28846119dcb 100644
--- a/gdb/acinclude.m4
+++ b/gdb/acinclude.m4
@@ -43,6 +43,7 @@ m4_include([../config/lib-link.m4])
 m4_include([../config/iconv.m4])
 
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 
 m4_include([../gdbsupport/common.m4])
 
@@ -233,7 +234,7 @@ AC_DEFUN([GDB_AC_CHECK_BFD], [
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
   LIBS="-lbfd -liberty -lz $intl $LIBS"
   AC_CACHE_CHECK(
diff --git a/gdb/config.in b/gdb/config.in
index a4975c68aad..e13a409ec2d 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -589,6 +589,9 @@
 /* Define to 1 if you have the `XML_StopParser' function. */
 #undef HAVE_XML_STOPPARSER
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Define to 1 if your system has the _etext variable. */
 #undef HAVE__ETEXT
 
diff --git a/gdb/configure b/gdb/configure
index 4dbd0c3b13c..57cd165088a 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -747,6 +747,8 @@ READLINE_DEPS
 READLINE
 LTLIBICONV
 LIBICONV
+ZSTD_LIBS
+ZSTD_CFLAGS
 zlibinc
 zlibdir
 MIG
@@ -893,6 +895,7 @@ enable_codesign
 with_pkgversion
 with_bugurl
 with_system_zlib
+with_zstd
 with_gnu_ld
 enable_rpath
 with_libiconv_prefix
@@ -961,6 +964,8 @@ DEBUGINFOD_CFLAGS
 DEBUGINFOD_LIBS
 YACC
 YFLAGS
+ZSTD_CFLAGS
+ZSTD_LIBS
 XMKMF'
 ac_subdirs_all='testsuite
 gdbtk'
@@ -1641,6 +1646,8 @@ Optional Packages:
   --with-pkgversion=PKG   Use PKG in the version string in place of "GDB"
   --with-bugurl=URL       Direct users to URL to report a bug
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
   --with-gnu-ld           assume the C compiler uses GNU ld default=no
   --with-libiconv-prefix[=DIR]  search for libiconv in DIR/include and DIR/lib
   --without-libiconv-prefix     don't search for libiconv in includedir and libdir
@@ -1721,6 +1728,8 @@ Some influential environment variables:
   YFLAGS      The list of arguments that will be passed by default to $YACC.
               This script will default YFLAGS to the empty string to avoid a
               default value of `-d' given by some make applications.
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
   XMKMF       Path to xmkmf, Makefile generator for X Window System
 
 Use these variables to override the choices made by `configure' or to help
@@ -8242,7 +8251,8 @@ if test "$ac_res" != no; then :
 fi
 
 
-# Link in zlib if we can.  This allows us to read compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to read compressed debug
+# sections.
 
   # Use the system's zlib library.
   zlibdir="-L\$(top_builddir)/../zlib"
@@ -8262,6 +8272,126 @@ fi
 
 
 
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if test "$with_zstd" != no; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+fi
+
+
+
       if test "X$prefix" = "XNONE"; then
     acl_final_prefix="$ac_default_prefix"
   else
@@ -17281,7 +17411,7 @@ WIN32LIBS="$WIN32LIBS $WIN32APILIBS"
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
   LIBS="-lbfd -liberty -lz $intl $LIBS"
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ELF support in BFD" >&5
@@ -17396,7 +17526,7 @@ fi
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
   LIBS="-lbfd -liberty -lz $intl $LIBS"
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Mach-O support in BFD" >&5
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 215a91c5b27..e8cf808d280 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -460,8 +460,10 @@ AC_SEARCH_LIBS(gethostbyname, nsl)
 # Some systems (e.g. Solaris) have `socketpair' in libsocket.
 AC_SEARCH_LIBS(socketpair, socket)
 
-# Link in zlib if we can.  This allows us to read compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to read compressed debug
+# sections.
 AM_ZLIB
+AM_ZSTD
 
 AM_ICONV
 
diff --git a/ld/Makefile.am b/ld/Makefile.am
index d31021c13e2..bbe25f3aca2 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -45,7 +45,7 @@ ELF_CLFAGS=-DELF_LIST_OPTIONS=@elf_list_options@ \
 	   -DELF_PLT_UNWIND_LIST_OPTIONS=@elf_plt_unwind_list_options@
 WARN_CFLAGS = @WARN_CFLAGS@
 NO_WERROR = @NO_WERROR@
-AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS)
+AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS) $(ZSTD_CFLAGS)
 
 # We put the scripts in the directory $(scriptdir)/ldscripts.
 # We can't put the scripts in $(datadir) because the SEARCH_DIR
@@ -959,7 +959,8 @@ ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmai
 	ldbuildid.c
 ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) \
 		      $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL_DEP) $(JANSSON_LIBS)
-ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(JANSSON_LIBS)
+ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) \
+	       $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(ZSTD_LIBS) $(JANSSON_LIBS)
 
 # Dependency tracking for the generated emulation files.
 EXTRA_ld_new_SOURCES += $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES)
diff --git a/ld/Makefile.in b/ld/Makefile.in
index ee0c98f65b0..400eed2717e 100644
--- a/ld/Makefile.in
+++ b/ld/Makefile.in
@@ -126,7 +126,8 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/plugins.m4 \
 	$(top_srcdir)/../config/po.m4 \
 	$(top_srcdir)/../config/progtest.m4 \
-	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../config/zlib.m4 \
+	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
 	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
 	$(top_srcdir)/../bfd/version.m4 $(top_srcdir)/configure.ac
@@ -477,6 +478,8 @@ WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
 XGETTEXT = @XGETTEXT@
 YACC = `if [ -f ../bison/bison ]; then echo ../bison/bison -y -L$(srcdir)/../bison/; else echo @YACC@; fi`
 YFLAGS = -d
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
@@ -564,7 +567,7 @@ ELF_CLFAGS = -DELF_LIST_OPTIONS=@elf_list_options@ \
 	   -DELF_SHLIB_LIST_OPTIONS=@elf_shlib_list_options@ \
 	   -DELF_PLT_UNWIND_LIST_OPTIONS=@elf_plt_unwind_list_options@
 
-AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS)
+AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS) $(ZSTD_CFLAGS)
 
 # We put the scripts in the directory $(scriptdir)/ldscripts.
 # We can't put the scripts in $(datadir) because the SEARCH_DIR
@@ -1011,7 +1014,9 @@ ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmai
 ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) \
 		      $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL_DEP) $(JANSSON_LIBS)
 
-ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(JANSSON_LIBS)
+ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) \
+	       $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(ZSTD_LIBS) $(JANSSON_LIBS)
+
 #
 #
 # Build a dummy plugin using libtool.
diff --git a/ld/NEWS b/ld/NEWS
index 355752e6b24..dfe2690d9f2 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* ld now supports zstd compressed debug sections.  The new option
+  --compress-debug-sections=zstd compresses debug sections with zstd.
+
 Changes in 2.39:
 
 * The ELF linker will now generate a warning message if the stack is made
diff --git a/ld/aclocal.m4 b/ld/aclocal.m4
index d20c542eed5..893e973e4f2 100644
--- a/ld/aclocal.m4
+++ b/ld/aclocal.m4
@@ -1203,6 +1203,7 @@ m4_include([../config/plugins.m4])
 m4_include([../config/po.m4])
 m4_include([../config/progtest.m4])
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/ld/config.in b/ld/config.in
index 0ccd79d59cd..3916740eee4 100644
--- a/ld/config.in
+++ b/ld/config.in
@@ -162,6 +162,9 @@
 /* Define to 1 if you have the <windows.h> header file. */
 #undef HAVE_WINDOWS_H
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Define to the sub-directory in which libtool stores uninstalled libraries.
    */
 #undef LT_OBJDIR
diff --git a/ld/configure b/ld/configure
index a1a07005400..175dd995b2b 100755
--- a/ld/configure
+++ b/ld/configure
@@ -646,6 +646,8 @@ elf_plt_unwind_list_options
 elf_shlib_list_options
 elf_list_options
 STRINGIFY
+ZSTD_LIBS
+ZSTD_CFLAGS
 zlibinc
 zlibdir
 NATIVE_LIB_DIRS
@@ -679,9 +681,6 @@ WARN_CFLAGS_FOR_BUILD
 WARN_CFLAGS
 JANSSON_LIBS
 JANSSON_CFLAGS
-PKG_CONFIG_LIBDIR
-PKG_CONFIG_PATH
-PKG_CONFIG
 enable_libctf
 ENABLE_LIBCTF_FALSE
 ENABLE_LIBCTF_TRUE
@@ -711,6 +710,9 @@ LD
 FGREP
 SED
 LIBTOOL
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
 EGREP
 CPP
 GREP
@@ -855,6 +857,7 @@ enable_werror
 enable_build_warnings
 enable_nls
 with_system_zlib
+with_zstd
 '
       ac_precious_vars='build_alias
 host_alias
@@ -868,14 +871,16 @@ CXX
 CXXFLAGS
 CCC
 CPP
-CXXCPP
 PKG_CONFIG
 PKG_CONFIG_PATH
 PKG_CONFIG_LIBDIR
+CXXCPP
 JANSSON_CFLAGS
 JANSSON_LIBS
 YACC
-YFLAGS'
+YFLAGS
+ZSTD_CFLAGS
+ZSTD_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1552,6 +1557,8 @@ Optional Packages:
   --with-lib-path=dir1:dir2...  set default LIB_PATH
   --with-sysroot=DIR Search for usr/lib et al within DIR.
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
 
 Some influential environment variables:
   CC          C compiler command
@@ -1564,12 +1571,12 @@ Some influential environment variables:
   CXX         C++ compiler command
   CXXFLAGS    C++ compiler flags
   CPP         C preprocessor
-  CXXCPP      C++ preprocessor
   PKG_CONFIG  path to pkg-config utility
   PKG_CONFIG_PATH
               directories to add to pkg-config's search path
   PKG_CONFIG_LIBDIR
               path overriding pkg-config's built-in search path
+  CXXCPP      C++ preprocessor
   JANSSON_CFLAGS
               C compiler flags for JANSSON, overriding pkg-config
   JANSSON_LIBS
@@ -1580,6 +1587,8 @@ Some influential environment variables:
   YFLAGS      The list of arguments that will be passed by default to $YACC.
               This script will default YFLAGS to the empty string to avoid a
               default value of `-d' given by some make applications.
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -5388,6 +5397,126 @@ $as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
 
 
 
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=0.9.0
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	else
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		PKG_CONFIG=""
+	fi
+fi
+
 case `pwd` in
   *\ * | *\	*)
     { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
@@ -11491,7 +11620,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11494 "configure"
+#line 11623 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11597,7 +11726,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11600 "configure"
+#line 11729 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -15586,126 +15715,6 @@ fi
 
 
 if test "x$enable_jansson" != "xno"; then
-
-
-
-
-
-
-
-if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
-	if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
-set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PKG_CONFIG+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $PKG_CONFIG in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-PKG_CONFIG=$ac_cv_path_PKG_CONFIG
-if test -n "$PKG_CONFIG"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
-$as_echo "$PKG_CONFIG" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_path_PKG_CONFIG"; then
-  ac_pt_PKG_CONFIG=$PKG_CONFIG
-  # Extract the first word of "pkg-config", so it can be a program name with args.
-set dummy pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $ac_pt_PKG_CONFIG in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
-if test -n "$ac_pt_PKG_CONFIG"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
-$as_echo "$ac_pt_PKG_CONFIG" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_pt_PKG_CONFIG" = x; then
-    PKG_CONFIG=""
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    PKG_CONFIG=$ac_pt_PKG_CONFIG
-  fi
-else
-  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
-fi
-
-fi
-if test -n "$PKG_CONFIG"; then
-	_pkg_min_version=0.9.0
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
-$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
-	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-	else
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-		PKG_CONFIG=""
-	fi
-fi
   if test -n "$PKG_CONFIG"; then :
 
 
@@ -17052,8 +17061,8 @@ $as_echo "#define HAVE_DECL_GETOPT 1" >>confdefs.h
 
 fi
 
-# Link in zlib if we can.  This allows us to read and write
-# compressed CTF sections.
+# Link in zlib/zstd if we can.  This allows us to read and write
+# compressed debug sections.
 
   # Use the system's zlib library.
   zlibdir="-L\$(top_builddir)/../zlib"
@@ -17072,6 +17081,126 @@ fi
 
 
 
+
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if test "$with_zstd" != no; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+fi
+
+
 # When converting linker scripts into strings for use in emulation
 # files, use astring.sed if the compiler supports ANSI string
 # concatenation, or ostring.sed otherwise.  This is to support the
diff --git a/ld/configure.ac b/ld/configure.ac
index eb55904c090..a491f9f1116 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -34,6 +34,7 @@ AC_PROG_GREP
 AC_GNU_SOURCE
 AC_USE_SYSTEM_EXTENSIONS
 AC_PROG_INSTALL
+PKG_PROG_PKG_CONFIG
 
 LT_INIT
 ACX_LARGEFILE
@@ -297,7 +298,6 @@ AC_ARG_ENABLE([jansson],
   [enable_jansson="no"])
 
 if test "x$enable_jansson" != "xno"; then
-  PKG_PROG_PKG_CONFIG
   AS_IF([test -n "$PKG_CONFIG"],
     [
       PKG_CHECK_MODULES(JANSSON, [jansson],
@@ -386,9 +386,10 @@ if test $ld_cv_decl_getopt_unistd_h = yes; then
 	    [Is the prototype for getopt in <unistd.h> in the expected format?])
 fi
 
-# Link in zlib if we can.  This allows us to read and write
-# compressed CTF sections.
+# Link in zlib/zstd if we can.  This allows us to read and write
+# compressed debug sections.
 AM_ZLIB
+AM_ZSTD
 
 # When converting linker scripts into strings for use in emulation
 # files, use astring.sed if the compiler supports ANSI string
diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
index c52484f35d3..acd66f907d1 100644
--- a/ld/emultempl/elf.em
+++ b/ld/emultempl/elf.em
@@ -668,6 +668,15 @@ gld${EMULATION_NAME}_handle_option (int optc)
 	link_info.compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
       else if (strcasecmp (optarg, "zlib-gabi") == 0)
 	link_info.compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
+      else if (strcasecmp (optarg, "zstd") == 0)
+	{
+#ifdef HAVE_ZSTD
+	  link_info.compress_debug = COMPRESS_DEBUG_ZSTD;
+#else
+	  einfo (_ ("%F%P: --compress-debug-sections=zstd: ld is not built "
+		    "with zstd support\n"));
+#endif
+	}
       else
 	einfo (_("%F%P: invalid --compress-debug-sections option: \`%s'\n"),
 	       optarg);
diff --git a/ld/ld.texi b/ld/ld.texi
index eabbec8faa9..9daed2e7e9f 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -2863,10 +2863,12 @@ but for most Linux based systems it will be @code{both}.
 @kindex --compress-debug-sections=zlib
 @kindex --compress-debug-sections=zlib-gnu
 @kindex --compress-debug-sections=zlib-gabi
+@kindex --compress-debug-sections=zstd
 @item --compress-debug-sections=none
 @itemx --compress-debug-sections=zlib
 @itemx --compress-debug-sections=zlib-gnu
 @itemx --compress-debug-sections=zlib-gabi
+@itemx --compress-debug-sections=zstd
 On ELF platforms, these options control how DWARF debug sections are
 compressed using zlib.
 
@@ -2880,6 +2882,9 @@ sets the SHF_COMPRESSED flag in the sections' headers.
 The @option{--compress-debug-sections=zlib} option is an alias for
 @option{--compress-debug-sections=zlib-gabi}.
 
+@option{--compress-debug-sections=zstd} compresses DWARF debug sections using
+zstd.
+
 Note that this option overrides any compression in input debug
 sections, so if a binary is linked with @option{--compress-debug-sections=none}
 for example, then any compressed debug sections in input files will be
diff --git a/ld/ldmain.c b/ld/ldmain.c
index 1bbddaaad32..71af5935b74 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -506,8 +506,12 @@ main (int argc, char **argv)
   if ((link_info.compress_debug & COMPRESS_DEBUG))
     {
       link_info.output_bfd->flags |= BFD_COMPRESS;
-      if (link_info.compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
-	link_info.output_bfd->flags |= BFD_COMPRESS_GABI;
+      if (link_info.compress_debug != COMPRESS_DEBUG_GNU_ZLIB)
+	{
+	  link_info.output_bfd->flags |= BFD_COMPRESS_GABI;
+	  if (link_info.compress_debug == COMPRESS_DEBUG_ZSTD)
+	    link_info.output_bfd->flags |= BFD_COMPRESS_ZSTD;
+	}
     }
 
   ldwrite ();
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 9225f71b3ce..299371fb775 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -2146,8 +2146,8 @@ elf_static_list_options (FILE *file)
   fprintf (file, _("\
   --package-metadata[=JSON]   Generate package metadata note\n"));
   fprintf (file, _("\
-  --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi]\n\
-                              Compress DWARF debug sections using zlib\n"));
+  --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi|zstd]\n\
+			      Compress DWARF debug sections\n"));
 #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
   fprintf (file, _("\
                                 Default: zlib-gabi\n"));
diff --git a/ld/testsuite/ld-elf/compress.exp b/ld/testsuite/ld-elf/compress.exp
index cfdd767b8ab..7b8a31cc41d 100644
--- a/ld/testsuite/ld-elf/compress.exp
+++ b/ld/testsuite/ld-elf/compress.exp
@@ -254,3 +254,20 @@ if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rt] } then {
 } else {
     pass "$test_name"
 }
+
+if { ![ld_assemble $as "--compress-debug-sections=zstd $srcdir/$subdir/empty.s" tmpdir/emptyzstd.o ] } {
+    return
+}
+set build_tests {
+  {"Build libzstdfoo.so with zstd compressed debug sections"
+   "-shared" "-fPIC -g -Wa,--compress-debug-sections=zstd -Wl,--compress-debug-sections=zstd"
+   {foo.c} {} "libzstdfoo.so"}
+}
+set run_tests {
+    {"Run zstdnormal with libzstdfoo.so with zstd compressed debug sections"
+     "tmpdir/begin.o tmpdir/libzstdfoo.so tmpdir/end.o -Wl,--compress-debug-sections=zstd" ""
+     {main.c} "zstdnormal" "normal.out" "-Wa,--compress-debug-sections=zstd"}
+}
+
+run_cc_link_tests $build_tests
+run_ld_link_exec_tests $run_tests
-- 
2.37.3.998.g577e59143f-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-23 18:20     ` Fangrui Song
@ 2022-09-23 18:57       ` Simon Marchi
  2022-09-23 20:34         ` Fangrui Song
  0 siblings, 1 reply; 32+ messages in thread
From: Simon Marchi @ 2022-09-23 18:57 UTC (permalink / raw)
  To: Fangrui Song, Nick Clifton; +Cc: Alan Modra, Jan Beulich, binutils, gdb-patches



On 2022-09-23 14:20, Fangrui Song wrote:
> On 2022-09-23, Simon Marchi wrote:
>>
>>
>> On 2022-09-23 11:45, Nick Clifton wrote:
>>> Hi Fangrui,
>>>
>>>> PR29397 PR29563: The new configure option --with-zstd defaults to auto.
>>>> If pkgconfig/libzstd.pc is found, define HAVE_ZSTD and support zstd
>>>> compressed debug sections for most tools.
> 
> Hi Simon and Nick,
> 
> I have checked that `make all-gdb` works in a --enable-gdb --without-debuginfod build.
> 
> I then inspected the 2020 commits adding AC_DEBUGINFOD to
> gdb/configure.ac and binutils/configure.ac. They come with no
> PKG_PROG_PKG_CONFIG and config/debuginfod.m4 does not have
> PKG_PROG_PKG_CONFIG, but they still work.  So I think AC_ZSTD doesn't
> need PKG_PROG_PKG_CONFIG, either. Though I have no insight why it
> behaves that way:)

Ok, I am a bit confused.  Based on my comprehension, since the first
call to PKG_CHECK_MODULES may not happen do to a condition:

  if test "x$with_debuginfod" != xno; then
    PKG_CHECK_MODULES([DEBUGINFOD], [libdebuginfod >= 0.179],
    ...
  fi

... the probing for pkg-config should not happen if --without-debuginfod
is used.  But in gdb/configure, I see that the probing for pkg-config
actually appears outside the condition.

Anyway, good if it works.

> +diff --git a/gdb/NEWS b/gdb/NEWS
> +index 9619842bc03..1457c99ff04 100644
> +--- a/gdb/NEWS
> ++++ b/gdb/NEWS
> +@@ -57,6 +57,8 @@
> + + * The Windows native target now supports target async.
> + ++* gdb now supports zstd compressed debug sections (ELFCOMPRESS_ZSTD) for ELF.
> ++

I'm not sure I understand the diff above, but I think it's missing an
empty line between the previous bullet and the new bullet.  Otherwise,
that is OK for GDB.

Simon

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-23 18:57       ` Simon Marchi
@ 2022-09-23 20:34         ` Fangrui Song
  2022-09-24  5:43           ` Eli Zaretskii
  0 siblings, 1 reply; 32+ messages in thread
From: Fangrui Song @ 2022-09-23 20:34 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Nick Clifton, Alan Modra, Jan Beulich, binutils, gdb-patches

On 2022-09-23, Simon Marchi wrote:
>
>
>On 2022-09-23 14:20, Fangrui Song wrote:
>> On 2022-09-23, Simon Marchi wrote:
>>>
>>>
>>> On 2022-09-23 11:45, Nick Clifton wrote:
>>>> Hi Fangrui,
>>>>
>>>>> PR29397 PR29563: The new configure option --with-zstd defaults to auto.
>>>>> If pkgconfig/libzstd.pc is found, define HAVE_ZSTD and support zstd
>>>>> compressed debug sections for most tools.
>>
>> Hi Simon and Nick,
>>
>> I have checked that `make all-gdb` works in a --enable-gdb --without-debuginfod build.
>>
>> I then inspected the 2020 commits adding AC_DEBUGINFOD to
>> gdb/configure.ac and binutils/configure.ac. They come with no
>> PKG_PROG_PKG_CONFIG and config/debuginfod.m4 does not have
>> PKG_PROG_PKG_CONFIG, but they still work.  So I think AC_ZSTD doesn't
>> need PKG_PROG_PKG_CONFIG, either. Though I have no insight why it
>> behaves that way:)
>
>Ok, I am a bit confused.  Based on my comprehension, since the first
>call to PKG_CHECK_MODULES may not happen do to a condition:
>
>  if test "x$with_debuginfod" != xno; then
>    PKG_CHECK_MODULES([DEBUGINFOD], [libdebuginfod >= 0.179],
>    ...
>  fi
>
>... the probing for pkg-config should not happen if --without-debuginfod
>is used.  But in gdb/configure, I see that the probing for pkg-config
>actually appears outside the condition.
>
>Anyway, good if it works.
>
>> +diff --git a/gdb/NEWS b/gdb/NEWS
>> +index 9619842bc03..1457c99ff04 100644
>> +--- a/gdb/NEWS
>> ++++ b/gdb/NEWS
>> +@@ -57,6 +57,8 @@
>> + + * The Windows native target now supports target async.
>> + ++* gdb now supports zstd compressed debug sections (ELFCOMPRESS_ZSTD) for ELF.
>> ++
>
>I'm not sure I understand the diff above, but I think it's missing an
>empty line between the previous bullet and the new bullet.  Otherwise,
>that is OK for GDB.
>
>Simon

Thanks!  The gdb news entry looks like (immediately before "* New commands")

--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -57,6 +57,8 @@
  
  * The Windows native target now supports target async.
  
+* gdb now supports zstd compressed debug sections (ELFCOMPRESS_ZSTD) for ELF.
+
  * New commands
  
  maintenance set ignore-prologue-end-flag on|off


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-23 20:34         ` Fangrui Song
@ 2022-09-24  5:43           ` Eli Zaretskii
  0 siblings, 0 replies; 32+ messages in thread
From: Eli Zaretskii @ 2022-09-24  5:43 UTC (permalink / raw)
  To: Fangrui Song; +Cc: simon.marchi, gdb-patches, binutils, nickc, jbeulich, amodra

> Date: Fri, 23 Sep 2022 13:34:17 -0700
> From: Fangrui Song via Gdb-patches <gdb-patches@sourceware.org>
> Cc: gdb-patches@sourceware.org, binutils@sourceware.org,
>  Nick Clifton <nickc@redhat.com>, Jan Beulich <jbeulich@suse.com>,
>  Alan Modra <amodra@gmail.com>
> 
> Thanks!  The gdb news entry looks like (immediately before "* New commands")
> 
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -57,6 +57,8 @@
>   
>   * The Windows native target now supports target async.
>   
> +* gdb now supports zstd compressed debug sections (ELFCOMPRESS_ZSTD) for ELF.
> +
>   * New commands
>   
>   maintenance set ignore-prologue-end-flag on|off

This is OK, thanks.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-23  4:08 [PATCH v3] binutils, gdb: support zstd compressed debug sections Fangrui Song
  2022-09-23 14:32 ` Simon Marchi
  2022-09-23 15:45 ` Nick Clifton
@ 2022-09-24  6:53 ` Enze Li
  2022-09-24  7:13   ` Fangrui Song
  2022-09-27 18:08 ` Tom Tromey
  2022-09-29 11:43 ` Martin Liška
  4 siblings, 1 reply; 32+ messages in thread
From: Enze Li @ 2022-09-24  6:53 UTC (permalink / raw)
  To: Fangrui Song via Gdb-patches
  Cc: Alan Modra, Jan Beulich, Nick Clifton, Simon Marchi,
	Fangrui Song, binutils

Hi Fangrui,

One nit, maybe not an important one.

A proper committed message should include a link to the relevant bug on
Bugzilla. Like this,

  Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29563

For more detail, see here[1].

[1] https://sourceware.org/gdb/wiki/ContributionChecklist#Properly_formatted_commit_messages

Thanks,
Enze

On Thu, Sep 22 2022 at 09:08:37 PM -0700, Fangrui Song via Gdb-patches wrote:

> PR29397 PR29563: The new configure option --with-zstd defaults to auto.
> If pkgconfig/libzstd.pc is found, define HAVE_ZSTD and support zstd
> compressed debug sections for most tools.
>
> * bfd: for addr2line, objdump --dwarf, gdb, etc
> * gas: support --compress-debug-sections=zstd
> * ld: support ELFCOMPRESS_ZSTD input and --compress-debug-sections=zstd
> * objcopy: support ELFCOMPRESS_ZSTD input for
>   --decompress-debug-sections and --compress-debug-sections=zstd
> * gdb: support ELFCOMPRESS_ZSTD input.  The bfd change references zstd
>   symbols, so gdb has to link against -lzstd in this patch.
>
> If zstd is not supported, ELFCOMPRESS_ZSTD input triggers an error.  We
> can avoid HAVE_ZSTD if binutils-gdb imports zstd/ like zlib/, but this
> is too heavyweight, so don't do it for now.
>
> ```
> % ld/ld-new a.o
> ld/ld-new: a.o: section .debug_abbrev is compressed with zstd, but BFD is not built with zstd support
> ...
>
> % ld/ld-new a.o --compress-debug-sections=zstd
> ld/ld-new: --compress-debug-sections=zstd: ld is not built with zstd support
>
> % binutils/objcopy --compress-debug-sections=zstd a.o b.o
> binutils/objcopy: --compress-debug-sections=zstd: binutils is not built with zstd support
>
> % binutils/objcopy b.o --decompress-debug-sections
> binutils/objcopy: zstd.o: section .debug_abbrev is compressed with zstd, but BFD is not built with zstd support
> ...
> ```
> ---
> Changes from v1:
> * use PKG_CHECK_MODULES to check libzstd.pc
>
> Changes from v2:
> * Improve PKG_CHECK_MODULES, autoreconf -vf
> * objcopy: check --compress-debug-sections=zstd in a !HAVE_ZSTD build
> ---
>  bfd/Makefile.am                              |   4 +-
>  bfd/Makefile.in                              |  13 +-
>  bfd/aclocal.m4                               |   2 +
>  bfd/bfd-in.h                                 |   3 +-
>  bfd/bfd-in2.h                                |  11 +-
>  bfd/bfd.c                                    |  26 +-
>  bfd/compress.c                               |  72 +++-
>  bfd/config.in                                |   3 +
>  bfd/configure                                | 268 ++++++++++++-
>  bfd/configure.ac                             |   3 +-
>  bfd/elf.c                                    |  12 +
>  bfd/elfxx-target.h                           |   6 +-
>  bfd/section.c                                |   3 +-
>  binutils/Makefile.in                         |   5 +-
>  binutils/aclocal.m4                          |   1 +
>  binutils/config.in                           |   3 +
>  binutils/configure                           | 135 ++++++-
>  binutils/configure.ac                        |   3 +-
>  binutils/doc/binutils.texi                   |  16 +-
>  binutils/objcopy.c                           |  19 +-
>  binutils/testsuite/binutils-all/compress.exp |  44 +++
>  config/zstd.m4                               |  24 ++
>  configure                                    |  10 +
>  configure.ac                                 |   3 +
>  gas/Makefile.am                              |   4 +-
>  gas/Makefile.in                              |  13 +-
>  gas/aclocal.m4                               |   2 +
>  gas/as.c                                     |  13 +-
>  gas/compress-debug.c                         |  60 ++-
>  gas/compress-debug.h                         |  10 +-
>  gas/config.in                                |   3 +
>  gas/configure                                | 268 ++++++++++++-
>  gas/configure.ac                             |   3 +-
>  gas/doc/as.texi                              |  11 +-
>  gas/write.c                                  |  36 +-
>  gdb/Makefile.in                              |   8 +-
>  gdb/acinclude.m4                             |   3 +-
>  gdb/config.in                                |   3 +
>  gdb/configure                                | 136 ++++++-
>  gdb/configure.ac                             |   4 +-
>  ld/Makefile.am                               |   5 +-
>  ld/Makefile.in                               |  11 +-
>  ld/aclocal.m4                                |   1 +
>  ld/config.in                                 |   3 +
>  ld/configure                                 | 389 ++++++++++++-------
>  ld/configure.ac                              |   7 +-
>  ld/emultempl/elf.em                          |   9 +
>  ld/ld.texi                                   |   5 +
>  ld/ldmain.c                                  |   8 +-
>  ld/lexsup.c                                  |   4 +-
>  ld/testsuite/ld-elf/compress.exp             |  17 +
>  51 files changed, 1470 insertions(+), 255 deletions(-)
>  create mode 100644 config/zstd.m4
>
> diff --git a/bfd/Makefile.am b/bfd/Makefile.am
> index c23dff6cac3..cfe903c63f0 100644
> --- a/bfd/Makefile.am
> +++ b/bfd/Makefile.am
> @@ -57,7 +57,7 @@ ZLIBINC = @zlibinc@
>  
>  WARN_CFLAGS = @WARN_CFLAGS@
>  NO_WERROR = @NO_WERROR@
> -AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
> +AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
>  AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DLIBDIR='"$(libdir)"' @LARGEFILE_CPPFLAGS@
>  if PLUGINS
>  bfdinclude_HEADERS += $(INCDIR)/plugin-api.h
> @@ -776,7 +776,7 @@ ofiles: stamp-ofiles ; @true
>  libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
>  EXTRA_libbfd_la_SOURCES = $(CFILES)
>  libbfd_la_DEPENDENCIES = $(OFILES) ofiles
> -libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB)
> +libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS)
>  libbfd_la_LDFLAGS += -release `cat libtool-soversion` @SHARED_LDFLAGS@
>  
>  # libtool will build .libs/libbfd.a.  We create libbfd.a in the build
> diff --git a/bfd/Makefile.in b/bfd/Makefile.in
> index 82843d2d61d..6be41a72a59 100644
> --- a/bfd/Makefile.in
> +++ b/bfd/Makefile.in
> @@ -122,10 +122,12 @@ am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
>  	$(top_srcdir)/../config/lead-dot.m4 \
>  	$(top_srcdir)/../config/nls.m4 \
>  	$(top_srcdir)/../config/override.m4 \
> +	$(top_srcdir)/../config/pkg.m4 \
>  	$(top_srcdir)/../config/plugins.m4 \
>  	$(top_srcdir)/../config/po.m4 \
>  	$(top_srcdir)/../config/progtest.m4 \
> -	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
> +	$(top_srcdir)/../config/zlib.m4 \
> +	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
>  	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
>  	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
>  	$(top_srcdir)/bfd.m4 $(top_srcdir)/warning.m4 \
> @@ -399,6 +401,9 @@ PACKAGE_URL = @PACKAGE_URL@
>  PACKAGE_VERSION = @PACKAGE_VERSION@
>  PATH_SEPARATOR = @PATH_SEPARATOR@
>  PKGVERSION = @PKGVERSION@
> +PKG_CONFIG = @PKG_CONFIG@
> +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
> +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
>  POSUB = @POSUB@
>  RANLIB = @RANLIB@
>  REPORT_BUGS_TEXI = @REPORT_BUGS_TEXI@
> @@ -416,6 +421,8 @@ WARN_CFLAGS = @WARN_CFLAGS@
>  WARN_CFLAGS_FOR_BUILD = @WARN_CFLAGS_FOR_BUILD@
>  WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
>  XGETTEXT = @XGETTEXT@
> +ZSTD_CFLAGS = @ZSTD_CFLAGS@
> +ZSTD_LIBS = @ZSTD_LIBS@
>  abs_builddir = @abs_builddir@
>  abs_srcdir = @abs_srcdir@
>  abs_top_builddir = @abs_top_builddir@
> @@ -520,7 +527,7 @@ libbfd_la_LDFLAGS = $(am__append_1) -release `cat libtool-soversion` \
>  # case both are empty.
>  ZLIB = @zlibdir@ -lz
>  ZLIBINC = @zlibinc@
> -AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
> +AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
>  AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DLIBDIR='"$(libdir)"' \
>  	@LARGEFILE_CPPFLAGS@ @HDEFINES@ @COREFLAG@ @TDEFINES@ \
>  	$(CSEARCH) $(CSWITCHES) $(HAVEVECS) @INCINTL@
> @@ -1199,7 +1206,7 @@ OFILES = $(BFD_BACKENDS) $(BFD_MACHINES) @COREFILE@ @bfd64_libs@
>  libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
>  EXTRA_libbfd_la_SOURCES = $(CFILES)
>  libbfd_la_DEPENDENCIES = $(OFILES) ofiles
> -libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB)
> +libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS)
>  
>  # libtool will build .libs/libbfd.a.  We create libbfd.a in the build
>  # directory so that we don't have to convert all the programs that use
> diff --git a/bfd/aclocal.m4 b/bfd/aclocal.m4
> index 0f8aa1d4518..09b849dfc87 100644
> --- a/bfd/aclocal.m4
> +++ b/bfd/aclocal.m4
> @@ -1176,10 +1176,12 @@ m4_include([../config/largefile.m4])
>  m4_include([../config/lead-dot.m4])
>  m4_include([../config/nls.m4])
>  m4_include([../config/override.m4])
> +m4_include([../config/pkg.m4])
>  m4_include([../config/plugins.m4])
>  m4_include([../config/po.m4])
>  m4_include([../config/progtest.m4])
>  m4_include([../config/zlib.m4])
> +m4_include([../config/zstd.m4])
>  m4_include([../libtool.m4])
>  m4_include([../ltoptions.m4])
>  m4_include([../ltsugar.m4])
> diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
> index 8605056aefe..4765ea80536 100644
> --- a/bfd/bfd-in.h
> +++ b/bfd/bfd-in.h
> @@ -342,7 +342,8 @@ enum compressed_debug_section_type
>    COMPRESS_DEBUG_NONE = 0,
>    COMPRESS_DEBUG = 1 << 0,
>    COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1,
> -  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2
> +  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2,
> +  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3
>  };
>  
>  /* This structure is used to keep track of stabs in sections
> diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
> index 79fcc4eb912..5c80956c79c 100644
> --- a/bfd/bfd-in2.h
> +++ b/bfd/bfd-in2.h
> @@ -349,7 +349,8 @@ enum compressed_debug_section_type
>    COMPRESS_DEBUG_NONE = 0,
>    COMPRESS_DEBUG = 1 << 0,
>    COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1,
> -  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2
> +  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2,
> +  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3
>  };
>  
>  /* This structure is used to keep track of stabs in sections
> @@ -962,7 +963,8 @@ typedef struct bfd_section
>    unsigned int compress_status : 2;
>  #define COMPRESS_SECTION_NONE    0
>  #define COMPRESS_SECTION_DONE    1
> -#define DECOMPRESS_SECTION_SIZED 2
> +#define DECOMPRESS_SECTION_ZLIB  2
> +#define DECOMPRESS_SECTION_ZSTD  3
>  
>    /* The following flags are used by the ELF linker. */
>  
> @@ -6637,12 +6639,14 @@ struct bfd
>  #define BFD_ARCHIVE_FULL_PATH  0x100000
>  
>  #define BFD_CLOSED_BY_CACHE    0x200000
> +  /* Compress sections in this BFD with SHF_COMPRESSED zstd.  */
> +#define BFD_COMPRESS_ZSTD      0x400000
>  
>    /* Flags bits to be saved in bfd_preserve_save.  */
>  #define BFD_FLAGS_SAVED \
>    (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
>     | BFD_PLUGIN | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON \
> -   | BFD_USE_ELF_STT_COMMON)
> +   | BFD_USE_ELF_STT_COMMON | BFD_COMPRESS_ZSTD)
>  
>    /* Flags bits which are for BFD use only.  */
>  #define BFD_FLAGS_FOR_BFD_USE_MASK \
> @@ -7271,6 +7275,7 @@ void bfd_update_compression_header
>  
>  bool bfd_check_compression_header
>     (bfd *abfd, bfd_byte *contents, asection *sec,
> +    unsigned int *ch_type,
>      bfd_size_type *uncompressed_size,
>      unsigned int *uncompressed_alignment_power);
>  
> diff --git a/bfd/bfd.c b/bfd/bfd.c
> index 0a21db11fd6..5f2033bee7a 100644
> --- a/bfd/bfd.c
> +++ b/bfd/bfd.c
> @@ -177,12 +177,15 @@ CODE_FRAGMENT
>  .#define BFD_ARCHIVE_FULL_PATH  0x100000
>  .
>  .#define BFD_CLOSED_BY_CACHE    0x200000
> +
> +.  {* Compress sections in this BFD with SHF_COMPRESSED zstd.  *}
> +.#define BFD_COMPRESS_ZSTD      0x400000
>  .
>  .  {* Flags bits to be saved in bfd_preserve_save.  *}
>  .#define BFD_FLAGS_SAVED \
>  .  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
>  .   | BFD_PLUGIN | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON \
> -.   | BFD_USE_ELF_STT_COMMON)
> +.   | BFD_USE_ELF_STT_COMMON | BFD_COMPRESS_ZSTD)
>  .
>  .  {* Flags bits which are for BFD use only.  *}
>  .#define BFD_FLAGS_FOR_BFD_USE_MASK \
> @@ -2500,6 +2503,9 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
>  	{
>  	  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
>  	  struct bfd_elf_section_data * esd = elf_section_data (sec);
> +	  const unsigned int ch_type = abfd->flags & BFD_COMPRESS_ZSTD
> +					   ? ELFCOMPRESS_ZSTD
> +					   : ELFCOMPRESS_ZLIB;
>  
>  	  /* Set the SHF_COMPRESSED bit.  */
>  	  elf_section_flags (sec) |= SHF_COMPRESSED;
> @@ -2507,7 +2513,7 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
>  	  if (bed->s->elfclass == ELFCLASS32)
>  	    {
>  	      Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) contents;
> -	      bfd_put_32 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
> +	      bfd_put_32 (abfd, ch_type, &echdr->ch_type);
>  	      bfd_put_32 (abfd, sec->size, &echdr->ch_size);
>  	      bfd_put_32 (abfd, 1u << sec->alignment_power,
>  			  &echdr->ch_addralign);
> @@ -2518,7 +2524,7 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
>  	  else
>  	    {
>  	      Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) contents;
> -	      bfd_put_32 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
> +	      bfd_put_32 (abfd, ch_type, &echdr->ch_type);
>  	      bfd_put_32 (abfd, 0, &echdr->ch_reserved);
>  	      bfd_put_64 (abfd, sec->size, &echdr->ch_size);
>  	      bfd_put_64 (abfd, UINT64_C (1) << sec->alignment_power,
> @@ -2553,14 +2559,15 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
>     SYNOPSIS
>  	bool bfd_check_compression_header
>  	  (bfd *abfd, bfd_byte *contents, asection *sec,
> +	  unsigned int *ch_type,
>  	  bfd_size_type *uncompressed_size,
>  	  unsigned int *uncompressed_alignment_power);
>  
>  DESCRIPTION
> -	Check the compression header at CONTENTS of SEC in ABFD and
> -	store the uncompressed size in UNCOMPRESSED_SIZE and the
> -	uncompressed data alignment in UNCOMPRESSED_ALIGNMENT_POWER
> -	if the compression header is valid.
> +	Check the compression header at CONTENTS of SEC in ABFD and store the
> +	ch_type in CH_TYPE, uncompressed size in UNCOMPRESSED_SIZE, and the
> +	uncompressed data alignment in UNCOMPRESSED_ALIGNMENT_POWER if the
> +	compression header is valid.
>  
>  RETURNS
>  	Return TRUE if the compression header is valid.
> @@ -2569,6 +2576,7 @@ RETURNS
>  bool
>  bfd_check_compression_header (bfd *abfd, bfd_byte *contents,
>  			      asection *sec,
> +			      unsigned int *ch_type,
>  			      bfd_size_type *uncompressed_size,
>  			      unsigned int *uncompressed_alignment_power)
>  {
> @@ -2591,7 +2599,9 @@ bfd_check_compression_header (bfd *abfd, bfd_byte *contents,
>  	  chdr.ch_size = bfd_get_64 (abfd, &echdr->ch_size);
>  	  chdr.ch_addralign = bfd_get_64 (abfd, &echdr->ch_addralign);
>  	}
> -      if (chdr.ch_type == ELFCOMPRESS_ZLIB
> +      *ch_type = chdr.ch_type;
> +      if ((chdr.ch_type == ELFCOMPRESS_ZLIB
> +	   || chdr.ch_type == ELFCOMPRESS_ZSTD)
>  	  && chdr.ch_addralign == (chdr.ch_addralign & -chdr.ch_addralign))
>  	{
>  	  *uncompressed_size = chdr.ch_size;
> diff --git a/bfd/compress.c b/bfd/compress.c
> index b2e39826e38..95c1f4c42d1 100644
> --- a/bfd/compress.c
> +++ b/bfd/compress.c
> @@ -20,18 +20,31 @@
>  
>  #include "sysdep.h"
>  #include <zlib.h>
> +#ifdef HAVE_ZSTD
> +#include <zstd.h>
> +#endif
>  #include "bfd.h"
> +#include "elf-bfd.h"
>  #include "libbfd.h"
>  #include "safe-ctype.h"
>  
>  #define MAX_COMPRESSION_HEADER_SIZE 24
>  
>  static bool
> -decompress_contents (bfd_byte *compressed_buffer,
> +decompress_contents (bool is_zstd, bfd_byte *compressed_buffer,
>  		     bfd_size_type compressed_size,
>  		     bfd_byte *uncompressed_buffer,
>  		     bfd_size_type uncompressed_size)
>  {
> +  if (is_zstd)
> +    {
> +#ifdef HAVE_ZSTD
> +      size_t ret = ZSTD_decompress (uncompressed_buffer, uncompressed_size,
> +				    compressed_buffer, compressed_size);
> +      return !ZSTD_isError (ret);
> +#endif
> +    }
> +
>    z_stream strm;
>    int rc;
>  
> @@ -69,7 +82,7 @@ decompress_contents (bfd_byte *compressed_buffer,
>  }
>  
>  /* Compress data of the size specified in @var{uncompressed_size}
> -   and pointed to by @var{uncompressed_buffer} using zlib and store
> +   and pointed to by @var{uncompressed_buffer} using zlib/zstd and store
>     as the contents field.  This function assumes the contents
>     field was allocated using bfd_malloc() or equivalent.
>  
> @@ -150,9 +163,10 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
>        sec->size = orig_uncompressed_size;
>        if (decompress)
>  	{
> -	  if (!decompress_contents (uncompressed_buffer
> -				    + orig_compression_header_size,
> -				    zlib_size, buffer, buffer_size))
> +	  if (!decompress_contents (
> +		  sec->compress_status == DECOMPRESS_SECTION_ZSTD,
> +		  uncompressed_buffer + orig_compression_header_size,
> +		  zlib_size, buffer, buffer_size))
>  	    {
>  	      bfd_set_error (bfd_error_bad_value);
>  	      bfd_release (abfd, buffer);
> @@ -175,10 +189,23 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
>      }
>    else
>      {
> -      if (compress ((Bytef*) buffer + header_size,
> -		    &compressed_size,
> -		    (const Bytef*) uncompressed_buffer,
> -		    uncompressed_size) != Z_OK)
> +      if (abfd->flags & BFD_COMPRESS_ZSTD)
> +	{
> +#if HAVE_ZSTD
> +	  compressed_size = ZSTD_compress (
> +		  buffer + header_size, compressed_size, uncompressed_buffer,
> +		  uncompressed_size, ZSTD_CLEVEL_DEFAULT);
> +	  if (ZSTD_isError (compressed_size))
> +	    {
> +	      bfd_release (abfd, buffer);
> +	      bfd_set_error (bfd_error_bad_value);
> +	      return 0;
> +	    }
> +#endif
> +	}
> +      else if (compress ((Bytef *)buffer + header_size, &compressed_size,
> +			 (const Bytef *)uncompressed_buffer, uncompressed_size)
> +	       != Z_OK)
>  	{
>  	  bfd_release (abfd, buffer);
>  	  bfd_set_error (bfd_error_bad_value);
> @@ -237,6 +264,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
>    bfd_size_type save_rawsize;
>    bfd_byte *compressed_buffer;
>    unsigned int compression_header_size;
> +  const unsigned int compress_status = sec->compress_status;
>  
>    if (abfd->direction != write_direction && sec->rawsize != 0)
>      sz = sec->rawsize;
> @@ -248,7 +276,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
>        return true;
>      }
>  
> -  switch (sec->compress_status)
> +  switch (compress_status)
>      {
>      case COMPRESS_SECTION_NONE:
>        if (p == NULL)
> @@ -298,7 +326,8 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
>        *ptr = p;
>        return true;
>  
> -    case DECOMPRESS_SECTION_SIZED:
> +    case DECOMPRESS_SECTION_ZLIB:
> +    case DECOMPRESS_SECTION_ZSTD:
>        /* Read in the full compressed section contents.  */
>        compressed_buffer = (bfd_byte *) bfd_malloc (sec->compressed_size);
>        if (compressed_buffer == NULL)
> @@ -316,7 +345,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
>        /* Restore rawsize and size.  */
>        sec->rawsize = save_rawsize;
>        sec->size = save_size;
> -      sec->compress_status = DECOMPRESS_SECTION_SIZED;
> +      sec->compress_status = compress_status;
>        if (!ret)
>  	goto fail_compressed;
>  
> @@ -330,8 +359,10 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
>  	/* Set header size to the zlib header size if it is a
>  	   SHF_COMPRESSED section.  */
>  	compression_header_size = 12;
> -      if (!decompress_contents (compressed_buffer + compression_header_size,
> -				sec->compressed_size - compression_header_size, p, sz))
> +      if (!decompress_contents (compress_status == DECOMPRESS_SECTION_ZSTD,
> +				compressed_buffer + compression_header_size,
> +				sec->compressed_size - compression_header_size,
> +				p, sz))
>  	{
>  	  bfd_set_error (bfd_error_bad_value);
>  	  if (p != *ptr)
> @@ -381,7 +412,8 @@ DESCRIPTION
>  void
>  bfd_cache_section_contents (asection *sec, void *contents)
>  {
> -  if (sec->compress_status == DECOMPRESS_SECTION_SIZED)
> +  if (sec->compress_status == DECOMPRESS_SECTION_ZLIB
> +      || sec->compress_status == DECOMPRESS_SECTION_ZSTD)
>      sec->compress_status = COMPRESS_SECTION_DONE;
>    sec->contents = contents;
>    sec->flags |= SEC_IN_MEMORY;
> @@ -418,6 +450,7 @@ bfd_is_section_compressed_with_header (bfd *abfd, sec_ptr sec,
>    int compression_header_size;
>    int header_size;
>    unsigned int saved = sec->compress_status;
> +  unsigned int ch_type;
>    bool compressed;
>  
>    *uncompressed_align_pow_p = 0;
> @@ -448,7 +481,7 @@ bfd_is_section_compressed_with_header (bfd *abfd, sec_ptr sec,
>      {
>        if (compression_header_size != 0)
>  	{
> -	  if (!bfd_check_compression_header (abfd, header, sec,
> +	  if (!bfd_check_compression_header (abfd, header, sec, &ch_type,
>  					     uncompressed_size_p,
>  					     uncompressed_align_pow_p))
>  	    compression_header_size = -1;
> @@ -507,7 +540,7 @@ SYNOPSIS
>  DESCRIPTION
>  	Record compressed section size, update section size with
>  	decompressed size and set compress_status to
> -	DECOMPRESS_SECTION_SIZED.
> +	DECOMPRESS_SECTION_{ZLIB,ZSTD}.
>  
>  	Return @code{FALSE} if the section is not a valid compressed
>  	section.  Otherwise, return @code{TRUE}.
> @@ -521,6 +554,7 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
>    int header_size;
>    bfd_size_type uncompressed_size;
>    unsigned int uncompressed_alignment_power = 0;
> +  unsigned int ch_type;
>    z_stream strm;
>  
>    compression_header_size = bfd_get_compression_header_size (abfd, sec);
> @@ -550,6 +584,7 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
>        uncompressed_size = bfd_getb64 (header + 4);
>      }
>    else if (!bfd_check_compression_header (abfd, header, sec,
> +					  &ch_type,
>  					  &uncompressed_size,
>  					  &uncompressed_alignment_power))
>      {
> @@ -569,7 +604,8 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
>    sec->compressed_size = sec->size;
>    sec->size = uncompressed_size;
>    bfd_set_section_alignment (sec, uncompressed_alignment_power);
> -  sec->compress_status = DECOMPRESS_SECTION_SIZED;
> +  sec->compress_status = ch_type == ELFCOMPRESS_ZSTD ? DECOMPRESS_SECTION_ZSTD
> +						     : DECOMPRESS_SECTION_ZLIB;
>  
>    return true;
>  }
> diff --git a/bfd/config.in b/bfd/config.in
> index f54a3cacbea..a59304e0a66 100644
> --- a/bfd/config.in
> +++ b/bfd/config.in
> @@ -232,6 +232,9 @@
>  /* Define to 1 if you have the <windows.h> header file. */
>  #undef HAVE_WINDOWS_H
>  
> +/* Define to 1 if zstd is enabled. */
> +#undef HAVE_ZSTD
> +
>  /* Define to the sub-directory in which libtool stores uninstalled libraries.
>     */
>  #undef LT_OBJDIR
> diff --git a/bfd/configure b/bfd/configure
> index 075d2ee0a1b..d905a7bf7a8 100755
> --- a/bfd/configure
> +++ b/bfd/configure
> @@ -652,6 +652,11 @@ TDEFINES
>  SHARED_LIBADD
>  SHARED_LDFLAGS
>  LIBM
> +ZSTD_LIBS
> +ZSTD_CFLAGS
> +PKG_CONFIG_LIBDIR
> +PKG_CONFIG_PATH
> +PKG_CONFIG
>  zlibinc
>  zlibdir
>  EXEEXT_FOR_BUILD
> @@ -839,6 +844,7 @@ enable_maintainer_mode
>  enable_install_libbfd
>  enable_nls
>  with_system_zlib
> +with_zstd
>  '
>        ac_precious_vars='build_alias
>  host_alias
> @@ -848,7 +854,12 @@ CFLAGS
>  LDFLAGS
>  LIBS
>  CPPFLAGS
> -CPP'
> +CPP
> +PKG_CONFIG
> +PKG_CONFIG_PATH
> +PKG_CONFIG_LIBDIR
> +ZSTD_CFLAGS
> +ZSTD_LIBS'
>  
>  
>  # Initialize some variables set by options.
> @@ -1511,6 +1522,8 @@ Optional Packages:
>                            Binutils"
>    --with-bugurl=URL       Direct users to URL to report a bug
>    --with-system-zlib      use installed libz
> +  --with-zstd             support zstd compressed debug sections
> +                          (default=auto)
>  
>  Some influential environment variables:
>    CC          C compiler command
> @@ -1521,6 +1534,13 @@ Some influential environment variables:
>    CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
>                you have headers in a nonstandard directory <include dir>
>    CPP         C preprocessor
> +  PKG_CONFIG  path to pkg-config utility
> +  PKG_CONFIG_PATH
> +              directories to add to pkg-config's search path
> +  PKG_CONFIG_LIBDIR
> +              path overriding pkg-config's built-in search path
> +  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
> +  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
>  
>  Use these variables to override the choices made by `configure' or to help
>  it to find libraries and programs with nonstandard names/locations.
> @@ -11086,7 +11106,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 11089 "configure"
> +#line 11109 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -11192,7 +11212,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 11195 "configure"
> +#line 11215 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -12995,7 +13015,7 @@ $as_echo "#define USE_BINARY_FOPEN 1" >>confdefs.h
>   ;;
>  esac
>  
> -# Link in zlib if we can.  This allows us to read compressed debug sections.
> +# Link in zlib/zstd if we can.  This allows us to read compressed debug sections.
>  # This is used only by compress.c.
>  
>    # Use the system's zlib library.
> @@ -13015,6 +13035,246 @@ fi
>  
>  
>  
> +
> +
> +
> +
> +
> +
> +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
> +	if test -n "$ac_tool_prefix"; then
> +  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
> +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
> +$as_echo_n "checking for $ac_word... " >&6; }
> +if ${ac_cv_path_PKG_CONFIG+:} false; then :
> +  $as_echo_n "(cached) " >&6
> +else
> +  case $PKG_CONFIG in
> +  [\\/]* | ?:[\\/]*)
> +  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
> +  ;;
> +  *)
> +  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
> +for as_dir in $PATH
> +do
> +  IFS=$as_save_IFS
> +  test -z "$as_dir" && as_dir=.
> +    for ac_exec_ext in '' $ac_executable_extensions; do
> +  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
> +    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
> +    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
> +    break 2
> +  fi
> +done
> +  done
> +IFS=$as_save_IFS
> +
> +  ;;
> +esac
> +fi
> +PKG_CONFIG=$ac_cv_path_PKG_CONFIG
> +if test -n "$PKG_CONFIG"; then
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
> +$as_echo "$PKG_CONFIG" >&6; }
> +else
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +fi
> +
> +
> +fi
> +if test -z "$ac_cv_path_PKG_CONFIG"; then
> +  ac_pt_PKG_CONFIG=$PKG_CONFIG
> +  # Extract the first word of "pkg-config", so it can be a program name with args.
> +set dummy pkg-config; ac_word=$2
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
> +$as_echo_n "checking for $ac_word... " >&6; }
> +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
> +  $as_echo_n "(cached) " >&6
> +else
> +  case $ac_pt_PKG_CONFIG in
> +  [\\/]* | ?:[\\/]*)
> +  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
> +  ;;
> +  *)
> +  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
> +for as_dir in $PATH
> +do
> +  IFS=$as_save_IFS
> +  test -z "$as_dir" && as_dir=.
> +    for ac_exec_ext in '' $ac_executable_extensions; do
> +  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
> +    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
> +    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
> +    break 2
> +  fi
> +done
> +  done
> +IFS=$as_save_IFS
> +
> +  ;;
> +esac
> +fi
> +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
> +if test -n "$ac_pt_PKG_CONFIG"; then
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
> +$as_echo "$ac_pt_PKG_CONFIG" >&6; }
> +else
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +fi
> +
> +  if test "x$ac_pt_PKG_CONFIG" = x; then
> +    PKG_CONFIG=""
> +  else
> +    case $cross_compiling:$ac_tool_warned in
> +yes:)
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
> +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
> +ac_tool_warned=yes ;;
> +esac
> +    PKG_CONFIG=$ac_pt_PKG_CONFIG
> +  fi
> +else
> +  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
> +fi
> +
> +fi
> +if test -n "$PKG_CONFIG"; then
> +	_pkg_min_version=0.9.0
> +	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
> +$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
> +	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
> +		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
> +$as_echo "yes" >&6; }
> +	else
> +		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +		PKG_CONFIG=""
> +	fi
> +fi
> +
> +
> +# Check whether --with-zstd was given.
> +if test "${with_zstd+set}" = set; then :
> +  withval=$with_zstd;
> +else
> +  with_zstd=auto
> +fi
> +
> +
> +if test "$with_zstd" != no; then
> +
> +pkg_failed=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
> +$as_echo_n "checking for libzstd... " >&6; }
> +
> +if test -n "$ZSTD_CFLAGS"; then
> +    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
> + elif test -n "$PKG_CONFIG"; then
> +    if test -n "$PKG_CONFIG" && \
> +    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
> +  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
> +  ac_status=$?
> +  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; then
> +  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
> +		      test "x$?" != "x0" && pkg_failed=yes
> +else
> +  pkg_failed=yes
> +fi
> + else
> +    pkg_failed=untried
> +fi
> +if test -n "$ZSTD_LIBS"; then
> +    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
> + elif test -n "$PKG_CONFIG"; then
> +    if test -n "$PKG_CONFIG" && \
> +    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
> +  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
> +  ac_status=$?
> +  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; then
> +  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
> +		      test "x$?" != "x0" && pkg_failed=yes
> +else
> +  pkg_failed=yes
> +fi
> + else
> +    pkg_failed=untried
> +fi
> +
> +if test $pkg_failed = no; then
> +  pkg_save_LDFLAGS="$LDFLAGS"
> +  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
> +  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> +/* end confdefs.h.  */
> +
> +int
> +main ()
> +{
> +
> +  ;
> +  return 0;
> +}
> +_ACEOF
> +if ac_fn_c_try_link "$LINENO"; then :
> +
> +else
> +  pkg_failed=yes
> +fi
> +rm -f core conftest.err conftest.$ac_objext \
> +    conftest$ac_exeext conftest.$ac_ext
> +  LDFLAGS=$pkg_save_LDFLAGS
> +fi
> +
> +
> +
> +if test $pkg_failed = yes; then
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +
> +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
> +        _pkg_short_errors_supported=yes
> +else
> +        _pkg_short_errors_supported=no
> +fi
> +        if test $_pkg_short_errors_supported = yes; then
> +	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
> +        else
> +	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
> +        fi
> +	# Put the nasty error message in config.log where it belongs
> +	echo "$ZSTD_PKG_ERRORS" >&5
> +
> +
> +    if test "$with_zstd" = yes; then
> +      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
> +    fi
> +
> +elif test $pkg_failed = untried; then
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +
> +    if test "$with_zstd" = yes; then
> +      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
> +    fi
> +
> +else
> +	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
> +	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
> +$as_echo "yes" >&6; }
> +
> +
> +$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
> +
> +
> +fi
> +fi
> +
> +
>  save_CFLAGS="$CFLAGS"
>  CFLAGS="$CFLAGS -Werror"
>  { $as_echo "$as_me:${as_lineno-$LINENO}: checking compiler support for hidden visibility" >&5
> diff --git a/bfd/configure.ac b/bfd/configure.ac
> index 28f3d1afce6..d1b2f76b31a 100644
> --- a/bfd/configure.ac
> +++ b/bfd/configure.ac
> @@ -230,9 +230,10 @@ AC_CHECK_DECLS([basename, ffs, stpcpy, asprintf, vasprintf, strnlen])
>  
>  BFD_BINARY_FOPEN
>  
> -# Link in zlib if we can.  This allows us to read compressed debug sections.
> +# Link in zlib/zstd if we can.  This allows us to read compressed debug sections.
>  # This is used only by compress.c.
>  AM_ZLIB
> +AM_ZSTD
>  
>  save_CFLAGS="$CFLAGS"
>  CFLAGS="$CFLAGS -Werror"
> diff --git a/bfd/elf.c b/bfd/elf.c
> index 16cea4f8aeb..e52fa458a5a 100644
> --- a/bfd/elf.c
> +++ b/bfd/elf.c
> @@ -1260,6 +1260,18 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
>  		 abfd, name);
>  	      return false;
>  	    }
> +#ifndef HAVE_ZSTD
> +	  if (newsect->compress_status == DECOMPRESS_SECTION_ZSTD)
> +	    {
> +	      _bfd_error_handler
> +		  /* xgettext:c-format */
> +		  (_ ("%pB: section %s is compressed with zstd, but BFD "
> +		      "is not built with zstd support"),
> +		   abfd, name);
> +	      newsect->compress_status = COMPRESS_SECTION_NONE;
> +	      return false;
> +	    }
> +#endif
>  	}
>  
>        if (abfd->is_linker_input)
> diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
> index feaba84bf2e..ca600bb5ddf 100644
> --- a/bfd/elfxx-target.h
> +++ b/bfd/elfxx-target.h
> @@ -989,7 +989,8 @@ const bfd_target TARGET_BIG_SYM =
>    /* object_flags: mask of all file flags */
>    (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS
>     | DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS
> -   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON),
> +   | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD | BFD_CONVERT_ELF_COMMON
> +   | BFD_USE_ELF_STT_COMMON),
>  
>    /* section_flags: mask of all section flags */
>    (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY
> @@ -1093,7 +1094,8 @@ const bfd_target TARGET_LITTLE_SYM =
>    /* object_flags: mask of all file flags */
>    (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS
>     | DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS
> -   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON),
> +   | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD | BFD_CONVERT_ELF_COMMON
> +   | BFD_USE_ELF_STT_COMMON),
>  
>    /* section_flags: mask of all section flags */
>    (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY
> diff --git a/bfd/section.c b/bfd/section.c
> index c7a02d729f2..614570e976e 100644
> --- a/bfd/section.c
> +++ b/bfd/section.c
> @@ -392,7 +392,8 @@ CODE_FRAGMENT
>  .  unsigned int compress_status : 2;
>  .#define COMPRESS_SECTION_NONE    0
>  .#define COMPRESS_SECTION_DONE    1
> -.#define DECOMPRESS_SECTION_SIZED 2
> +.#define DECOMPRESS_SECTION_ZLIB  2
> +.#define DECOMPRESS_SECTION_ZSTD  3
>  .
>  .  {* The following flags are used by the ELF linker. *}
>  .
> diff --git a/binutils/Makefile.in b/binutils/Makefile.in
> index 78d32b350e3..6de4e239408 100644
> --- a/binutils/Makefile.in
> +++ b/binutils/Makefile.in
> @@ -156,7 +156,8 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
>  	$(top_srcdir)/../config/plugins.m4 \
>  	$(top_srcdir)/../config/po.m4 \
>  	$(top_srcdir)/../config/progtest.m4 \
> -	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
> +	$(top_srcdir)/../config/zlib.m4 \
> +	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
>  	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
>  	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
>  	$(top_srcdir)/../bfd/version.m4 \
> @@ -575,6 +576,8 @@ WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
>  XGETTEXT = @XGETTEXT@
>  YACC = `if [ -f ../bison/bison ]; then echo ../bison/bison -y -L$(srcdir)/../bison/; else echo @YACC@; fi`
>  YFLAGS = -d
> +ZSTD_CFLAGS = @ZSTD_CFLAGS@
> +ZSTD_LIBS = @ZSTD_LIBS@
>  abs_builddir = @abs_builddir@
>  abs_srcdir = @abs_srcdir@
>  abs_top_builddir = @abs_top_builddir@
> diff --git a/binutils/aclocal.m4 b/binutils/aclocal.m4
> index a877fa7f873..28271f56279 100644
> --- a/binutils/aclocal.m4
> +++ b/binutils/aclocal.m4
> @@ -1205,6 +1205,7 @@ m4_include([../config/plugins.m4])
>  m4_include([../config/po.m4])
>  m4_include([../config/progtest.m4])
>  m4_include([../config/zlib.m4])
> +m4_include([../config/zstd.m4])
>  m4_include([../libtool.m4])
>  m4_include([../ltoptions.m4])
>  m4_include([../ltsugar.m4])
> diff --git a/binutils/config.in b/binutils/config.in
> index c5fb919aa95..bee8c07e2f7 100644
> --- a/binutils/config.in
> +++ b/binutils/config.in
> @@ -157,6 +157,9 @@
>  /* Define to 1 if you have the <windows.h> header file. */
>  #undef HAVE_WINDOWS_H
>  
> +/* Define to 1 if zstd is enabled. */
> +#undef HAVE_ZSTD
> +
>  /* Define as const if the declaration of iconv() needs const. */
>  #undef ICONV_CONST
>  
> diff --git a/binutils/configure b/binutils/configure
> index 1c518227f57..54d0f184da1 100755
> --- a/binutils/configure
> +++ b/binutils/configure
> @@ -650,6 +650,8 @@ LTLIBICONV
>  LIBICONV
>  MSGPACK_LIBS
>  MSGPACK_CFLAGS
> +ZSTD_LIBS
> +ZSTD_CFLAGS
>  zlibinc
>  zlibdir
>  DEMANGLER_NAME
> @@ -832,6 +834,7 @@ enable_build_warnings
>  enable_nls
>  enable_maintainer_mode
>  with_system_zlib
> +with_zstd
>  with_msgpack
>  enable_rpath
>  with_libiconv_prefix
> @@ -853,6 +856,8 @@ DEBUGINFOD_CFLAGS
>  DEBUGINFOD_LIBS
>  YACC
>  YFLAGS
> +ZSTD_CFLAGS
> +ZSTD_LIBS
>  MSGPACK_CFLAGS
>  MSGPACK_LIBS'
>  
> @@ -1517,6 +1522,8 @@ Optional Packages:
>    --with-debuginfod       Enable debuginfo lookups with debuginfod
>                            (auto/yes/no)
>    --with-system-zlib      use installed libz
> +  --with-zstd             support zstd compressed debug sections
> +                          (default=auto)
>    --with-msgpack          Enable msgpack support (auto/yes/no)
>    --with-gnu-ld           assume the C compiler uses GNU ld default=no
>    --with-libiconv-prefix[=DIR]  search for libiconv in DIR/include and DIR/lib
> @@ -1547,6 +1554,8 @@ Some influential environment variables:
>    YFLAGS      The list of arguments that will be passed by default to $YACC.
>                This script will default YFLAGS to the empty string to avoid a
>                default value of `-d' given by some make applications.
> +  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
> +  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
>    MSGPACK_CFLAGS
>                C compiler flags for MSGPACK, overriding pkg-config
>    MSGPACK_LIBS
> @@ -10804,7 +10813,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 10807 "configure"
> +#line 10816 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -10910,7 +10919,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 10913 "configure"
> +#line 10922 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -13468,7 +13477,7 @@ cat >>confdefs.h <<_ACEOF
>  _ACEOF
>  
>  
> -# Link in zlib if we can.  This allows us to read compressed debug
> +# Link in zlib/zstd if we can.  This allows us to read compressed debug
>  # sections.  This is used only by readelf.c (objdump uses bfd for
>  # reading compressed sections).
>  
> @@ -13490,6 +13499,126 @@ fi
>  
>  
>  
> +# Check whether --with-zstd was given.
> +if test "${with_zstd+set}" = set; then :
> +  withval=$with_zstd;
> +else
> +  with_zstd=auto
> +fi
> +
> +
> +if test "$with_zstd" != no; then
> +
> +pkg_failed=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
> +$as_echo_n "checking for libzstd... " >&6; }
> +
> +if test -n "$ZSTD_CFLAGS"; then
> +    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
> + elif test -n "$PKG_CONFIG"; then
> +    if test -n "$PKG_CONFIG" && \
> +    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
> +  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
> +  ac_status=$?
> +  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; then
> +  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
> +		      test "x$?" != "x0" && pkg_failed=yes
> +else
> +  pkg_failed=yes
> +fi
> + else
> +    pkg_failed=untried
> +fi
> +if test -n "$ZSTD_LIBS"; then
> +    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
> + elif test -n "$PKG_CONFIG"; then
> +    if test -n "$PKG_CONFIG" && \
> +    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
> +  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
> +  ac_status=$?
> +  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; then
> +  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
> +		      test "x$?" != "x0" && pkg_failed=yes
> +else
> +  pkg_failed=yes
> +fi
> + else
> +    pkg_failed=untried
> +fi
> +
> +if test $pkg_failed = no; then
> +  pkg_save_LDFLAGS="$LDFLAGS"
> +  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
> +  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> +/* end confdefs.h.  */
> +
> +int
> +main ()
> +{
> +
> +  ;
> +  return 0;
> +}
> +_ACEOF
> +if ac_fn_c_try_link "$LINENO"; then :
> +
> +else
> +  pkg_failed=yes
> +fi
> +rm -f core conftest.err conftest.$ac_objext \
> +    conftest$ac_exeext conftest.$ac_ext
> +  LDFLAGS=$pkg_save_LDFLAGS
> +fi
> +
> +
> +
> +if test $pkg_failed = yes; then
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +
> +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
> +        _pkg_short_errors_supported=yes
> +else
> +        _pkg_short_errors_supported=no
> +fi
> +        if test $_pkg_short_errors_supported = yes; then
> +	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
> +        else
> +	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
> +        fi
> +	# Put the nasty error message in config.log where it belongs
> +	echo "$ZSTD_PKG_ERRORS" >&5
> +
> +
> +    if test "$with_zstd" = yes; then
> +      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
> +    fi
> +
> +elif test $pkg_failed = untried; then
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +
> +    if test "$with_zstd" = yes; then
> +      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
> +    fi
> +
> +else
> +	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
> +	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
> +$as_echo "yes" >&6; }
> +
> +
> +$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
> +
> +
> +fi
> +fi
> +
> +
> +
>  case "${host}" in
>  *-*-msdos* | *-*-go32* | *-*-mingw32* | *-*-cygwin* | *-*-windows*)
>  
> diff --git a/binutils/configure.ac b/binutils/configure.ac
> index ec002d3f88f..c152b7f6733 100644
> --- a/binutils/configure.ac
> +++ b/binutils/configure.ac
> @@ -265,10 +265,11 @@ fi
>  
>  AC_CHECK_DECLS([asprintf, environ, getc_unlocked, stpcpy, strnlen])
>  
> -# Link in zlib if we can.  This allows us to read compressed debug
> +# Link in zlib/zstd if we can.  This allows us to read compressed debug
>  # sections.  This is used only by readelf.c (objdump uses bfd for
>  # reading compressed sections).
>  AM_ZLIB
> +AM_ZSTD
>  
>  BFD_BINARY_FOPEN
>  
> diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
> index 1499db5728c..34a4164eb94 100644
> --- a/binutils/doc/binutils.texi
> +++ b/binutils/doc/binutils.texi
> @@ -2159,21 +2159,23 @@ ELF ABI.  Note - if compression would actually make a section
>  @itemx --compress-debug-sections=zlib
>  @itemx --compress-debug-sections=zlib-gnu
>  @itemx --compress-debug-sections=zlib-gabi
> +@itemx --compress-debug-sections=zstd
>  For ELF files, these options control how DWARF debug sections are
>  compressed.  @option{--compress-debug-sections=none} is equivalent
>  to @option{--decompress-debug-sections}.
>  @option{--compress-debug-sections=zlib} and
>  @option{--compress-debug-sections=zlib-gabi} are equivalent to
>  @option{--compress-debug-sections}.
> -@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug
> -sections using zlib.  The debug sections are renamed to begin with
> -@samp{.zdebug} instead of @samp{.debug}.  Note - if compression would
> -actually make a section @emph{larger}, then it is not compressed nor
> -renamed.
> +@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug sections
> +using the obsoleted zlib-gnu format.  The debug sections are renamed to begin
> +with @samp{.zdebug}.
> +@option{--compress-debug-sections=zstd} compresses DWARF debug
> +sections using zstd.  Note - if compression would actually make a section
> +@emph{larger}, then it is not compressed nor renamed.
>  
>  @item --decompress-debug-sections
> -Decompress DWARF debug sections using zlib.  The original section
> -names of the compressed sections are restored.
> +Decompress DWARF debug sections.  For a @samp{.zdebug} section, the original
> +name is restored.
>  
>  @item --elf-stt-common=yes
>  @itemx --elf-stt-common=no
> diff --git a/binutils/objcopy.c b/binutils/objcopy.c
> index 43261756a42..fc668f00bbc 100644
> --- a/binutils/objcopy.c
> +++ b/binutils/objcopy.c
> @@ -232,7 +232,8 @@ static enum
>    compress_zlib = compress | 1 << 1,
>    compress_gnu_zlib = compress | 1 << 2,
>    compress_gabi_zlib = compress | 1 << 3,
> -  decompress = 1 << 4
> +  compress_zstd = compress | 1 << 4,
> +  decompress = 1 << 5
>  } do_debug_sections = nothing;
>  
>  /* Whether to generate ELF common symbols with the STT_COMMON type.  */
> @@ -678,8 +679,8 @@ copy_usage (FILE *stream, int exit_status)
>                                     <commit>\n\
>       --subsystem <name>[:<version>]\n\
>                                     Set PE subsystem to <name> [& <version>]\n\
> -     --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
> -                                   Compress DWARF debug sections using zlib\n\
> +     --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
> +				   Compress DWARF debug sections\n\
>       --decompress-debug-sections   Decompress DWARF debug sections using zlib\n\
>       --elf-stt-common=[yes|no]     Generate ELF common symbols with STT_COMMON\n\
>                                       type\n\
> @@ -2659,7 +2660,8 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
>        if ((do_debug_sections & compress) != 0
>  	  && do_debug_sections != compress)
>  	{
> -	  non_fatal (_("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi] is unsupported on `%s'"),
> +	  non_fatal (_ ("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi|"
> +			"zstd] is unsupported on `%s'"),
>  		     bfd_get_archive_filename (ibfd));
>  	  return false;
>  	}
> @@ -3807,6 +3809,13 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
>        if (do_debug_sections != compress_gnu_zlib)
>  	ibfd->flags |= BFD_COMPRESS_GABI;
>        break;
> +    case compress_zstd:
> +      ibfd->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD;
> +#ifndef HAVE_ZSTD
> +      fatal (_ ("--compress-debug-sections=zstd: binutils is not built with "
> +		"zstd support"));
> +#endif
> +      break;
>      case decompress:
>        ibfd->flags |= BFD_DECOMPRESS;
>        break;
> @@ -5469,6 +5478,8 @@ copy_main (int argc, char *argv[])
>  		do_debug_sections = compress_gnu_zlib;
>  	      else if (strcasecmp (optarg, "zlib-gabi") == 0)
>  		do_debug_sections = compress_gabi_zlib;
> +	      else if (strcasecmp (optarg, "zstd") == 0)
> +		do_debug_sections = compress_zstd;
>  	      else
>  		fatal (_("unrecognized --compress-debug-sections type `%s'"),
>  		       optarg);
> diff --git a/binutils/testsuite/binutils-all/compress.exp b/binutils/testsuite/binutils-all/compress.exp
> index c88da74a987..4e74c824664 100644
> --- a/binutils/testsuite/binutils-all/compress.exp
> +++ b/binutils/testsuite/binutils-all/compress.exp
> @@ -576,6 +576,50 @@ if { [regexp_diff objdump.out $srcdir/$subdir/dw2-3gabi.W] } then {
>      pass "$testname"
>  }
>  
> +if { [binutils_assemble_flags $srcdir/$subdir/dw2-1.S ${compressedfile}zstd.o --compress-debug-sections=zstd] } then {
> +    set testname "objcopy compress debug sections with zstd"
> +    set got [binutils_run $OBJCOPY "--compress-debug-sections=zstd ${testfile}.o ${copyfile}zstd.o"]
> +    if ![string match "" $got] then {
> +	fail "objcopy ($testname)"
> +	return
> +    }
> +    send_log "cmp ${compressedfile}zstd.o ${copyfile}zstd.o\n"
> +    verbose "cmp ${compressedfile}zstd.o ${copyfile}zstd.o"
> +    set src1 ${compressedfile}zstd.o
> +    set src2 ${copyfile}zstd.o
> +    set status [remote_exec build cmp "${src1} ${src2}"]
> +    set exec_output [lindex $status 1]
> +    set exec_output [prune_warnings $exec_output]
> +    if ![string match "" $exec_output] then {
> +	send_log "$exec_output\n"
> +	verbose "$exec_output" 1
> +	fail "objcopy ($testname)"
> +    } else {
> +	pass "objcopy ($testname)"
> +    }
> +
> +    set testname "objcopy decompress compressed debug sections with zstd"
> +    set got [binutils_run $OBJCOPY "--decompress-debug-sections ${compressedfile}zstd.o ${copyfile}zstd.o"]
> +    if ![string match "" $got] then {
> +	fail "objcopy ($testname)"
> +	return
> +    }
> +    send_log "cmp ${testfile}.o ${copyfile}zstd.o\n"
> +    verbose "cmp ${testfile}.o ${copyfile}zstd.o"
> +    set src1 ${testfile}.o
> +    set src2 ${copyfile}zstd.o
> +    set status [remote_exec build cmp "${src1} ${src2}"]
> +    set exec_output [lindex $status 1]
> +    set exec_output [prune_warnings $exec_output]
> +    if ![string match "" $exec_output] then {
> +	send_log "$exec_output\n"
> +	verbose "$exec_output" 1
> +	fail "objcopy ($testname)"
> +    } else {
> +	pass "objcopy ($testname)"
> +    }
> +}
> +
>  proc convert_test { testname  as_flags  objcop_flags } {
>      global srcdir
>      global subdir
> diff --git a/config/zstd.m4 b/config/zstd.m4
> new file mode 100644
> index 00000000000..93ae17b89d3
> --- /dev/null
> +++ b/config/zstd.m4
> @@ -0,0 +1,24 @@
> +dnl Copyright (C) 2022 Free Software Foundation, Inc.
> +dnl This file is free software, distributed under the terms of the GNU
> +dnl General Public License.  As a special exception to the GNU General
> +dnl Public License, this file may be distributed as part of a program
> +dnl that contains a configuration script generated by Autoconf, under
> +dnl the same distribution terms as the rest of that program.
> +
> +dnl Enable features using the zstd library.
> +AC_DEFUN([AM_ZSTD],
> +[
> +AC_ARG_WITH(zstd,
> +  [AS_HELP_STRING([--with-zstd], [support zstd compressed debug sections (default=auto)])],
> +  [], [with_zstd=auto])
> +
> +if test "$with_zstd" != no; then
> +  PKG_CHECK_MODULES(ZSTD, [libzstd], [
> +    AC_DEFINE(HAVE_ZSTD, 1, [Define to 1 if zstd is enabled.])
> +  ], [
> +    if test "$with_zstd" = yes; then
> +      AC_MSG_ERROR([--with-zstd was given, but pkgconfig/libzstd.pc is not found])
> +    fi
> +  ])
> +fi
> +])
> diff --git a/configure b/configure
> index d75f47a1e95..f14e0efd675 100755
> --- a/configure
> +++ b/configure
> @@ -785,6 +785,7 @@ ac_user_opts='
>  enable_option_checking
>  with_build_libsubdir
>  with_system_zlib
> +with_zstd
>  enable_as_accelerator_for
>  enable_offload_targets
>  enable_gold
> @@ -1567,6 +1568,8 @@ Optional Packages:
>    --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
>    --with-build-libsubdir=DIR  Directory where to find libraries for build system
>    --with-system-zlib      use installed libz
> +  --with-zstd             Support zstd compressed debug sections
> +                          (default=auto)
>    --with-mpc=PATH         specify prefix directory for installed MPC package.
>                            Equivalent to --with-mpc-include=PATH/include plus
>                            --with-mpc-lib=PATH/lib
> @@ -2925,6 +2928,13 @@ if test x$with_system_zlib = xyes ; then
>    noconfigdirs="$noconfigdirs zlib"
>  fi
>  
> +
> +# Check whether --with-zstd was given.
> +if test "${with_zstd+set}" = set; then :
> +  withval=$with_zstd;
> +fi
> +
> +
>  # Don't compile the bundled readline/libreadline.a if --with-system-readline
>  # is provided.
>  if test x$with_system_readline = xyes ; then
> diff --git a/configure.ac b/configure.ac
> index ae18d436aca..0152c69292e 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -246,6 +246,9 @@ if test x$with_system_zlib = xyes ; then
>    noconfigdirs="$noconfigdirs zlib"
>  fi
>  
> +AC_ARG_WITH(zstd,
> +[AS_HELP_STRING([--with-zstd], [Support zstd compressed debug sections (default=auto)])])
> +
>  # Don't compile the bundled readline/libreadline.a if --with-system-readline
>  # is provided.
>  if test x$with_system_readline = xyes ; then
> diff --git a/gas/Makefile.am b/gas/Makefile.am
> index bd597398671..5f0f24abf8d 100644
> --- a/gas/Makefile.am
> +++ b/gas/Makefile.am
> @@ -42,7 +42,7 @@ am__skipyacc =
>  
>  WARN_CFLAGS = @WARN_CFLAGS@ @WARN_WRITE_STRINGS@
>  NO_WERROR = @NO_WERROR@
> -AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
> +AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
>  
>  TARG_CPU = @target_cpu_type@
>  TARG_CPU_C = $(srcdir)/config/tc-@target_cpu_type@.c
> @@ -407,7 +407,7 @@ STAGESTUFF = *.@OBJEXT@ $(noinst_PROGRAMS)
>  
>  as_new_SOURCES = $(GAS_CFILES)
>  as_new_LDADD = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
> -	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB)
> +	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB) $(ZSTD_LIBS)
>  as_new_DEPENDENCIES = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
>  	$(extra_objects) $(GASLIBS) $(LIBINTL_DEP)
>  EXTRA_as_new_SOURCES = $(CFILES) $(HFILES) $(TARGET_CPU_CFILES) \
> diff --git a/gas/Makefile.in b/gas/Makefile.in
> index c57d78f82c4..5a4dd702252 100644
> --- a/gas/Makefile.in
> +++ b/gas/Makefile.in
> @@ -140,10 +140,12 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
>  	$(top_srcdir)/../config/lead-dot.m4 \
>  	$(top_srcdir)/../config/nls.m4 \
>  	$(top_srcdir)/../config/override.m4 \
> +	$(top_srcdir)/../config/pkg.m4 \
>  	$(top_srcdir)/../config/plugins.m4 \
>  	$(top_srcdir)/../config/po.m4 \
>  	$(top_srcdir)/../config/progtest.m4 \
> -	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
> +	$(top_srcdir)/../config/zlib.m4 \
> +	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
>  	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
>  	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
>  	$(top_srcdir)/acinclude.m4 $(top_srcdir)/../bfd/version.m4 \
> @@ -429,6 +431,9 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
>  PACKAGE_URL = @PACKAGE_URL@
>  PACKAGE_VERSION = @PACKAGE_VERSION@
>  PATH_SEPARATOR = @PATH_SEPARATOR@
> +PKG_CONFIG = @PKG_CONFIG@
> +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
> +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
>  POSUB = @POSUB@
>  RANLIB = @RANLIB@
>  SED = @SED@
> @@ -443,6 +448,8 @@ WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
>  XGETTEXT = @XGETTEXT@
>  YACC = `if [ -f ../bison/bison ] ; then echo ../bison/bison -y -L../bison/bison ; else echo @YACC@ ; fi`
>  YFLAGS = @YFLAGS@
> +ZSTD_CFLAGS = @ZSTD_CFLAGS@
> +ZSTD_LIBS = @ZSTD_LIBS@
>  abs_builddir = @abs_builddir@
>  abs_srcdir = @abs_srcdir@
>  abs_top_builddir = @abs_top_builddir@
> @@ -524,7 +531,7 @@ ZLIBINC = @zlibinc@
>  # maintainer mode is disabled.  Avoid this.
>  am__skiplex = 
>  am__skipyacc = 
> -AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
> +AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
>  TARG_CPU = @target_cpu_type@
>  TARG_CPU_C = $(srcdir)/config/tc-@target_cpu_type@.c
>  TARG_CPU_O = config/tc-@target_cpu_type@.@OBJEXT@
> @@ -874,7 +881,7 @@ GASLIBS = @OPCODES_LIB@ ../bfd/libbfd.la ../libiberty/libiberty.a
>  STAGESTUFF = *.@OBJEXT@ $(noinst_PROGRAMS)
>  as_new_SOURCES = $(GAS_CFILES)
>  as_new_LDADD = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
> -	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB)
> +	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB) $(ZSTD_LIBS)
>  
>  as_new_DEPENDENCIES = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
>  	$(extra_objects) $(GASLIBS) $(LIBINTL_DEP)
> diff --git a/gas/aclocal.m4 b/gas/aclocal.m4
> index 70183124da7..722030c776f 100644
> --- a/gas/aclocal.m4
> +++ b/gas/aclocal.m4
> @@ -1196,10 +1196,12 @@ m4_include([../config/lcmessage.m4])
>  m4_include([../config/lead-dot.m4])
>  m4_include([../config/nls.m4])
>  m4_include([../config/override.m4])
> +m4_include([../config/pkg.m4])
>  m4_include([../config/plugins.m4])
>  m4_include([../config/po.m4])
>  m4_include([../config/progtest.m4])
>  m4_include([../config/zlib.m4])
> +m4_include([../config/zstd.m4])
>  m4_include([../libtool.m4])
>  m4_include([../ltoptions.m4])
>  m4_include([../ltsugar.m4])
> diff --git a/gas/as.c b/gas/as.c
> index 6268779cf90..35ad6b3ab3b 100644
> --- a/gas/as.c
> +++ b/gas/as.c
> @@ -252,14 +252,14 @@ Options:\n\
>    --alternate             initially turn on alternate macro syntax\n"));
>  #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
>    fprintf (stream, _("\
> -  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
> +  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
>                            compress DWARF debug sections using zlib [default]\n"));
>    fprintf (stream, _("\
>    --nocompress-debug-sections\n\
>                            don't compress DWARF debug sections\n"));
>  #else
>    fprintf (stream, _("\
> -  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
> +  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
>                            compress DWARF debug sections using zlib\n"));
>    fprintf (stream, _("\
>    --nocompress-debug-sections\n\
> @@ -736,6 +736,15 @@ This program has absolutely no warranty.\n"));
>  		flag_compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
>  	      else if (strcasecmp (optarg, "zlib-gabi") == 0)
>  		flag_compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
> +	      else if (strcasecmp (optarg, "zstd") == 0)
> +		{
> +#ifdef HAVE_ZSTD
> +		  flag_compress_debug = COMPRESS_DEBUG_ZSTD;
> +#else
> +		  as_fatal (_ ("--compress-debug-sections=zstd: gas is not "
> +			       "built with zstd support"));
> +#endif
> +		}
>  	      else
>  		as_fatal (_("Invalid --compress-debug-sections option: `%s'"),
>  			  optarg);
> diff --git a/gas/compress-debug.c b/gas/compress-debug.c
> index c80dbeec4e7..3cd175f6e57 100644
> --- a/gas/compress-debug.c
> +++ b/gas/compress-debug.c
> @@ -21,14 +21,23 @@
>  #include "config.h"
>  #include <stdio.h>
>  #include <zlib.h>
> +#if HAVE_ZSTD
> +#include <zstd.h>
> +#endif
>  #include "ansidecl.h"
>  #include "compress-debug.h"
>  
>  /* Initialize the compression engine.  */
>  
> -struct z_stream_s *
> -compress_init (void)
> +void *
> +compress_init (bool use_zstd)
>  {
> +  if (use_zstd) {
> +#if HAVE_ZSTD
> +    return ZSTD_createCCtx ();
> +#endif
> +  }
> +
>    static struct z_stream_s strm;
>  
>    strm.zalloc = NULL;
> @@ -42,22 +51,37 @@ compress_init (void)
>     from the engine goes into the current frag on the obstack.  */
>  
>  int
> -compress_data (struct z_stream_s *strm, const char **next_in,
> -	       int *avail_in, char **next_out, int *avail_out)
> +compress_data (bool use_zstd, void *ctx, const char **next_in, int *avail_in,
> +	       char **next_out, int *avail_out)
>  {
> -  int out_size = 0;
> -  int x;
> +  if (use_zstd)
> +    {
> +#if HAVE_ZSTD
> +      ZSTD_outBuffer ob = { *next_out, *avail_out, 0 };
> +      ZSTD_inBuffer ib = { *next_in, *avail_in, 0 };
> +      size_t ret = ZSTD_compressStream2 (ctx, &ob, &ib, ZSTD_e_continue);
> +      *next_in += ib.pos;
> +      *avail_in -= ib.pos;
> +      *next_out += ob.pos;
> +      *avail_out -= ob.pos;
> +      if (ZSTD_isError (ret))
> +	return -1;
> +      return (int)ob.pos;
> +#endif
> +    }
> +
> +  struct z_stream_s *strm = ctx;
>  
>    strm->next_in = (Bytef *) (*next_in);
>    strm->avail_in = *avail_in;
>    strm->next_out = (Bytef *) (*next_out);
>    strm->avail_out = *avail_out;
>  
> -  x = deflate (strm, Z_NO_FLUSH);
> +  int x = deflate (strm, Z_NO_FLUSH);
>    if (x != Z_OK)
>      return -1;
>  
> -  out_size = *avail_out - strm->avail_out;
> +  int out_size = *avail_out - strm->avail_out;
>    *next_in = (char *) (strm->next_in);
>    *avail_in = strm->avail_in;
>    *next_out = (char *) (strm->next_out);
> @@ -71,10 +95,28 @@ compress_data (struct z_stream_s *strm, const char **next_in,
>     needed.  */
>  
>  int
> -compress_finish (struct z_stream_s *strm, char **next_out,
> +compress_finish (bool use_zstd, void *ctx, char **next_out,
>  		 int *avail_out, int *out_size)
>  {
> +  if (use_zstd)
> +    {
> +#if HAVE_ZSTD
> +      ZSTD_outBuffer ob = { *next_out, *avail_out, 0 };
> +      ZSTD_inBuffer ib = { 0 };
> +      size_t ret = ZSTD_compressStream2 (ctx, &ob, &ib, ZSTD_e_end);
> +      *out_size = ob.pos;
> +      *next_out += ob.pos;
> +      *avail_out -= ob.pos;
> +      if (ZSTD_isError (ret))
> +	return -1;
> +      if (ret == 0)
> +	ZSTD_freeCCtx (ctx);
> +      return ret ? 1 : 0;
> +#endif
> +    }
> +
>    int x;
> +  struct z_stream_s *strm = ctx;
>  
>    strm->avail_in = 0;
>    strm->next_out = (Bytef *) (*next_out);
> diff --git a/gas/compress-debug.h b/gas/compress-debug.h
> index 0183e269fef..87de0f8444e 100644
> --- a/gas/compress-debug.h
> +++ b/gas/compress-debug.h
> @@ -21,19 +21,19 @@
>  #ifndef COMPRESS_DEBUG_H
>  #define COMPRESS_DEBUG_H
>  
> +#include <stdbool.h>
> +
>  struct z_stream_s;
>  
>  /* Initialize the compression engine.  */
> -extern struct z_stream_s *
> -compress_init (void);
> +extern void *compress_init (bool);
>  
>  /* Stream the contents of a frag to the compression engine.  Output
>     from the engine goes into the current frag on the obstack.  */
> -extern int
> -compress_data (struct z_stream_s *, const char **, int *, char **, int *);
> +extern int compress_data (bool, void *, const char **, int *, char **, int *);
>  
>  /* Finish the compression and consume the remaining compressed output.  */
>  extern int
> -compress_finish (struct z_stream_s *, char **, int *, int *);
> +compress_finish (bool, void *, char **, int *, int *);
>  
>  #endif /* COMPRESS_DEBUG_H */
> diff --git a/gas/config.in b/gas/config.in
> index e243fd277ee..0d1668a3eac 100644
> --- a/gas/config.in
> +++ b/gas/config.in
> @@ -134,6 +134,9 @@
>  /* Define to 1 if you have the <windows.h> header file. */
>  #undef HAVE_WINDOWS_H
>  
> +/* Define to 1 if zstd is enabled. */
> +#undef HAVE_ZSTD
> +
>  /* Using i386 COFF? */
>  #undef I386COFF
>  
> diff --git a/gas/configure b/gas/configure
> index d0449a1d7ab..1833adffaa8 100755
> --- a/gas/configure
> +++ b/gas/configure
> @@ -633,6 +633,11 @@ ac_subst_vars='am__EXEEXT_FALSE
>  am__EXEEXT_TRUE
>  LTLIBOBJS
>  LIBOBJS
> +ZSTD_LIBS
> +ZSTD_CFLAGS
> +PKG_CONFIG_LIBDIR
> +PKG_CONFIG_PATH
> +PKG_CONFIG
>  zlibinc
>  zlibdir
>  LIBM
> @@ -817,6 +822,7 @@ with_cpu
>  enable_nls
>  enable_maintainer_mode
>  with_system_zlib
> +with_zstd
>  '
>        ac_precious_vars='build_alias
>  host_alias
> @@ -828,7 +834,12 @@ LIBS
>  CPPFLAGS
>  CPP
>  YACC
> -YFLAGS'
> +YFLAGS
> +PKG_CONFIG
> +PKG_CONFIG_PATH
> +PKG_CONFIG_LIBDIR
> +ZSTD_CFLAGS
> +ZSTD_LIBS'
>  
>  
>  # Initialize some variables set by options.
> @@ -1493,6 +1504,8 @@ Optional Packages:
>    --with-cpu=CPU          default cpu variant is CPU (currently only supported
>                            on ARC)
>    --with-system-zlib      use installed libz
> +  --with-zstd             support zstd compressed debug sections
> +                          (default=auto)
>  
>  Some influential environment variables:
>    CC          C compiler command
> @@ -1509,6 +1522,13 @@ Some influential environment variables:
>    YFLAGS      The list of arguments that will be passed by default to $YACC.
>                This script will default YFLAGS to the empty string to avoid a
>                default value of `-d' given by some make applications.
> +  PKG_CONFIG  path to pkg-config utility
> +  PKG_CONFIG_PATH
> +              directories to add to pkg-config's search path
> +  PKG_CONFIG_LIBDIR
> +              path overriding pkg-config's built-in search path
> +  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
> +  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
>  
>  Use these variables to override the choices made by `configure' or to help
>  it to find libraries and programs with nonstandard names/locations.
> @@ -10702,7 +10722,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 10705 "configure"
> +#line 10725 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -10808,7 +10828,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 10811 "configure"
> +#line 10831 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -13945,7 +13965,7 @@ $as_echo "#define USE_BINARY_FOPEN 1" >>confdefs.h
>   ;;
>  esac
>  
> -# Link in zlib if we can.  This allows us to write compressed debug sections.
> +# Link in zlib/zstd if we can.  This allows us to write compressed debug sections.
>  
>    # Use the system's zlib library.
>    zlibdir="-L\$(top_builddir)/../zlib"
> @@ -13964,6 +13984,246 @@ fi
>  
>  
>  
> +
> +
> +
> +
> +
> +
> +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
> +	if test -n "$ac_tool_prefix"; then
> +  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
> +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
> +$as_echo_n "checking for $ac_word... " >&6; }
> +if ${ac_cv_path_PKG_CONFIG+:} false; then :
> +  $as_echo_n "(cached) " >&6
> +else
> +  case $PKG_CONFIG in
> +  [\\/]* | ?:[\\/]*)
> +  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
> +  ;;
> +  *)
> +  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
> +for as_dir in $PATH
> +do
> +  IFS=$as_save_IFS
> +  test -z "$as_dir" && as_dir=.
> +    for ac_exec_ext in '' $ac_executable_extensions; do
> +  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
> +    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
> +    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
> +    break 2
> +  fi
> +done
> +  done
> +IFS=$as_save_IFS
> +
> +  ;;
> +esac
> +fi
> +PKG_CONFIG=$ac_cv_path_PKG_CONFIG
> +if test -n "$PKG_CONFIG"; then
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
> +$as_echo "$PKG_CONFIG" >&6; }
> +else
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +fi
> +
> +
> +fi
> +if test -z "$ac_cv_path_PKG_CONFIG"; then
> +  ac_pt_PKG_CONFIG=$PKG_CONFIG
> +  # Extract the first word of "pkg-config", so it can be a program name with args.
> +set dummy pkg-config; ac_word=$2
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
> +$as_echo_n "checking for $ac_word... " >&6; }
> +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
> +  $as_echo_n "(cached) " >&6
> +else
> +  case $ac_pt_PKG_CONFIG in
> +  [\\/]* | ?:[\\/]*)
> +  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
> +  ;;
> +  *)
> +  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
> +for as_dir in $PATH
> +do
> +  IFS=$as_save_IFS
> +  test -z "$as_dir" && as_dir=.
> +    for ac_exec_ext in '' $ac_executable_extensions; do
> +  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
> +    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
> +    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
> +    break 2
> +  fi
> +done
> +  done
> +IFS=$as_save_IFS
> +
> +  ;;
> +esac
> +fi
> +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
> +if test -n "$ac_pt_PKG_CONFIG"; then
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
> +$as_echo "$ac_pt_PKG_CONFIG" >&6; }
> +else
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +fi
> +
> +  if test "x$ac_pt_PKG_CONFIG" = x; then
> +    PKG_CONFIG=""
> +  else
> +    case $cross_compiling:$ac_tool_warned in
> +yes:)
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
> +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
> +ac_tool_warned=yes ;;
> +esac
> +    PKG_CONFIG=$ac_pt_PKG_CONFIG
> +  fi
> +else
> +  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
> +fi
> +
> +fi
> +if test -n "$PKG_CONFIG"; then
> +	_pkg_min_version=0.9.0
> +	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
> +$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
> +	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
> +		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
> +$as_echo "yes" >&6; }
> +	else
> +		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +		PKG_CONFIG=""
> +	fi
> +fi
> +
> +
> +# Check whether --with-zstd was given.
> +if test "${with_zstd+set}" = set; then :
> +  withval=$with_zstd;
> +else
> +  with_zstd=auto
> +fi
> +
> +
> +if test "$with_zstd" != no; then
> +
> +pkg_failed=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
> +$as_echo_n "checking for libzstd... " >&6; }
> +
> +if test -n "$ZSTD_CFLAGS"; then
> +    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
> + elif test -n "$PKG_CONFIG"; then
> +    if test -n "$PKG_CONFIG" && \
> +    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
> +  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
> +  ac_status=$?
> +  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; then
> +  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
> +		      test "x$?" != "x0" && pkg_failed=yes
> +else
> +  pkg_failed=yes
> +fi
> + else
> +    pkg_failed=untried
> +fi
> +if test -n "$ZSTD_LIBS"; then
> +    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
> + elif test -n "$PKG_CONFIG"; then
> +    if test -n "$PKG_CONFIG" && \
> +    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
> +  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
> +  ac_status=$?
> +  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; then
> +  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
> +		      test "x$?" != "x0" && pkg_failed=yes
> +else
> +  pkg_failed=yes
> +fi
> + else
> +    pkg_failed=untried
> +fi
> +
> +if test $pkg_failed = no; then
> +  pkg_save_LDFLAGS="$LDFLAGS"
> +  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
> +  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> +/* end confdefs.h.  */
> +
> +int
> +main ()
> +{
> +
> +  ;
> +  return 0;
> +}
> +_ACEOF
> +if ac_fn_c_try_link "$LINENO"; then :
> +
> +else
> +  pkg_failed=yes
> +fi
> +rm -f core conftest.err conftest.$ac_objext \
> +    conftest$ac_exeext conftest.$ac_ext
> +  LDFLAGS=$pkg_save_LDFLAGS
> +fi
> +
> +
> +
> +if test $pkg_failed = yes; then
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +
> +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
> +        _pkg_short_errors_supported=yes
> +else
> +        _pkg_short_errors_supported=no
> +fi
> +        if test $_pkg_short_errors_supported = yes; then
> +	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
> +        else
> +	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
> +        fi
> +	# Put the nasty error message in config.log where it belongs
> +	echo "$ZSTD_PKG_ERRORS" >&5
> +
> +
> +    if test "$with_zstd" = yes; then
> +      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
> +    fi
> +
> +elif test $pkg_failed = untried; then
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +
> +    if test "$with_zstd" = yes; then
> +      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
> +    fi
> +
> +else
> +	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
> +	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
> +$as_echo "yes" >&6; }
> +
> +
> +$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
> +
> +
> +fi
> +fi
> +
> +
>  # Support for VMS timestamps via cross compile
>  
>  if test "$ac_cv_header_time_h" = yes; then
> diff --git a/gas/configure.ac b/gas/configure.ac
> index 21795a82bdd..8750ea21381 100644
> --- a/gas/configure.ac
> +++ b/gas/configure.ac
> @@ -1004,8 +1004,9 @@ AC_CHECK_DECLS([asprintf, mempcpy, stpcpy])
>  
>  BFD_BINARY_FOPEN
>  
> -# Link in zlib if we can.  This allows us to write compressed debug sections.
> +# Link in zlib/zstd if we can.  This allows us to write compressed debug sections.
>  AM_ZLIB
> +AM_ZSTD
>  
>  # Support for VMS timestamps via cross compile
>  
> diff --git a/gas/doc/as.texi b/gas/doc/as.texi
> index e915893da86..01f49434021 100644
> --- a/gas/doc/as.texi
> +++ b/gas/doc/as.texi
> @@ -711,16 +711,19 @@ given section @emph{larger} then it is not compressed.
>  @itemx --compress-debug-sections=zlib
>  @itemx --compress-debug-sections=zlib-gnu
>  @itemx --compress-debug-sections=zlib-gabi
> +@itemx --compress-debug-sections=zstd
>  These options control how DWARF debug sections are compressed.
>  @option{--compress-debug-sections=none} is equivalent to
>  @option{--nocompress-debug-sections}.
>  @option{--compress-debug-sections=zlib} and
>  @option{--compress-debug-sections=zlib-gabi} are equivalent to
>  @option{--compress-debug-sections}.
> -@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug
> -sections using zlib.  The debug sections are renamed to begin with
> -@samp{.zdebug}.  Note if compression would make a given section
> -@emph{larger} then it is not compressed nor renamed.
> +@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug sections
> +using the obsoleted zlib-gnu format.  The debug sections are renamed to begin
> +with @samp{.zdebug}.
> +@option{--compress-debug-sections=zstd} compresses DWARF debug
> +sections using zstd.  Note - if compression would actually make a section
> +@emph{larger}, then it is not compressed nor renamed.
>  
>  @end ifset
>  
> diff --git a/gas/write.c b/gas/write.c
> index f76bbdb706e..0e49df7c03f 100644
> --- a/gas/write.c
> +++ b/gas/write.c
> @@ -1413,7 +1413,7 @@ write_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
>  }
>  
>  static int
> -compress_frag (struct z_stream_s *strm, const char *contents, int in_size,
> +compress_frag (bool use_zstd, void *ctx, const char *contents, int in_size,
>  	       fragS **last_newf, struct obstack *ob)
>  {
>    int out_size;
> @@ -1442,10 +1442,10 @@ compress_frag (struct z_stream_s *strm, const char *contents, int in_size,
>  	as_fatal (_("can't extend frag"));
>        next_out = obstack_next_free (ob);
>        obstack_blank_fast (ob, avail_out);
> -      out_size = compress_data (strm, &contents, &in_size,
> -				&next_out, &avail_out);
> +      out_size = compress_data (use_zstd, ctx, &contents, &in_size, &next_out,
> +				&avail_out);
>        if (out_size < 0)
> -        return -1;
> +	return -1;
>  
>        f->fr_fix += out_size;
>        total_out_size += out_size;
> @@ -1471,7 +1471,6 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
>    const char *section_name;
>    char *compressed_name;
>    char *header;
> -  struct z_stream_s *strm;
>    int x;
>    flagword flags = bfd_section_flags (sec);
>    unsigned int header_size, compression_header_size;
> @@ -1485,21 +1484,22 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
>    if (!startswith (section_name, ".debug_"))
>      return;
>  
> -  strm = compress_init ();
> -  if (strm == NULL)
> +  bool use_zstd = abfd->flags & BFD_COMPRESS_ZSTD;
> +  void *ctx = compress_init (use_zstd);
> +  if (ctx == NULL)
>      return;
>  
> -  if (flag_compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
> +  if (flag_compress_debug == COMPRESS_DEBUG_GNU_ZLIB)
> +    {
> +      compression_header_size = 0;
> +      header_size = 12;
> +    }
> +  else
>      {
>        compression_header_size
>  	= bfd_get_compression_header_size (stdoutput, NULL);
>        header_size = compression_header_size;
>      }
> -  else
> -    {
> -      compression_header_size = 0;
> -      header_size = 12;
> -    }
>  
>    /* Create a new frag to contain the compression header.  */
>    first_newf = frag_alloc (ob);
> @@ -1531,7 +1531,7 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
>        gas_assert (f->fr_type == rs_fill);
>        if (f->fr_fix)
>  	{
> -	  out_size = compress_frag (strm, f->fr_literal, f->fr_fix,
> +	  out_size = compress_frag (use_zstd, ctx, f->fr_literal, f->fr_fix,
>  				    &last_newf, ob);
>  	  if (out_size < 0)
>  	    return;
> @@ -1545,8 +1545,8 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
>  	{
>  	  while (count--)
>  	    {
> -	      out_size = compress_frag (strm, fill_literal, (int) fill_size,
> -				        &last_newf, ob);
> +	      out_size = compress_frag (use_zstd, ctx, fill_literal,
> +					(int)fill_size, &last_newf, ob);
>  	      if (out_size < 0)
>  		return;
>  	      compressed_size += out_size;
> @@ -1579,7 +1579,7 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
>  	as_fatal (_("can't extend frag"));
>        next_out = obstack_next_free (ob);
>        obstack_blank_fast (ob, avail_out);
> -      x = compress_finish (strm, &next_out, &avail_out, &out_size);
> +      x = compress_finish (use_zstd, ctx, &next_out, &avail_out, &out_size);
>        if (x < 0)
>  	return;
>  
> @@ -2540,6 +2540,8 @@ write_object_file (void)
>      {
>        if (flag_compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
>  	stdoutput->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI;
> +      else if (flag_compress_debug == COMPRESS_DEBUG_ZSTD)
> +	stdoutput->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD;
>        else
>  	stdoutput->flags |= BFD_COMPRESS;
>        bfd_map_over_sections (stdoutput, compress_debug, (char *) 0);
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 2598b81d205..c528ee5aa80 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -173,6 +173,9 @@ BFD_CFLAGS = -I$(BFD_DIR) -I$(BFD_SRC)
>  ZLIB = @zlibdir@ -lz
>  ZLIBINC = @zlibinc@
>  
> +ZSTD_CFLAGS = @ZSTD_CFLAGS@
> +ZSTD_LIBS = @ZSTD_LIBS@
> +
>  # Where is the decnumber library?  Typically in ../libdecnumber.
>  LIBDECNUMBER_DIR = ../libdecnumber
>  LIBDECNUMBER = $(LIBDECNUMBER_DIR)/libdecnumber.a
> @@ -625,7 +628,7 @@ INTERNAL_CPPFLAGS = $(CPPFLAGS) @GUILE_CPPFLAGS@ @PYTHON_CPPFLAGS@ \
>  INTERNAL_CFLAGS_BASE = \
>  	$(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \
>  	$(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) $(ZLIBINC) \
> -	$(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
> +	$(ZSTD_CFLAGS) $(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
>  	$(INTL_CFLAGS) $(INCGNU) $(INCSUPPORT) $(LIBBACKTRACE_INC) \
>  	$(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) $(SRCHIGH_CFLAGS) \
>  	$(TOP_CFLAGS) $(PTHREAD_CFLAGS) $(DEBUGINFOD_CFLAGS)
> @@ -647,7 +650,7 @@ INTERNAL_LDFLAGS = \
>  # Libraries and corresponding dependencies for compiling gdb.
>  # XM_CLIBS, defined in *config files, have host-dependent libs.
>  # LIBIBERTY appears twice on purpose.
> -CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) \
> +CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) $(ZSTD_LIBS) \
>          $(LIBSUPPORT) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
>  	$(XM_CLIBS) $(GDBTKLIBS)  $(LIBBACKTRACE_LIB) \
>  	@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
> @@ -2298,6 +2301,7 @@ aclocal_m4_deps = \
>  	../config/lcmessage.m4 \
>  	../config/codeset.m4 \
>  	../config/zlib.m4 \
> +	../config/zstd.m4 \
>  	../config/ax_pthread.m4
>  
>  $(srcdir)/aclocal.m4: @MAINTAINER_MODE_TRUE@ $(aclocal_m4_deps)
> diff --git a/gdb/acinclude.m4 b/gdb/acinclude.m4
> index 95ff2b6f35e..28846119dcb 100644
> --- a/gdb/acinclude.m4
> +++ b/gdb/acinclude.m4
> @@ -43,6 +43,7 @@ m4_include([../config/lib-link.m4])
>  m4_include([../config/iconv.m4])
>  
>  m4_include([../config/zlib.m4])
> +m4_include([../config/zstd.m4])
>  
>  m4_include([../gdbsupport/common.m4])
>  
> @@ -233,7 +234,7 @@ AC_DEFUN([GDB_AC_CHECK_BFD], [
>    # always want our bfd.
>    CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
>    ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
> -  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
> +  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
>    intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
>    LIBS="-lbfd -liberty -lz $intl $LIBS"
>    AC_CACHE_CHECK(
> diff --git a/gdb/config.in b/gdb/config.in
> index a4975c68aad..e13a409ec2d 100644
> --- a/gdb/config.in
> +++ b/gdb/config.in
> @@ -589,6 +589,9 @@
>  /* Define to 1 if you have the `XML_StopParser' function. */
>  #undef HAVE_XML_STOPPARSER
>  
> +/* Define to 1 if zstd is enabled. */
> +#undef HAVE_ZSTD
> +
>  /* Define to 1 if your system has the _etext variable. */
>  #undef HAVE__ETEXT
>  
> diff --git a/gdb/configure b/gdb/configure
> index 4dbd0c3b13c..57cd165088a 100755
> --- a/gdb/configure
> +++ b/gdb/configure
> @@ -747,6 +747,8 @@ READLINE_DEPS
>  READLINE
>  LTLIBICONV
>  LIBICONV
> +ZSTD_LIBS
> +ZSTD_CFLAGS
>  zlibinc
>  zlibdir
>  MIG
> @@ -893,6 +895,7 @@ enable_codesign
>  with_pkgversion
>  with_bugurl
>  with_system_zlib
> +with_zstd
>  with_gnu_ld
>  enable_rpath
>  with_libiconv_prefix
> @@ -961,6 +964,8 @@ DEBUGINFOD_CFLAGS
>  DEBUGINFOD_LIBS
>  YACC
>  YFLAGS
> +ZSTD_CFLAGS
> +ZSTD_LIBS
>  XMKMF'
>  ac_subdirs_all='testsuite
>  gdbtk'
> @@ -1641,6 +1646,8 @@ Optional Packages:
>    --with-pkgversion=PKG   Use PKG in the version string in place of "GDB"
>    --with-bugurl=URL       Direct users to URL to report a bug
>    --with-system-zlib      use installed libz
> +  --with-zstd             support zstd compressed debug sections
> +                          (default=auto)
>    --with-gnu-ld           assume the C compiler uses GNU ld default=no
>    --with-libiconv-prefix[=DIR]  search for libiconv in DIR/include and DIR/lib
>    --without-libiconv-prefix     don't search for libiconv in includedir and libdir
> @@ -1721,6 +1728,8 @@ Some influential environment variables:
>    YFLAGS      The list of arguments that will be passed by default to $YACC.
>                This script will default YFLAGS to the empty string to avoid a
>                default value of `-d' given by some make applications.
> +  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
> +  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
>    XMKMF       Path to xmkmf, Makefile generator for X Window System
>  
>  Use these variables to override the choices made by `configure' or to help
> @@ -8242,7 +8251,8 @@ if test "$ac_res" != no; then :
>  fi
>  
>  
> -# Link in zlib if we can.  This allows us to read compressed debug sections.
> +# Link in zlib/zstd if we can.  This allows us to read compressed debug
> +# sections.
>  
>    # Use the system's zlib library.
>    zlibdir="-L\$(top_builddir)/../zlib"
> @@ -8262,6 +8272,126 @@ fi
>  
>  
>  
> +# Check whether --with-zstd was given.
> +if test "${with_zstd+set}" = set; then :
> +  withval=$with_zstd;
> +else
> +  with_zstd=auto
> +fi
> +
> +
> +if test "$with_zstd" != no; then
> +
> +pkg_failed=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
> +$as_echo_n "checking for libzstd... " >&6; }
> +
> +if test -n "$ZSTD_CFLAGS"; then
> +    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
> + elif test -n "$PKG_CONFIG"; then
> +    if test -n "$PKG_CONFIG" && \
> +    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
> +  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
> +  ac_status=$?
> +  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; then
> +  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
> +		      test "x$?" != "x0" && pkg_failed=yes
> +else
> +  pkg_failed=yes
> +fi
> + else
> +    pkg_failed=untried
> +fi
> +if test -n "$ZSTD_LIBS"; then
> +    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
> + elif test -n "$PKG_CONFIG"; then
> +    if test -n "$PKG_CONFIG" && \
> +    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
> +  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
> +  ac_status=$?
> +  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; then
> +  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
> +		      test "x$?" != "x0" && pkg_failed=yes
> +else
> +  pkg_failed=yes
> +fi
> + else
> +    pkg_failed=untried
> +fi
> +
> +if test $pkg_failed = no; then
> +  pkg_save_LDFLAGS="$LDFLAGS"
> +  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
> +  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> +/* end confdefs.h.  */
> +
> +int
> +main ()
> +{
> +
> +  ;
> +  return 0;
> +}
> +_ACEOF
> +if ac_fn_c_try_link "$LINENO"; then :
> +
> +else
> +  pkg_failed=yes
> +fi
> +rm -f core conftest.err conftest.$ac_objext \
> +    conftest$ac_exeext conftest.$ac_ext
> +  LDFLAGS=$pkg_save_LDFLAGS
> +fi
> +
> +
> +
> +if test $pkg_failed = yes; then
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +
> +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
> +        _pkg_short_errors_supported=yes
> +else
> +        _pkg_short_errors_supported=no
> +fi
> +        if test $_pkg_short_errors_supported = yes; then
> +	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
> +        else
> +	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
> +        fi
> +	# Put the nasty error message in config.log where it belongs
> +	echo "$ZSTD_PKG_ERRORS" >&5
> +
> +
> +    if test "$with_zstd" = yes; then
> +      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
> +    fi
> +
> +elif test $pkg_failed = untried; then
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +
> +    if test "$with_zstd" = yes; then
> +      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
> +    fi
> +
> +else
> +	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
> +	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
> +$as_echo "yes" >&6; }
> +
> +
> +$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
> +
> +
> +fi
> +fi
> +
> +
> +
>        if test "X$prefix" = "XNONE"; then
>      acl_final_prefix="$ac_default_prefix"
>    else
> @@ -17281,7 +17411,7 @@ WIN32LIBS="$WIN32LIBS $WIN32APILIBS"
>    # always want our bfd.
>    CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
>    ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
> -  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
> +  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
>    intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
>    LIBS="-lbfd -liberty -lz $intl $LIBS"
>    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ELF support in BFD" >&5
> @@ -17396,7 +17526,7 @@ fi
>    # always want our bfd.
>    CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
>    ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
> -  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
> +  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
>    intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
>    LIBS="-lbfd -liberty -lz $intl $LIBS"
>    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Mach-O support in BFD" >&5
> diff --git a/gdb/configure.ac b/gdb/configure.ac
> index 215a91c5b27..e8cf808d280 100644
> --- a/gdb/configure.ac
> +++ b/gdb/configure.ac
> @@ -460,8 +460,10 @@ AC_SEARCH_LIBS(gethostbyname, nsl)
>  # Some systems (e.g. Solaris) have `socketpair' in libsocket.
>  AC_SEARCH_LIBS(socketpair, socket)
>  
> -# Link in zlib if we can.  This allows us to read compressed debug sections.
> +# Link in zlib/zstd if we can.  This allows us to read compressed debug
> +# sections.
>  AM_ZLIB
> +AM_ZSTD
>  
>  AM_ICONV
>  
> diff --git a/ld/Makefile.am b/ld/Makefile.am
> index d31021c13e2..bbe25f3aca2 100644
> --- a/ld/Makefile.am
> +++ b/ld/Makefile.am
> @@ -45,7 +45,7 @@ ELF_CLFAGS=-DELF_LIST_OPTIONS=@elf_list_options@ \
>  	   -DELF_PLT_UNWIND_LIST_OPTIONS=@elf_plt_unwind_list_options@
>  WARN_CFLAGS = @WARN_CFLAGS@
>  NO_WERROR = @NO_WERROR@
> -AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS)
> +AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS) $(ZSTD_CFLAGS)
>  
>  # We put the scripts in the directory $(scriptdir)/ldscripts.
>  # We can't put the scripts in $(datadir) because the SEARCH_DIR
> @@ -959,7 +959,8 @@ ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmai
>  	ldbuildid.c
>  ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) \
>  		      $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL_DEP) $(JANSSON_LIBS)
> -ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(JANSSON_LIBS)
> +ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) \
> +	       $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(ZSTD_LIBS) $(JANSSON_LIBS)
>  
>  # Dependency tracking for the generated emulation files.
>  EXTRA_ld_new_SOURCES += $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES)
> diff --git a/ld/Makefile.in b/ld/Makefile.in
> index ee0c98f65b0..400eed2717e 100644
> --- a/ld/Makefile.in
> +++ b/ld/Makefile.in
> @@ -126,7 +126,8 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
>  	$(top_srcdir)/../config/plugins.m4 \
>  	$(top_srcdir)/../config/po.m4 \
>  	$(top_srcdir)/../config/progtest.m4 \
> -	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
> +	$(top_srcdir)/../config/zlib.m4 \
> +	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
>  	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
>  	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
>  	$(top_srcdir)/../bfd/version.m4 $(top_srcdir)/configure.ac
> @@ -477,6 +478,8 @@ WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
>  XGETTEXT = @XGETTEXT@
>  YACC = `if [ -f ../bison/bison ]; then echo ../bison/bison -y -L$(srcdir)/../bison/; else echo @YACC@; fi`
>  YFLAGS = -d
> +ZSTD_CFLAGS = @ZSTD_CFLAGS@
> +ZSTD_LIBS = @ZSTD_LIBS@
>  abs_builddir = @abs_builddir@
>  abs_srcdir = @abs_srcdir@
>  abs_top_builddir = @abs_top_builddir@
> @@ -564,7 +567,7 @@ ELF_CLFAGS = -DELF_LIST_OPTIONS=@elf_list_options@ \
>  	   -DELF_SHLIB_LIST_OPTIONS=@elf_shlib_list_options@ \
>  	   -DELF_PLT_UNWIND_LIST_OPTIONS=@elf_plt_unwind_list_options@
>  
> -AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS)
> +AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS) $(ZSTD_CFLAGS)
>  
>  # We put the scripts in the directory $(scriptdir)/ldscripts.
>  # We can't put the scripts in $(datadir) because the SEARCH_DIR
> @@ -1011,7 +1014,9 @@ ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmai
>  ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) \
>  		      $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL_DEP) $(JANSSON_LIBS)
>  
> -ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(JANSSON_LIBS)
> +ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) \
> +	       $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(ZSTD_LIBS) $(JANSSON_LIBS)
> +
>  #
>  #
>  # Build a dummy plugin using libtool.
> diff --git a/ld/aclocal.m4 b/ld/aclocal.m4
> index d20c542eed5..893e973e4f2 100644
> --- a/ld/aclocal.m4
> +++ b/ld/aclocal.m4
> @@ -1203,6 +1203,7 @@ m4_include([../config/plugins.m4])
>  m4_include([../config/po.m4])
>  m4_include([../config/progtest.m4])
>  m4_include([../config/zlib.m4])
> +m4_include([../config/zstd.m4])
>  m4_include([../libtool.m4])
>  m4_include([../ltoptions.m4])
>  m4_include([../ltsugar.m4])
> diff --git a/ld/config.in b/ld/config.in
> index 0ccd79d59cd..3916740eee4 100644
> --- a/ld/config.in
> +++ b/ld/config.in
> @@ -162,6 +162,9 @@
>  /* Define to 1 if you have the <windows.h> header file. */
>  #undef HAVE_WINDOWS_H
>  
> +/* Define to 1 if zstd is enabled. */
> +#undef HAVE_ZSTD
> +
>  /* Define to the sub-directory in which libtool stores uninstalled libraries.
>     */
>  #undef LT_OBJDIR
> diff --git a/ld/configure b/ld/configure
> index a1a07005400..175dd995b2b 100755
> --- a/ld/configure
> +++ b/ld/configure
> @@ -646,6 +646,8 @@ elf_plt_unwind_list_options
>  elf_shlib_list_options
>  elf_list_options
>  STRINGIFY
> +ZSTD_LIBS
> +ZSTD_CFLAGS
>  zlibinc
>  zlibdir
>  NATIVE_LIB_DIRS
> @@ -679,9 +681,6 @@ WARN_CFLAGS_FOR_BUILD
>  WARN_CFLAGS
>  JANSSON_LIBS
>  JANSSON_CFLAGS
> -PKG_CONFIG_LIBDIR
> -PKG_CONFIG_PATH
> -PKG_CONFIG
>  enable_libctf
>  ENABLE_LIBCTF_FALSE
>  ENABLE_LIBCTF_TRUE
> @@ -711,6 +710,9 @@ LD
>  FGREP
>  SED
>  LIBTOOL
> +PKG_CONFIG_LIBDIR
> +PKG_CONFIG_PATH
> +PKG_CONFIG
>  EGREP
>  CPP
>  GREP
> @@ -855,6 +857,7 @@ enable_werror
>  enable_build_warnings
>  enable_nls
>  with_system_zlib
> +with_zstd
>  '
>        ac_precious_vars='build_alias
>  host_alias
> @@ -868,14 +871,16 @@ CXX
>  CXXFLAGS
>  CCC
>  CPP
> -CXXCPP
>  PKG_CONFIG
>  PKG_CONFIG_PATH
>  PKG_CONFIG_LIBDIR
> +CXXCPP
>  JANSSON_CFLAGS
>  JANSSON_LIBS
>  YACC
> -YFLAGS'
> +YFLAGS
> +ZSTD_CFLAGS
> +ZSTD_LIBS'
>  
>  
>  # Initialize some variables set by options.
> @@ -1552,6 +1557,8 @@ Optional Packages:
>    --with-lib-path=dir1:dir2...  set default LIB_PATH
>    --with-sysroot=DIR Search for usr/lib et al within DIR.
>    --with-system-zlib      use installed libz
> +  --with-zstd             support zstd compressed debug sections
> +                          (default=auto)
>  
>  Some influential environment variables:
>    CC          C compiler command
> @@ -1564,12 +1571,12 @@ Some influential environment variables:
>    CXX         C++ compiler command
>    CXXFLAGS    C++ compiler flags
>    CPP         C preprocessor
> -  CXXCPP      C++ preprocessor
>    PKG_CONFIG  path to pkg-config utility
>    PKG_CONFIG_PATH
>                directories to add to pkg-config's search path
>    PKG_CONFIG_LIBDIR
>                path overriding pkg-config's built-in search path
> +  CXXCPP      C++ preprocessor
>    JANSSON_CFLAGS
>                C compiler flags for JANSSON, overriding pkg-config
>    JANSSON_LIBS
> @@ -1580,6 +1587,8 @@ Some influential environment variables:
>    YFLAGS      The list of arguments that will be passed by default to $YACC.
>                This script will default YFLAGS to the empty string to avoid a
>                default value of `-d' given by some make applications.
> +  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
> +  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
>  
>  Use these variables to override the choices made by `configure' or to help
>  it to find libraries and programs with nonstandard names/locations.
> @@ -5388,6 +5397,126 @@ $as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
>  
>  
>  
> +
> +
> +
> +
> +
> +
> +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
> +	if test -n "$ac_tool_prefix"; then
> +  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
> +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
> +$as_echo_n "checking for $ac_word... " >&6; }
> +if ${ac_cv_path_PKG_CONFIG+:} false; then :
> +  $as_echo_n "(cached) " >&6
> +else
> +  case $PKG_CONFIG in
> +  [\\/]* | ?:[\\/]*)
> +  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
> +  ;;
> +  *)
> +  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
> +for as_dir in $PATH
> +do
> +  IFS=$as_save_IFS
> +  test -z "$as_dir" && as_dir=.
> +    for ac_exec_ext in '' $ac_executable_extensions; do
> +  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
> +    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
> +    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
> +    break 2
> +  fi
> +done
> +  done
> +IFS=$as_save_IFS
> +
> +  ;;
> +esac
> +fi
> +PKG_CONFIG=$ac_cv_path_PKG_CONFIG
> +if test -n "$PKG_CONFIG"; then
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
> +$as_echo "$PKG_CONFIG" >&6; }
> +else
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +fi
> +
> +
> +fi
> +if test -z "$ac_cv_path_PKG_CONFIG"; then
> +  ac_pt_PKG_CONFIG=$PKG_CONFIG
> +  # Extract the first word of "pkg-config", so it can be a program name with args.
> +set dummy pkg-config; ac_word=$2
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
> +$as_echo_n "checking for $ac_word... " >&6; }
> +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
> +  $as_echo_n "(cached) " >&6
> +else
> +  case $ac_pt_PKG_CONFIG in
> +  [\\/]* | ?:[\\/]*)
> +  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
> +  ;;
> +  *)
> +  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
> +for as_dir in $PATH
> +do
> +  IFS=$as_save_IFS
> +  test -z "$as_dir" && as_dir=.
> +    for ac_exec_ext in '' $ac_executable_extensions; do
> +  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
> +    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
> +    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
> +    break 2
> +  fi
> +done
> +  done
> +IFS=$as_save_IFS
> +
> +  ;;
> +esac
> +fi
> +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
> +if test -n "$ac_pt_PKG_CONFIG"; then
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
> +$as_echo "$ac_pt_PKG_CONFIG" >&6; }
> +else
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +fi
> +
> +  if test "x$ac_pt_PKG_CONFIG" = x; then
> +    PKG_CONFIG=""
> +  else
> +    case $cross_compiling:$ac_tool_warned in
> +yes:)
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
> +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
> +ac_tool_warned=yes ;;
> +esac
> +    PKG_CONFIG=$ac_pt_PKG_CONFIG
> +  fi
> +else
> +  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
> +fi
> +
> +fi
> +if test -n "$PKG_CONFIG"; then
> +	_pkg_min_version=0.9.0
> +	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
> +$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
> +	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
> +		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
> +$as_echo "yes" >&6; }
> +	else
> +		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +		PKG_CONFIG=""
> +	fi
> +fi
> +
>  case `pwd` in
>    *\ * | *\	*)
>      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
> @@ -11491,7 +11620,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 11494 "configure"
> +#line 11623 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -11597,7 +11726,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 11600 "configure"
> +#line 11729 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -15586,126 +15715,6 @@ fi
>  
>  
>  if test "x$enable_jansson" != "xno"; then
> -
> -
> -
> -
> -
> -
> -
> -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
> -	if test -n "$ac_tool_prefix"; then
> -  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
> -set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
> -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
> -$as_echo_n "checking for $ac_word... " >&6; }
> -if ${ac_cv_path_PKG_CONFIG+:} false; then :
> -  $as_echo_n "(cached) " >&6
> -else
> -  case $PKG_CONFIG in
> -  [\\/]* | ?:[\\/]*)
> -  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
> -  ;;
> -  *)
> -  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
> -for as_dir in $PATH
> -do
> -  IFS=$as_save_IFS
> -  test -z "$as_dir" && as_dir=.
> -    for ac_exec_ext in '' $ac_executable_extensions; do
> -  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
> -    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
> -    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
> -    break 2
> -  fi
> -done
> -  done
> -IFS=$as_save_IFS
> -
> -  ;;
> -esac
> -fi
> -PKG_CONFIG=$ac_cv_path_PKG_CONFIG
> -if test -n "$PKG_CONFIG"; then
> -  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
> -$as_echo "$PKG_CONFIG" >&6; }
> -else
> -  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> -$as_echo "no" >&6; }
> -fi
> -
> -
> -fi
> -if test -z "$ac_cv_path_PKG_CONFIG"; then
> -  ac_pt_PKG_CONFIG=$PKG_CONFIG
> -  # Extract the first word of "pkg-config", so it can be a program name with args.
> -set dummy pkg-config; ac_word=$2
> -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
> -$as_echo_n "checking for $ac_word... " >&6; }
> -if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
> -  $as_echo_n "(cached) " >&6
> -else
> -  case $ac_pt_PKG_CONFIG in
> -  [\\/]* | ?:[\\/]*)
> -  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
> -  ;;
> -  *)
> -  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
> -for as_dir in $PATH
> -do
> -  IFS=$as_save_IFS
> -  test -z "$as_dir" && as_dir=.
> -    for ac_exec_ext in '' $ac_executable_extensions; do
> -  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
> -    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
> -    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
> -    break 2
> -  fi
> -done
> -  done
> -IFS=$as_save_IFS
> -
> -  ;;
> -esac
> -fi
> -ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
> -if test -n "$ac_pt_PKG_CONFIG"; then
> -  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
> -$as_echo "$ac_pt_PKG_CONFIG" >&6; }
> -else
> -  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> -$as_echo "no" >&6; }
> -fi
> -
> -  if test "x$ac_pt_PKG_CONFIG" = x; then
> -    PKG_CONFIG=""
> -  else
> -    case $cross_compiling:$ac_tool_warned in
> -yes:)
> -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
> -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
> -ac_tool_warned=yes ;;
> -esac
> -    PKG_CONFIG=$ac_pt_PKG_CONFIG
> -  fi
> -else
> -  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
> -fi
> -
> -fi
> -if test -n "$PKG_CONFIG"; then
> -	_pkg_min_version=0.9.0
> -	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
> -$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
> -	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
> -		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
> -$as_echo "yes" >&6; }
> -	else
> -		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> -$as_echo "no" >&6; }
> -		PKG_CONFIG=""
> -	fi
> -fi
>    if test -n "$PKG_CONFIG"; then :
>  
>  
> @@ -17052,8 +17061,8 @@ $as_echo "#define HAVE_DECL_GETOPT 1" >>confdefs.h
>  
>  fi
>  
> -# Link in zlib if we can.  This allows us to read and write
> -# compressed CTF sections.
> +# Link in zlib/zstd if we can.  This allows us to read and write
> +# compressed debug sections.
>  
>    # Use the system's zlib library.
>    zlibdir="-L\$(top_builddir)/../zlib"
> @@ -17072,6 +17081,126 @@ fi
>  
>  
>  
> +
> +# Check whether --with-zstd was given.
> +if test "${with_zstd+set}" = set; then :
> +  withval=$with_zstd;
> +else
> +  with_zstd=auto
> +fi
> +
> +
> +if test "$with_zstd" != no; then
> +
> +pkg_failed=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
> +$as_echo_n "checking for libzstd... " >&6; }
> +
> +if test -n "$ZSTD_CFLAGS"; then
> +    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
> + elif test -n "$PKG_CONFIG"; then
> +    if test -n "$PKG_CONFIG" && \
> +    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
> +  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
> +  ac_status=$?
> +  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; then
> +  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
> +		      test "x$?" != "x0" && pkg_failed=yes
> +else
> +  pkg_failed=yes
> +fi
> + else
> +    pkg_failed=untried
> +fi
> +if test -n "$ZSTD_LIBS"; then
> +    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
> + elif test -n "$PKG_CONFIG"; then
> +    if test -n "$PKG_CONFIG" && \
> +    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
> +  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
> +  ac_status=$?
> +  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; then
> +  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
> +		      test "x$?" != "x0" && pkg_failed=yes
> +else
> +  pkg_failed=yes
> +fi
> + else
> +    pkg_failed=untried
> +fi
> +
> +if test $pkg_failed = no; then
> +  pkg_save_LDFLAGS="$LDFLAGS"
> +  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
> +  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> +/* end confdefs.h.  */
> +
> +int
> +main ()
> +{
> +
> +  ;
> +  return 0;
> +}
> +_ACEOF
> +if ac_fn_c_try_link "$LINENO"; then :
> +
> +else
> +  pkg_failed=yes
> +fi
> +rm -f core conftest.err conftest.$ac_objext \
> +    conftest$ac_exeext conftest.$ac_ext
> +  LDFLAGS=$pkg_save_LDFLAGS
> +fi
> +
> +
> +
> +if test $pkg_failed = yes; then
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +
> +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
> +        _pkg_short_errors_supported=yes
> +else
> +        _pkg_short_errors_supported=no
> +fi
> +        if test $_pkg_short_errors_supported = yes; then
> +	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
> +        else
> +	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
> +        fi
> +	# Put the nasty error message in config.log where it belongs
> +	echo "$ZSTD_PKG_ERRORS" >&5
> +
> +
> +    if test "$with_zstd" = yes; then
> +      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
> +    fi
> +
> +elif test $pkg_failed = untried; then
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
> +$as_echo "no" >&6; }
> +
> +    if test "$with_zstd" = yes; then
> +      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
> +    fi
> +
> +else
> +	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
> +	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
> +        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
> +$as_echo "yes" >&6; }
> +
> +
> +$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
> +
> +
> +fi
> +fi
> +
> +
>  # When converting linker scripts into strings for use in emulation
>  # files, use astring.sed if the compiler supports ANSI string
>  # concatenation, or ostring.sed otherwise.  This is to support the
> diff --git a/ld/configure.ac b/ld/configure.ac
> index eb55904c090..a491f9f1116 100644
> --- a/ld/configure.ac
> +++ b/ld/configure.ac
> @@ -34,6 +34,7 @@ AC_PROG_GREP
>  AC_GNU_SOURCE
>  AC_USE_SYSTEM_EXTENSIONS
>  AC_PROG_INSTALL
> +PKG_PROG_PKG_CONFIG
>  
>  LT_INIT
>  ACX_LARGEFILE
> @@ -297,7 +298,6 @@ AC_ARG_ENABLE([jansson],
>    [enable_jansson="no"])
>  
>  if test "x$enable_jansson" != "xno"; then
> -  PKG_PROG_PKG_CONFIG
>    AS_IF([test -n "$PKG_CONFIG"],
>      [
>        PKG_CHECK_MODULES(JANSSON, [jansson],
> @@ -386,9 +386,10 @@ if test $ld_cv_decl_getopt_unistd_h = yes; then
>  	    [Is the prototype for getopt in <unistd.h> in the expected format?])
>  fi
>  
> -# Link in zlib if we can.  This allows us to read and write
> -# compressed CTF sections.
> +# Link in zlib/zstd if we can.  This allows us to read and write
> +# compressed debug sections.
>  AM_ZLIB
> +AM_ZSTD
>  
>  # When converting linker scripts into strings for use in emulation
>  # files, use astring.sed if the compiler supports ANSI string
> diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
> index c52484f35d3..acd66f907d1 100644
> --- a/ld/emultempl/elf.em
> +++ b/ld/emultempl/elf.em
> @@ -668,6 +668,15 @@ gld${EMULATION_NAME}_handle_option (int optc)
>  	link_info.compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
>        else if (strcasecmp (optarg, "zlib-gabi") == 0)
>  	link_info.compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
> +      else if (strcasecmp (optarg, "zstd") == 0)
> +	{
> +#ifdef HAVE_ZSTD
> +	  link_info.compress_debug = COMPRESS_DEBUG_ZSTD;
> +#else
> +	  einfo (_ ("%F%P: --compress-debug-sections=zstd: ld is not built "
> +		    "with zstd support\n"));
> +#endif
> +	}
>        else
>  	einfo (_("%F%P: invalid --compress-debug-sections option: \`%s'\n"),
>  	       optarg);
> diff --git a/ld/ld.texi b/ld/ld.texi
> index eabbec8faa9..9daed2e7e9f 100644
> --- a/ld/ld.texi
> +++ b/ld/ld.texi
> @@ -2863,10 +2863,12 @@ but for most Linux based systems it will be @code{both}.
>  @kindex --compress-debug-sections=zlib
>  @kindex --compress-debug-sections=zlib-gnu
>  @kindex --compress-debug-sections=zlib-gabi
> +@kindex --compress-debug-sections=zstd
>  @item --compress-debug-sections=none
>  @itemx --compress-debug-sections=zlib
>  @itemx --compress-debug-sections=zlib-gnu
>  @itemx --compress-debug-sections=zlib-gabi
> +@itemx --compress-debug-sections=zstd
>  On ELF platforms, these options control how DWARF debug sections are
>  compressed using zlib.
>  
> @@ -2880,6 +2882,9 @@ sets the SHF_COMPRESSED flag in the sections' headers.
>  The @option{--compress-debug-sections=zlib} option is an alias for
>  @option{--compress-debug-sections=zlib-gabi}.
>  
> +@option{--compress-debug-sections=zstd} compresses DWARF debug sections using
> +zstd.
> +
>  Note that this option overrides any compression in input debug
>  sections, so if a binary is linked with @option{--compress-debug-sections=none}
>  for example, then any compressed debug sections in input files will be
> diff --git a/ld/ldmain.c b/ld/ldmain.c
> index 1bbddaaad32..71af5935b74 100644
> --- a/ld/ldmain.c
> +++ b/ld/ldmain.c
> @@ -506,8 +506,12 @@ main (int argc, char **argv)
>    if ((link_info.compress_debug & COMPRESS_DEBUG))
>      {
>        link_info.output_bfd->flags |= BFD_COMPRESS;
> -      if (link_info.compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
> -	link_info.output_bfd->flags |= BFD_COMPRESS_GABI;
> +      if (link_info.compress_debug != COMPRESS_DEBUG_GNU_ZLIB)
> +	{
> +	  link_info.output_bfd->flags |= BFD_COMPRESS_GABI;
> +	  if (link_info.compress_debug == COMPRESS_DEBUG_ZSTD)
> +	    link_info.output_bfd->flags |= BFD_COMPRESS_ZSTD;
> +	}
>      }
>  
>    ldwrite ();
> diff --git a/ld/lexsup.c b/ld/lexsup.c
> index 9225f71b3ce..299371fb775 100644
> --- a/ld/lexsup.c
> +++ b/ld/lexsup.c
> @@ -2146,8 +2146,8 @@ elf_static_list_options (FILE *file)
>    fprintf (file, _("\
>    --package-metadata[=JSON]   Generate package metadata note\n"));
>    fprintf (file, _("\
> -  --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi]\n\
> -                              Compress DWARF debug sections using zlib\n"));
> +  --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi|zstd]\n\
> +			      Compress DWARF debug sections\n"));
>  #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
>    fprintf (file, _("\
>                                  Default: zlib-gabi\n"));
> diff --git a/ld/testsuite/ld-elf/compress.exp b/ld/testsuite/ld-elf/compress.exp
> index cfdd767b8ab..7b8a31cc41d 100644
> --- a/ld/testsuite/ld-elf/compress.exp
> +++ b/ld/testsuite/ld-elf/compress.exp
> @@ -254,3 +254,20 @@ if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rt] } then {
>  } else {
>      pass "$test_name"
>  }
> +
> +if { ![ld_assemble $as "--compress-debug-sections=zstd $srcdir/$subdir/empty.s" tmpdir/emptyzstd.o ] } {
> +    return
> +}
> +set build_tests {
> +  {"Build libzstdfoo.so with zstd compressed debug sections"
> +   "-shared" "-fPIC -g -Wa,--compress-debug-sections=zstd -Wl,--compress-debug-sections=zstd"
> +   {foo.c} {} "libzstdfoo.so"}
> +}
> +set run_tests {
> +    {"Run zstdnormal with libzstdfoo.so with zstd compressed debug sections"
> +     "tmpdir/begin.o tmpdir/libzstdfoo.so tmpdir/end.o -Wl,--compress-debug-sections=zstd" ""
> +     {main.c} "zstdnormal" "normal.out" "-Wa,--compress-debug-sections=zstd"}
> +}
> +
> +run_cc_link_tests $build_tests
> +run_ld_link_exec_tests $run_tests

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-24  6:53 ` Enze Li
@ 2022-09-24  7:13   ` Fangrui Song
  2022-09-27 18:06     ` Tom Tromey
  0 siblings, 1 reply; 32+ messages in thread
From: Fangrui Song @ 2022-09-24  7:13 UTC (permalink / raw)
  To: Enze Li
  Cc: Fangrui Song via Gdb-patches, Alan Modra, Jan Beulich,
	Nick Clifton, Simon Marchi, binutils

On 2022-09-24, Enze Li wrote:
>Hi Fangrui,
>
>One nit, maybe not an important one.
>
>A proper committed message should include a link to the relevant bug on
>Bugzilla. Like this,
>
>  Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29563
>
>For more detail, see here[1].
>
>[1] https://sourceware.org/gdb/wiki/ContributionChecklist#Properly_formatted_commit_messages
>
>Thanks,
>Enze

Hi Enze,

Thanks for the notice.  I see that gdb started to use "Bug:" since 2021-07.

In binutils, there isn't such a convention and there is no commit using
"Bug:".  So I will keep using the umbrella link PR29397.

I am on the
fence whether the gdb one needs to use "Bug:" but I'll probably not use
it this time.  Ideally the gdb patch should be separate, but since the
bfd's zstd dependency needs gdb build system's cooperation it is placed
in the same patch:)

I am still waiting for an approval from binutils side.  Relatedly, I
believe ChangeLog is no longer strictly enforced.  There are many recent
commits don't using ChangeLog.  I intentionally skip ChangeLog for this
patch since I believe it would provide little value.  (I see
"ANNOUNCEMENT: ChangeLog policy change after GDB 11".)

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-23 14:32 ` Simon Marchi
@ 2022-09-26  5:12   ` Alan Modra
  2022-09-26  7:20     ` Fangrui Song
  2022-09-26 14:08     ` Simon Marchi
  0 siblings, 2 replies; 32+ messages in thread
From: Alan Modra @ 2022-09-26  5:12 UTC (permalink / raw)
  To: Simon Marchi
  Cc: Fangrui Song, Jan Beulich, Nick Clifton, binutils, gdb-patches

On Fri, Sep 23, 2022 at 10:32:43AM -0400, Simon Marchi wrote:
> Just one question: you moved PKG_PROG_PKG_CONFIG up in ld/configure.ac,
> which I think is ok.

I'm going to fix this one another way.

>  But what about the other configure.ac files, don't
> they need PKG_PROG_PKG_CONFIG too?  gdb/configure.ac, for instance, uses
> pkg-config for debuginfod.  So if the user passes --without-debuginfod
> --with-zstd, I expect things to fail, as the pkg-config will be skipped.

No, that will be fine, I think  The reason being that
PKG_CHECK_MODULES AC_REQUIREs PKG_PROG_PKG_CONFIG.  So the expansion
of AC_DEBUGINFOD will emit an expansion of PKG_PROG_PKG_CONFIG if that
has not already occurred, before the entire AC_DEBUGINFOD expansion.

> binutils/configure.ac probably has the same problem, since it uses
> PKG_CHECK_MODULES for msgpack.

I'll fix this one even though it isn't a problem now because
AC_DEBUGINFOD and AM_ZSTD preceed it.  We should use AS_IF more often,
particularly when autoconf macros are invoked.

> I would suggest using PKG_PROG_PKG_CONFIG at the top of all configure.ac
> that use AM_ZSTD, out of precaution.

Better to avoid the need..

binutils/
	* configure.ac (msgpack): Use "AS_IF" rather than "if".
	* configure: Regenerate.
ld/
	* configure.ac (jansson): Use "AS_IF" rather than "if".
	* configure: Regenerate.

diff --git a/binutils/configure b/binutils/configure
index 1c518227f57..4c0c391e9d5 100755
--- a/binutils/configure
+++ b/binutils/configure
@@ -13507,8 +13507,7 @@ else
 fi
 
 
-
-if test "$with_msgpack" != no; then
+if test "$with_msgpack" != no; then :
 
 pkg_failed=no
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for msgpack" >&5
@@ -13592,29 +13591,23 @@ fi
 	# Put the nasty error message in config.log where it belongs
 	echo "$MSGPACK_PKG_ERRORS" >&5
 
-
-      if test "$with_msgpack" = yes; then
-	as_fn_error $? "--with-msgpack was given, but msgpack is missing or unusable." "$LINENO" 5
-      fi
-
+	if test "$with_msgpack" = yes; then :
+  as_fn_error $? "--with-msgpack was given, but msgpack is missing or unusable." "$LINENO" 5
+fi
 elif test $pkg_failed = untried; then
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-
-      if test "$with_msgpack" = yes; then
-	as_fn_error $? "--with-msgpack was given, but msgpack is missing or unusable." "$LINENO" 5
-      fi
-
+	if test "$with_msgpack" = yes; then :
+  as_fn_error $? "--with-msgpack was given, but msgpack is missing or unusable." "$LINENO" 5
+fi
 else
 	MSGPACK_CFLAGS=$pkg_cv_MSGPACK_CFLAGS
 	MSGPACK_LIBS=$pkg_cv_MSGPACK_LIBS
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
 
-
 $as_echo "#define HAVE_MSGPACK 1" >>confdefs.h
 
-
 fi
 fi
 
diff --git a/binutils/configure.ac b/binutils/configure.ac
index ec002d3f88f..0798d84f4d1 100644
--- a/binutils/configure.ac
+++ b/binutils/configure.ac
@@ -278,16 +278,11 @@ AC_ARG_WITH([msgpack],
 	    [],
 	    [with_msgpack=auto])
 
-
-if test "$with_msgpack" != no; then
-  PKG_CHECK_MODULES(MSGPACK, msgpack, [
-    AC_DEFINE([HAVE_MSGPACK], [1], [Define to 1 if msgpack is available.])
-  ], [
-      if test "$with_msgpack" = yes; then
-	AC_MSG_ERROR([--with-msgpack was given, but msgpack is missing or unusable.])
-      fi
-  ])
-fi
+AS_IF([test "$with_msgpack" != no],
+  [PKG_CHECK_MODULES(MSGPACK, msgpack,
+    [AC_DEFINE([HAVE_MSGPACK], [1], [Define to 1 if msgpack is available.])],
+    [AS_IF([test "$with_msgpack" = yes],
+      [AC_MSG_ERROR([--with-msgpack was given, but msgpack is missing or unusable.])])])])
 
 # target-specific stuff:
 
diff --git a/ld/configure b/ld/configure
index a1a07005400..4efe3ef5dfc 100755
--- a/ld/configure
+++ b/ld/configure
@@ -15585,7 +15585,6 @@ else
 fi
 
 
-if test "x$enable_jansson" != "xno"; then
 
 
 
@@ -15706,8 +15705,7 @@ $as_echo "no" >&6; }
 		PKG_CONFIG=""
 	fi
 fi
-  if test -n "$PKG_CONFIG"; then :
-
+if test "x$enable_jansson" != "xno"; then :
 
 pkg_failed=no
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jansson" >&5
@@ -15791,15 +15789,11 @@ fi
 	# Put the nasty error message in config.log where it belongs
 	echo "$JANSSON_PKG_ERRORS" >&5
 
-
-	  as_fn_error $? "Cannot find jansson library" "$LINENO" 5
-
+	as_fn_error $? "Cannot find jansson library" "$LINENO" 5
 elif test $pkg_failed = untried; then
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-
-	  as_fn_error $? "Cannot find jansson library" "$LINENO" 5
-
+	as_fn_error $? "Cannot find jansson library" "$LINENO" 5
 else
 	JANSSON_CFLAGS=$pkg_cv_JANSSON_CFLAGS
 	JANSSON_LIBS=$pkg_cv_JANSSON_LIBS
@@ -15814,11 +15808,6 @@ $as_echo "#define HAVE_JANSSON 1" >>confdefs.h
 
 fi
 
-else
-
-      as_fn_error $? "Cannot find pkg-config" "$LINENO" 5
-
-fi
 fi
 
 
diff --git a/ld/configure.ac b/ld/configure.ac
index eb55904c090..8a8bfc9a14e 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -296,24 +296,15 @@ AC_ARG_ENABLE([jansson],
   [enable_jansson=$enableval],
   [enable_jansson="no"])
 
-if test "x$enable_jansson" != "xno"; then
-  PKG_PROG_PKG_CONFIG
-  AS_IF([test -n "$PKG_CONFIG"],
+AS_IF([test "x$enable_jansson" != "xno"],
+  [PKG_CHECK_MODULES(JANSSON, [jansson],
     [
-      PKG_CHECK_MODULES(JANSSON, [jansson],
-	[
-	  AC_DEFINE(HAVE_JANSSON, 1, [The jansson library is to be used])
-	  AC_SUBST([JANSSON_CFLAGS])
-	  AC_SUBST([JANSSON_LIBS])
-	],
-	[
-	  AC_MSG_ERROR([Cannot find jansson library])
-	])
+      AC_DEFINE(HAVE_JANSSON, 1, [The jansson library is to be used])
+      AC_SUBST([JANSSON_CFLAGS])
+      AC_SUBST([JANSSON_LIBS])
     ],
-    [
-      AC_MSG_ERROR([Cannot find pkg-config])
-    ])
-fi
+    [AC_MSG_ERROR([Cannot find jansson library])])
+  ])
 
 AM_BINUTILS_WARNINGS
 


-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-26  5:12   ` Alan Modra
@ 2022-09-26  7:20     ` Fangrui Song
  2022-09-26 13:30       ` Alan Modra
  2022-09-26 14:08     ` Simon Marchi
  1 sibling, 1 reply; 32+ messages in thread
From: Fangrui Song @ 2022-09-26  7:20 UTC (permalink / raw)
  To: Alan Modra; +Cc: Simon Marchi, Jan Beulich, Nick Clifton, binutils, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1586 bytes --]

On 2022-09-26, Alan Modra wrote:
>On Fri, Sep 23, 2022 at 10:32:43AM -0400, Simon Marchi wrote:
>> Just one question: you moved PKG_PROG_PKG_CONFIG up in ld/configure.ac,
>> which I think is ok.
>
>I'm going to fix this one another way.
>
>>  But what about the other configure.ac files, don't
>> they need PKG_PROG_PKG_CONFIG too?  gdb/configure.ac, for instance, uses
>> pkg-config for debuginfod.  So if the user passes --without-debuginfod
>> --with-zstd, I expect things to fail, as the pkg-config will be skipped.
>
>No, that will be fine, I think  The reason being that
>PKG_CHECK_MODULES AC_REQUIREs PKG_PROG_PKG_CONFIG.  So the expansion
>of AC_DEBUGINFOD will emit an expansion of PKG_PROG_PKG_CONFIG if that
>has not already occurred, before the entire AC_DEBUGINFOD expansion.
>
>> binutils/configure.ac probably has the same problem, since it uses
>> PKG_CHECK_MODULES for msgpack.
>
>I'll fix this one even though it isn't a problem now because
>AC_DEBUGINFOD and AM_ZSTD preceed it.  We should use AS_IF more often,
>particularly when autoconf macros are invoked.
>
>> I would suggest using PKG_PROG_PKG_CONFIG at the top of all configure.ac
>> that use AM_ZSTD, out of precaution.
>
>Better to avoid the need..
>
>binutils/
>	* configure.ac (msgpack): Use "AS_IF" rather than "if".
>	* configure: Regenerate.
>ld/
>	* configure.ac (jansson): Use "AS_IF" rather than "if".
>	* configure: Regenerate.
>

Thanks.  I've changed the zstd patch to use AS_IF, too.

BTW: I think the `!= xno` trick for ancient shells is not needed.  `!=
no` is used many times in binutils-gdb.

[-- Attachment #2: v4-0001-binutils-gdb-support-zstd-compressed-debug-sectio.patch --]
[-- Type: text/x-diff, Size: 109885 bytes --]

From 1c70c807039cecab5fff2e7c09e0086d093d4042 Mon Sep 17 00:00:00 2001
From: Fangrui Song <maskray@google.com>
Date: Mon, 26 Sep 2022 00:15:19 -0700
Subject: [PATCH v4] binutils, gdb: support zstd compressed debug sections

PR29397 PR29563: The new configure option --with-zstd defaults to auto.
If pkgconfig/libzstd.pc is found, define HAVE_ZSTD and support zstd
compressed debug sections for most tools.

* bfd: for addr2line, objdump --dwarf, gdb, etc
* gas: support --compress-debug-sections=zstd
* ld: support ELFCOMPRESS_ZSTD input and --compress-debug-sections=zstd
* objcopy: support ELFCOMPRESS_ZSTD input for
  --decompress-debug-sections and --compress-debug-sections=zstd
* gdb: support ELFCOMPRESS_ZSTD input.  The bfd change references zstd
  symbols, so gdb has to link against -lzstd in this patch.

If zstd is not supported, ELFCOMPRESS_ZSTD input triggers an error.  We
can avoid HAVE_ZSTD if binutils-gdb imports zstd/ like zlib/, but this
is too heavyweight, so don't do it for now.

```
% ld/ld-new a.o
ld/ld-new: a.o: section .debug_abbrev is compressed with zstd, but BFD is not built with zstd support
...

% ld/ld-new a.o --compress-debug-sections=zstd
ld/ld-new: --compress-debug-sections=zstd: ld is not built with zstd support

% binutils/objcopy --compress-debug-sections=zstd a.o b.o
binutils/objcopy: --compress-debug-sections=zstd: binutils is not built with zstd support

% binutils/objcopy b.o --decompress-debug-sections
binutils/objcopy: zstd.o: section .debug_abbrev is compressed with zstd, but BFD is not built with zstd support
...
```
---
 bfd/Makefile.am                              |   4 +-
 bfd/Makefile.in                              |  13 +-
 bfd/aclocal.m4                               |   2 +
 bfd/bfd-in.h                                 |   3 +-
 bfd/bfd-in2.h                                |  11 +-
 bfd/bfd.c                                    |  26 +-
 bfd/compress.c                               |  72 +++-
 bfd/config.in                                |   3 +
 bfd/configure                                | 268 ++++++++++++-
 bfd/configure.ac                             |   3 +-
 bfd/elf.c                                    |  12 +
 bfd/elfxx-target.h                           |   6 +-
 bfd/section.c                                |   3 +-
 binutils/Makefile.in                         |   5 +-
 binutils/NEWS                                |   6 +
 binutils/aclocal.m4                          |   1 +
 binutils/config.in                           |   3 +
 binutils/configure                           | 136 ++++++-
 binutils/configure.ac                        |   3 +-
 binutils/doc/binutils.texi                   |  16 +-
 binutils/objcopy.c                           |  19 +-
 binutils/testsuite/binutils-all/compress.exp |  44 +++
 config/zstd.m4                               |  23 ++
 configure                                    |  10 +
 configure.ac                                 |   3 +
 gas/Makefile.am                              |   4 +-
 gas/Makefile.in                              |  13 +-
 gas/NEWS                                     |   3 +
 gas/aclocal.m4                               |   2 +
 gas/as.c                                     |  13 +-
 gas/compress-debug.c                         |  60 ++-
 gas/compress-debug.h                         |  10 +-
 gas/config.in                                |   3 +
 gas/configure                                | 269 ++++++++++++-
 gas/configure.ac                             |   3 +-
 gas/doc/as.texi                              |  11 +-
 gas/write.c                                  |  36 +-
 gdb/Makefile.in                              |   8 +-
 gdb/NEWS                                     |   2 +
 gdb/acinclude.m4                             |   3 +-
 gdb/config.in                                |   3 +
 gdb/configure                                | 137 ++++++-
 gdb/configure.ac                             |   4 +-
 ld/Makefile.am                               |   5 +-
 ld/Makefile.in                               |  11 +-
 ld/NEWS                                      |   3 +
 ld/aclocal.m4                                |   1 +
 ld/config.in                                 |   3 +
 ld/configure                                 | 390 ++++++++++++-------
 ld/configure.ac                              |   6 +-
 ld/emultempl/elf.em                          |   9 +
 ld/ld.texi                                   |   5 +
 ld/ldmain.c                                  |   8 +-
 ld/lexsup.c                                  |   4 +-
 ld/testsuite/ld-elf/compress.exp             |  17 +
 55 files changed, 1487 insertions(+), 254 deletions(-)
 create mode 100644 config/zstd.m4

diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index a5652b2a9c7..98a487b7fcd 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -57,7 +57,7 @@ ZLIBINC = @zlibinc@
 
 WARN_CFLAGS = @WARN_CFLAGS@
 NO_WERROR = @NO_WERROR@
-AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
+AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
 AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DLIBDIR='"$(libdir)"' @LARGEFILE_CPPFLAGS@
 if PLUGINS
 bfdinclude_HEADERS += $(INCDIR)/plugin-api.h
@@ -776,7 +776,7 @@ ofiles: stamp-ofiles ; @true
 libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
 EXTRA_libbfd_la_SOURCES = $(CFILES)
 libbfd_la_DEPENDENCIES = $(OFILES) ofiles
-libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB)
+libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS)
 libbfd_la_LDFLAGS += -release `cat libtool-soversion` @SHARED_LDFLAGS@
 
 # libtool will build .libs/libbfd.a.  We create libbfd.a in the build
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index 83d686529a0..3c9ebf38f83 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -122,10 +122,12 @@ am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
 	$(top_srcdir)/../config/nls.m4 \
 	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/pkg.m4 \
 	$(top_srcdir)/../config/plugins.m4 \
 	$(top_srcdir)/../config/po.m4 \
 	$(top_srcdir)/../config/progtest.m4 \
-	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../config/zlib.m4 \
+	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
 	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
 	$(top_srcdir)/bfd.m4 $(top_srcdir)/warning.m4 \
@@ -399,6 +401,9 @@ PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
 PKGVERSION = @PKGVERSION@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
 POSUB = @POSUB@
 RANLIB = @RANLIB@
 REPORT_BUGS_TEXI = @REPORT_BUGS_TEXI@
@@ -416,6 +421,8 @@ WARN_CFLAGS = @WARN_CFLAGS@
 WARN_CFLAGS_FOR_BUILD = @WARN_CFLAGS_FOR_BUILD@
 WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
 XGETTEXT = @XGETTEXT@
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
@@ -520,7 +527,7 @@ libbfd_la_LDFLAGS = $(am__append_1) -release `cat libtool-soversion` \
 # case both are empty.
 ZLIB = @zlibdir@ -lz
 ZLIBINC = @zlibinc@
-AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
+AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
 AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DLIBDIR='"$(libdir)"' \
 	@LARGEFILE_CPPFLAGS@ @HDEFINES@ @COREFLAG@ @TDEFINES@ \
 	$(CSEARCH) $(CSWITCHES) $(HAVEVECS) @INCINTL@
@@ -1199,7 +1206,7 @@ OFILES = $(BFD_BACKENDS) $(BFD_MACHINES) @COREFILE@ @bfd64_libs@
 libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
 EXTRA_libbfd_la_SOURCES = $(CFILES)
 libbfd_la_DEPENDENCIES = $(OFILES) ofiles
-libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB)
+libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS)
 
 # libtool will build .libs/libbfd.a.  We create libbfd.a in the build
 # directory so that we don't have to convert all the programs that use
diff --git a/bfd/aclocal.m4 b/bfd/aclocal.m4
index 0f8aa1d4518..09b849dfc87 100644
--- a/bfd/aclocal.m4
+++ b/bfd/aclocal.m4
@@ -1176,10 +1176,12 @@ m4_include([../config/largefile.m4])
 m4_include([../config/lead-dot.m4])
 m4_include([../config/nls.m4])
 m4_include([../config/override.m4])
+m4_include([../config/pkg.m4])
 m4_include([../config/plugins.m4])
 m4_include([../config/po.m4])
 m4_include([../config/progtest.m4])
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index 8605056aefe..4765ea80536 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -342,7 +342,8 @@ enum compressed_debug_section_type
   COMPRESS_DEBUG_NONE = 0,
   COMPRESS_DEBUG = 1 << 0,
   COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1,
-  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2
+  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2,
+  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3
 };
 
 /* This structure is used to keep track of stabs in sections
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 79fcc4eb912..5c80956c79c 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -349,7 +349,8 @@ enum compressed_debug_section_type
   COMPRESS_DEBUG_NONE = 0,
   COMPRESS_DEBUG = 1 << 0,
   COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1,
-  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2
+  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2,
+  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3
 };
 
 /* This structure is used to keep track of stabs in sections
@@ -962,7 +963,8 @@ typedef struct bfd_section
   unsigned int compress_status : 2;
 #define COMPRESS_SECTION_NONE    0
 #define COMPRESS_SECTION_DONE    1
-#define DECOMPRESS_SECTION_SIZED 2
+#define DECOMPRESS_SECTION_ZLIB  2
+#define DECOMPRESS_SECTION_ZSTD  3
 
   /* The following flags are used by the ELF linker. */
 
@@ -6637,12 +6639,14 @@ struct bfd
 #define BFD_ARCHIVE_FULL_PATH  0x100000
 
 #define BFD_CLOSED_BY_CACHE    0x200000
+  /* Compress sections in this BFD with SHF_COMPRESSED zstd.  */
+#define BFD_COMPRESS_ZSTD      0x400000
 
   /* Flags bits to be saved in bfd_preserve_save.  */
 #define BFD_FLAGS_SAVED \
   (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
    | BFD_PLUGIN | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON \
-   | BFD_USE_ELF_STT_COMMON)
+   | BFD_USE_ELF_STT_COMMON | BFD_COMPRESS_ZSTD)
 
   /* Flags bits which are for BFD use only.  */
 #define BFD_FLAGS_FOR_BFD_USE_MASK \
@@ -7271,6 +7275,7 @@ void bfd_update_compression_header
 
 bool bfd_check_compression_header
    (bfd *abfd, bfd_byte *contents, asection *sec,
+    unsigned int *ch_type,
     bfd_size_type *uncompressed_size,
     unsigned int *uncompressed_alignment_power);
 
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 0a21db11fd6..5f2033bee7a 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -177,12 +177,15 @@ CODE_FRAGMENT
 .#define BFD_ARCHIVE_FULL_PATH  0x100000
 .
 .#define BFD_CLOSED_BY_CACHE    0x200000
+
+.  {* Compress sections in this BFD with SHF_COMPRESSED zstd.  *}
+.#define BFD_COMPRESS_ZSTD      0x400000
 .
 .  {* Flags bits to be saved in bfd_preserve_save.  *}
 .#define BFD_FLAGS_SAVED \
 .  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
 .   | BFD_PLUGIN | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON \
-.   | BFD_USE_ELF_STT_COMMON)
+.   | BFD_USE_ELF_STT_COMMON | BFD_COMPRESS_ZSTD)
 .
 .  {* Flags bits which are for BFD use only.  *}
 .#define BFD_FLAGS_FOR_BFD_USE_MASK \
@@ -2500,6 +2503,9 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
 	{
 	  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 	  struct bfd_elf_section_data * esd = elf_section_data (sec);
+	  const unsigned int ch_type = abfd->flags & BFD_COMPRESS_ZSTD
+					   ? ELFCOMPRESS_ZSTD
+					   : ELFCOMPRESS_ZLIB;
 
 	  /* Set the SHF_COMPRESSED bit.  */
 	  elf_section_flags (sec) |= SHF_COMPRESSED;
@@ -2507,7 +2513,7 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
 	  if (bed->s->elfclass == ELFCLASS32)
 	    {
 	      Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) contents;
-	      bfd_put_32 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+	      bfd_put_32 (abfd, ch_type, &echdr->ch_type);
 	      bfd_put_32 (abfd, sec->size, &echdr->ch_size);
 	      bfd_put_32 (abfd, 1u << sec->alignment_power,
 			  &echdr->ch_addralign);
@@ -2518,7 +2524,7 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
 	  else
 	    {
 	      Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) contents;
-	      bfd_put_32 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+	      bfd_put_32 (abfd, ch_type, &echdr->ch_type);
 	      bfd_put_32 (abfd, 0, &echdr->ch_reserved);
 	      bfd_put_64 (abfd, sec->size, &echdr->ch_size);
 	      bfd_put_64 (abfd, UINT64_C (1) << sec->alignment_power,
@@ -2553,14 +2559,15 @@ bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
    SYNOPSIS
 	bool bfd_check_compression_header
 	  (bfd *abfd, bfd_byte *contents, asection *sec,
+	  unsigned int *ch_type,
 	  bfd_size_type *uncompressed_size,
 	  unsigned int *uncompressed_alignment_power);
 
 DESCRIPTION
-	Check the compression header at CONTENTS of SEC in ABFD and
-	store the uncompressed size in UNCOMPRESSED_SIZE and the
-	uncompressed data alignment in UNCOMPRESSED_ALIGNMENT_POWER
-	if the compression header is valid.
+	Check the compression header at CONTENTS of SEC in ABFD and store the
+	ch_type in CH_TYPE, uncompressed size in UNCOMPRESSED_SIZE, and the
+	uncompressed data alignment in UNCOMPRESSED_ALIGNMENT_POWER if the
+	compression header is valid.
 
 RETURNS
 	Return TRUE if the compression header is valid.
@@ -2569,6 +2576,7 @@ RETURNS
 bool
 bfd_check_compression_header (bfd *abfd, bfd_byte *contents,
 			      asection *sec,
+			      unsigned int *ch_type,
 			      bfd_size_type *uncompressed_size,
 			      unsigned int *uncompressed_alignment_power)
 {
@@ -2591,7 +2599,9 @@ bfd_check_compression_header (bfd *abfd, bfd_byte *contents,
 	  chdr.ch_size = bfd_get_64 (abfd, &echdr->ch_size);
 	  chdr.ch_addralign = bfd_get_64 (abfd, &echdr->ch_addralign);
 	}
-      if (chdr.ch_type == ELFCOMPRESS_ZLIB
+      *ch_type = chdr.ch_type;
+      if ((chdr.ch_type == ELFCOMPRESS_ZLIB
+	   || chdr.ch_type == ELFCOMPRESS_ZSTD)
 	  && chdr.ch_addralign == (chdr.ch_addralign & -chdr.ch_addralign))
 	{
 	  *uncompressed_size = chdr.ch_size;
diff --git a/bfd/compress.c b/bfd/compress.c
index b2e39826e38..95c1f4c42d1 100644
--- a/bfd/compress.c
+++ b/bfd/compress.c
@@ -20,18 +20,31 @@
 
 #include "sysdep.h"
 #include <zlib.h>
+#ifdef HAVE_ZSTD
+#include <zstd.h>
+#endif
 #include "bfd.h"
+#include "elf-bfd.h"
 #include "libbfd.h"
 #include "safe-ctype.h"
 
 #define MAX_COMPRESSION_HEADER_SIZE 24
 
 static bool
-decompress_contents (bfd_byte *compressed_buffer,
+decompress_contents (bool is_zstd, bfd_byte *compressed_buffer,
 		     bfd_size_type compressed_size,
 		     bfd_byte *uncompressed_buffer,
 		     bfd_size_type uncompressed_size)
 {
+  if (is_zstd)
+    {
+#ifdef HAVE_ZSTD
+      size_t ret = ZSTD_decompress (uncompressed_buffer, uncompressed_size,
+				    compressed_buffer, compressed_size);
+      return !ZSTD_isError (ret);
+#endif
+    }
+
   z_stream strm;
   int rc;
 
@@ -69,7 +82,7 @@ decompress_contents (bfd_byte *compressed_buffer,
 }
 
 /* Compress data of the size specified in @var{uncompressed_size}
-   and pointed to by @var{uncompressed_buffer} using zlib and store
+   and pointed to by @var{uncompressed_buffer} using zlib/zstd and store
    as the contents field.  This function assumes the contents
    field was allocated using bfd_malloc() or equivalent.
 
@@ -150,9 +163,10 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
       sec->size = orig_uncompressed_size;
       if (decompress)
 	{
-	  if (!decompress_contents (uncompressed_buffer
-				    + orig_compression_header_size,
-				    zlib_size, buffer, buffer_size))
+	  if (!decompress_contents (
+		  sec->compress_status == DECOMPRESS_SECTION_ZSTD,
+		  uncompressed_buffer + orig_compression_header_size,
+		  zlib_size, buffer, buffer_size))
 	    {
 	      bfd_set_error (bfd_error_bad_value);
 	      bfd_release (abfd, buffer);
@@ -175,10 +189,23 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
     }
   else
     {
-      if (compress ((Bytef*) buffer + header_size,
-		    &compressed_size,
-		    (const Bytef*) uncompressed_buffer,
-		    uncompressed_size) != Z_OK)
+      if (abfd->flags & BFD_COMPRESS_ZSTD)
+	{
+#if HAVE_ZSTD
+	  compressed_size = ZSTD_compress (
+		  buffer + header_size, compressed_size, uncompressed_buffer,
+		  uncompressed_size, ZSTD_CLEVEL_DEFAULT);
+	  if (ZSTD_isError (compressed_size))
+	    {
+	      bfd_release (abfd, buffer);
+	      bfd_set_error (bfd_error_bad_value);
+	      return 0;
+	    }
+#endif
+	}
+      else if (compress ((Bytef *)buffer + header_size, &compressed_size,
+			 (const Bytef *)uncompressed_buffer, uncompressed_size)
+	       != Z_OK)
 	{
 	  bfd_release (abfd, buffer);
 	  bfd_set_error (bfd_error_bad_value);
@@ -237,6 +264,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
   bfd_size_type save_rawsize;
   bfd_byte *compressed_buffer;
   unsigned int compression_header_size;
+  const unsigned int compress_status = sec->compress_status;
 
   if (abfd->direction != write_direction && sec->rawsize != 0)
     sz = sec->rawsize;
@@ -248,7 +276,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
       return true;
     }
 
-  switch (sec->compress_status)
+  switch (compress_status)
     {
     case COMPRESS_SECTION_NONE:
       if (p == NULL)
@@ -298,7 +326,8 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
       *ptr = p;
       return true;
 
-    case DECOMPRESS_SECTION_SIZED:
+    case DECOMPRESS_SECTION_ZLIB:
+    case DECOMPRESS_SECTION_ZSTD:
       /* Read in the full compressed section contents.  */
       compressed_buffer = (bfd_byte *) bfd_malloc (sec->compressed_size);
       if (compressed_buffer == NULL)
@@ -316,7 +345,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
       /* Restore rawsize and size.  */
       sec->rawsize = save_rawsize;
       sec->size = save_size;
-      sec->compress_status = DECOMPRESS_SECTION_SIZED;
+      sec->compress_status = compress_status;
       if (!ret)
 	goto fail_compressed;
 
@@ -330,8 +359,10 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
 	/* Set header size to the zlib header size if it is a
 	   SHF_COMPRESSED section.  */
 	compression_header_size = 12;
-      if (!decompress_contents (compressed_buffer + compression_header_size,
-				sec->compressed_size - compression_header_size, p, sz))
+      if (!decompress_contents (compress_status == DECOMPRESS_SECTION_ZSTD,
+				compressed_buffer + compression_header_size,
+				sec->compressed_size - compression_header_size,
+				p, sz))
 	{
 	  bfd_set_error (bfd_error_bad_value);
 	  if (p != *ptr)
@@ -381,7 +412,8 @@ DESCRIPTION
 void
 bfd_cache_section_contents (asection *sec, void *contents)
 {
-  if (sec->compress_status == DECOMPRESS_SECTION_SIZED)
+  if (sec->compress_status == DECOMPRESS_SECTION_ZLIB
+      || sec->compress_status == DECOMPRESS_SECTION_ZSTD)
     sec->compress_status = COMPRESS_SECTION_DONE;
   sec->contents = contents;
   sec->flags |= SEC_IN_MEMORY;
@@ -418,6 +450,7 @@ bfd_is_section_compressed_with_header (bfd *abfd, sec_ptr sec,
   int compression_header_size;
   int header_size;
   unsigned int saved = sec->compress_status;
+  unsigned int ch_type;
   bool compressed;
 
   *uncompressed_align_pow_p = 0;
@@ -448,7 +481,7 @@ bfd_is_section_compressed_with_header (bfd *abfd, sec_ptr sec,
     {
       if (compression_header_size != 0)
 	{
-	  if (!bfd_check_compression_header (abfd, header, sec,
+	  if (!bfd_check_compression_header (abfd, header, sec, &ch_type,
 					     uncompressed_size_p,
 					     uncompressed_align_pow_p))
 	    compression_header_size = -1;
@@ -507,7 +540,7 @@ SYNOPSIS
 DESCRIPTION
 	Record compressed section size, update section size with
 	decompressed size and set compress_status to
-	DECOMPRESS_SECTION_SIZED.
+	DECOMPRESS_SECTION_{ZLIB,ZSTD}.
 
 	Return @code{FALSE} if the section is not a valid compressed
 	section.  Otherwise, return @code{TRUE}.
@@ -521,6 +554,7 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
   int header_size;
   bfd_size_type uncompressed_size;
   unsigned int uncompressed_alignment_power = 0;
+  unsigned int ch_type;
   z_stream strm;
 
   compression_header_size = bfd_get_compression_header_size (abfd, sec);
@@ -550,6 +584,7 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
       uncompressed_size = bfd_getb64 (header + 4);
     }
   else if (!bfd_check_compression_header (abfd, header, sec,
+					  &ch_type,
 					  &uncompressed_size,
 					  &uncompressed_alignment_power))
     {
@@ -569,7 +604,8 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
   sec->compressed_size = sec->size;
   sec->size = uncompressed_size;
   bfd_set_section_alignment (sec, uncompressed_alignment_power);
-  sec->compress_status = DECOMPRESS_SECTION_SIZED;
+  sec->compress_status = ch_type == ELFCOMPRESS_ZSTD ? DECOMPRESS_SECTION_ZSTD
+						     : DECOMPRESS_SECTION_ZLIB;
 
   return true;
 }
diff --git a/bfd/config.in b/bfd/config.in
index f54a3cacbea..a59304e0a66 100644
--- a/bfd/config.in
+++ b/bfd/config.in
@@ -232,6 +232,9 @@
 /* Define to 1 if you have the <windows.h> header file. */
 #undef HAVE_WINDOWS_H
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Define to the sub-directory in which libtool stores uninstalled libraries.
    */
 #undef LT_OBJDIR
diff --git a/bfd/configure b/bfd/configure
index 075d2ee0a1b..d905a7bf7a8 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -652,6 +652,11 @@ TDEFINES
 SHARED_LIBADD
 SHARED_LDFLAGS
 LIBM
+ZSTD_LIBS
+ZSTD_CFLAGS
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
 zlibinc
 zlibdir
 EXEEXT_FOR_BUILD
@@ -839,6 +844,7 @@ enable_maintainer_mode
 enable_install_libbfd
 enable_nls
 with_system_zlib
+with_zstd
 '
       ac_precious_vars='build_alias
 host_alias
@@ -848,7 +854,12 @@ CFLAGS
 LDFLAGS
 LIBS
 CPPFLAGS
-CPP'
+CPP
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
+ZSTD_CFLAGS
+ZSTD_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1511,6 +1522,8 @@ Optional Packages:
                           Binutils"
   --with-bugurl=URL       Direct users to URL to report a bug
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
 
 Some influential environment variables:
   CC          C compiler command
@@ -1521,6 +1534,13 @@ Some influential environment variables:
   CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
               you have headers in a nonstandard directory <include dir>
   CPP         C preprocessor
+  PKG_CONFIG  path to pkg-config utility
+  PKG_CONFIG_PATH
+              directories to add to pkg-config's search path
+  PKG_CONFIG_LIBDIR
+              path overriding pkg-config's built-in search path
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -11086,7 +11106,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11089 "configure"
+#line 11109 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11192,7 +11212,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11195 "configure"
+#line 11215 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12995,7 +13015,7 @@ $as_echo "#define USE_BINARY_FOPEN 1" >>confdefs.h
  ;;
 esac
 
-# Link in zlib if we can.  This allows us to read compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to read compressed debug sections.
 # This is used only by compress.c.
 
   # Use the system's zlib library.
@@ -13015,6 +13035,246 @@ fi
 
 
 
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=0.9.0
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	else
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		PKG_CONFIG=""
+	fi
+fi
+
+
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if test "$with_zstd" != no; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+fi
+
+
 save_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS -Werror"
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking compiler support for hidden visibility" >&5
diff --git a/bfd/configure.ac b/bfd/configure.ac
index 28f3d1afce6..d1b2f76b31a 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -230,9 +230,10 @@ AC_CHECK_DECLS([basename, ffs, stpcpy, asprintf, vasprintf, strnlen])
 
 BFD_BINARY_FOPEN
 
-# Link in zlib if we can.  This allows us to read compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to read compressed debug sections.
 # This is used only by compress.c.
 AM_ZLIB
+AM_ZSTD
 
 save_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS -Werror"
diff --git a/bfd/elf.c b/bfd/elf.c
index 9a0bc1d2740..9d34781a97c 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1260,6 +1260,18 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
 		 abfd, name);
 	      return false;
 	    }
+#ifndef HAVE_ZSTD
+	  if (newsect->compress_status == DECOMPRESS_SECTION_ZSTD)
+	    {
+	      _bfd_error_handler
+		  /* xgettext:c-format */
+		  (_ ("%pB: section %s is compressed with zstd, but BFD "
+		      "is not built with zstd support"),
+		   abfd, name);
+	      newsect->compress_status = COMPRESS_SECTION_NONE;
+	      return false;
+	    }
+#endif
 	}
 
       if (abfd->is_linker_input)
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index feaba84bf2e..ca600bb5ddf 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -989,7 +989,8 @@ const bfd_target TARGET_BIG_SYM =
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS
    | DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS
-   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON),
+   | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD | BFD_CONVERT_ELF_COMMON
+   | BFD_USE_ELF_STT_COMMON),
 
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY
@@ -1093,7 +1094,8 @@ const bfd_target TARGET_LITTLE_SYM =
   /* object_flags: mask of all file flags */
   (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS
    | DYNAMIC | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS
-   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON),
+   | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD | BFD_CONVERT_ELF_COMMON
+   | BFD_USE_ELF_STT_COMMON),
 
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY
diff --git a/bfd/section.c b/bfd/section.c
index c7a02d729f2..614570e976e 100644
--- a/bfd/section.c
+++ b/bfd/section.c
@@ -392,7 +392,8 @@ CODE_FRAGMENT
 .  unsigned int compress_status : 2;
 .#define COMPRESS_SECTION_NONE    0
 .#define COMPRESS_SECTION_DONE    1
-.#define DECOMPRESS_SECTION_SIZED 2
+.#define DECOMPRESS_SECTION_ZLIB  2
+.#define DECOMPRESS_SECTION_ZSTD  3
 .
 .  {* The following flags are used by the ELF linker. *}
 .
diff --git a/binutils/Makefile.in b/binutils/Makefile.in
index 78d32b350e3..6de4e239408 100644
--- a/binutils/Makefile.in
+++ b/binutils/Makefile.in
@@ -156,7 +156,8 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/plugins.m4 \
 	$(top_srcdir)/../config/po.m4 \
 	$(top_srcdir)/../config/progtest.m4 \
-	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../config/zlib.m4 \
+	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
 	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
 	$(top_srcdir)/../bfd/version.m4 \
@@ -575,6 +576,8 @@ WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
 XGETTEXT = @XGETTEXT@
 YACC = `if [ -f ../bison/bison ]; then echo ../bison/bison -y -L$(srcdir)/../bison/; else echo @YACC@; fi`
 YFLAGS = -d
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
diff --git a/binutils/NEWS b/binutils/NEWS
index 8c2c416c17e..83c73d0660a 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -1,5 +1,11 @@
 -*- text -*-
 
+* objcopy --decompress-debug-sections now supports zstd compressed debug
+  sections.  The new option --compress-debug-sections=zstd compresses debug
+  sections with zstd.
+
+* addr2line and objdump --dwarf now support zstd compressed debug sections.
+
 * The dlltool program now accepts --deterministic-libraries and
   --non-deterministic-libraries as command line options to control whether or
   not it generates deterministic output libraries.  If neither of these options
diff --git a/binutils/aclocal.m4 b/binutils/aclocal.m4
index a877fa7f873..28271f56279 100644
--- a/binutils/aclocal.m4
+++ b/binutils/aclocal.m4
@@ -1205,6 +1205,7 @@ m4_include([../config/plugins.m4])
 m4_include([../config/po.m4])
 m4_include([../config/progtest.m4])
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/binutils/config.in b/binutils/config.in
index c5fb919aa95..bee8c07e2f7 100644
--- a/binutils/config.in
+++ b/binutils/config.in
@@ -157,6 +157,9 @@
 /* Define to 1 if you have the <windows.h> header file. */
 #undef HAVE_WINDOWS_H
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Define as const if the declaration of iconv() needs const. */
 #undef ICONV_CONST
 
diff --git a/binutils/configure b/binutils/configure
index 4c0c391e9d5..5f68fed3f94 100755
--- a/binutils/configure
+++ b/binutils/configure
@@ -650,6 +650,8 @@ LTLIBICONV
 LIBICONV
 MSGPACK_LIBS
 MSGPACK_CFLAGS
+ZSTD_LIBS
+ZSTD_CFLAGS
 zlibinc
 zlibdir
 DEMANGLER_NAME
@@ -832,6 +834,7 @@ enable_build_warnings
 enable_nls
 enable_maintainer_mode
 with_system_zlib
+with_zstd
 with_msgpack
 enable_rpath
 with_libiconv_prefix
@@ -853,6 +856,8 @@ DEBUGINFOD_CFLAGS
 DEBUGINFOD_LIBS
 YACC
 YFLAGS
+ZSTD_CFLAGS
+ZSTD_LIBS
 MSGPACK_CFLAGS
 MSGPACK_LIBS'
 
@@ -1517,6 +1522,8 @@ Optional Packages:
   --with-debuginfod       Enable debuginfo lookups with debuginfod
                           (auto/yes/no)
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
   --with-msgpack          Enable msgpack support (auto/yes/no)
   --with-gnu-ld           assume the C compiler uses GNU ld default=no
   --with-libiconv-prefix[=DIR]  search for libiconv in DIR/include and DIR/lib
@@ -1547,6 +1554,8 @@ Some influential environment variables:
   YFLAGS      The list of arguments that will be passed by default to $YACC.
               This script will default YFLAGS to the empty string to avoid a
               default value of `-d' given by some make applications.
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
   MSGPACK_CFLAGS
               C compiler flags for MSGPACK, overriding pkg-config
   MSGPACK_LIBS
@@ -10804,7 +10813,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10807 "configure"
+#line 10816 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10910,7 +10919,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10913 "configure"
+#line 10922 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13468,7 +13477,7 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-# Link in zlib if we can.  This allows us to read compressed debug
+# Link in zlib/zstd if we can.  This allows us to read compressed debug
 # sections.  This is used only by readelf.c (objdump uses bfd for
 # reading compressed sections).
 
@@ -13490,6 +13499,127 @@ fi
 
 
 
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if "$with_zstd" != no; then :
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+
+fi
+
+
+
 case "${host}" in
 *-*-msdos* | *-*-go32* | *-*-mingw32* | *-*-cygwin* | *-*-windows*)
 
diff --git a/binutils/configure.ac b/binutils/configure.ac
index 0798d84f4d1..01cf8882be4 100644
--- a/binutils/configure.ac
+++ b/binutils/configure.ac
@@ -265,10 +265,11 @@ fi
 
 AC_CHECK_DECLS([asprintf, environ, getc_unlocked, stpcpy, strnlen])
 
-# Link in zlib if we can.  This allows us to read compressed debug
+# Link in zlib/zstd if we can.  This allows us to read compressed debug
 # sections.  This is used only by readelf.c (objdump uses bfd for
 # reading compressed sections).
 AM_ZLIB
+AM_ZSTD
 
 BFD_BINARY_FOPEN
 
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 1499db5728c..34a4164eb94 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -2159,21 +2159,23 @@ ELF ABI.  Note - if compression would actually make a section
 @itemx --compress-debug-sections=zlib
 @itemx --compress-debug-sections=zlib-gnu
 @itemx --compress-debug-sections=zlib-gabi
+@itemx --compress-debug-sections=zstd
 For ELF files, these options control how DWARF debug sections are
 compressed.  @option{--compress-debug-sections=none} is equivalent
 to @option{--decompress-debug-sections}.
 @option{--compress-debug-sections=zlib} and
 @option{--compress-debug-sections=zlib-gabi} are equivalent to
 @option{--compress-debug-sections}.
-@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug
-sections using zlib.  The debug sections are renamed to begin with
-@samp{.zdebug} instead of @samp{.debug}.  Note - if compression would
-actually make a section @emph{larger}, then it is not compressed nor
-renamed.
+@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug sections
+using the obsoleted zlib-gnu format.  The debug sections are renamed to begin
+with @samp{.zdebug}.
+@option{--compress-debug-sections=zstd} compresses DWARF debug
+sections using zstd.  Note - if compression would actually make a section
+@emph{larger}, then it is not compressed nor renamed.
 
 @item --decompress-debug-sections
-Decompress DWARF debug sections using zlib.  The original section
-names of the compressed sections are restored.
+Decompress DWARF debug sections.  For a @samp{.zdebug} section, the original
+name is restored.
 
 @item --elf-stt-common=yes
 @itemx --elf-stt-common=no
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index 43261756a42..fc668f00bbc 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -232,7 +232,8 @@ static enum
   compress_zlib = compress | 1 << 1,
   compress_gnu_zlib = compress | 1 << 2,
   compress_gabi_zlib = compress | 1 << 3,
-  decompress = 1 << 4
+  compress_zstd = compress | 1 << 4,
+  decompress = 1 << 5
 } do_debug_sections = nothing;
 
 /* Whether to generate ELF common symbols with the STT_COMMON type.  */
@@ -678,8 +679,8 @@ copy_usage (FILE *stream, int exit_status)
                                    <commit>\n\
      --subsystem <name>[:<version>]\n\
                                    Set PE subsystem to <name> [& <version>]\n\
-     --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
-                                   Compress DWARF debug sections using zlib\n\
+     --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
+				   Compress DWARF debug sections\n\
      --decompress-debug-sections   Decompress DWARF debug sections using zlib\n\
      --elf-stt-common=[yes|no]     Generate ELF common symbols with STT_COMMON\n\
                                      type\n\
@@ -2659,7 +2660,8 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
       if ((do_debug_sections & compress) != 0
 	  && do_debug_sections != compress)
 	{
-	  non_fatal (_("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi] is unsupported on `%s'"),
+	  non_fatal (_ ("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi|"
+			"zstd] is unsupported on `%s'"),
 		     bfd_get_archive_filename (ibfd));
 	  return false;
 	}
@@ -3807,6 +3809,13 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
       if (do_debug_sections != compress_gnu_zlib)
 	ibfd->flags |= BFD_COMPRESS_GABI;
       break;
+    case compress_zstd:
+      ibfd->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD;
+#ifndef HAVE_ZSTD
+      fatal (_ ("--compress-debug-sections=zstd: binutils is not built with "
+		"zstd support"));
+#endif
+      break;
     case decompress:
       ibfd->flags |= BFD_DECOMPRESS;
       break;
@@ -5469,6 +5478,8 @@ copy_main (int argc, char *argv[])
 		do_debug_sections = compress_gnu_zlib;
 	      else if (strcasecmp (optarg, "zlib-gabi") == 0)
 		do_debug_sections = compress_gabi_zlib;
+	      else if (strcasecmp (optarg, "zstd") == 0)
+		do_debug_sections = compress_zstd;
 	      else
 		fatal (_("unrecognized --compress-debug-sections type `%s'"),
 		       optarg);
diff --git a/binutils/testsuite/binutils-all/compress.exp b/binutils/testsuite/binutils-all/compress.exp
index c88da74a987..4e74c824664 100644
--- a/binutils/testsuite/binutils-all/compress.exp
+++ b/binutils/testsuite/binutils-all/compress.exp
@@ -576,6 +576,50 @@ if { [regexp_diff objdump.out $srcdir/$subdir/dw2-3gabi.W] } then {
     pass "$testname"
 }
 
+if { [binutils_assemble_flags $srcdir/$subdir/dw2-1.S ${compressedfile}zstd.o --compress-debug-sections=zstd] } then {
+    set testname "objcopy compress debug sections with zstd"
+    set got [binutils_run $OBJCOPY "--compress-debug-sections=zstd ${testfile}.o ${copyfile}zstd.o"]
+    if ![string match "" $got] then {
+	fail "objcopy ($testname)"
+	return
+    }
+    send_log "cmp ${compressedfile}zstd.o ${copyfile}zstd.o\n"
+    verbose "cmp ${compressedfile}zstd.o ${copyfile}zstd.o"
+    set src1 ${compressedfile}zstd.o
+    set src2 ${copyfile}zstd.o
+    set status [remote_exec build cmp "${src1} ${src2}"]
+    set exec_output [lindex $status 1]
+    set exec_output [prune_warnings $exec_output]
+    if ![string match "" $exec_output] then {
+	send_log "$exec_output\n"
+	verbose "$exec_output" 1
+	fail "objcopy ($testname)"
+    } else {
+	pass "objcopy ($testname)"
+    }
+
+    set testname "objcopy decompress compressed debug sections with zstd"
+    set got [binutils_run $OBJCOPY "--decompress-debug-sections ${compressedfile}zstd.o ${copyfile}zstd.o"]
+    if ![string match "" $got] then {
+	fail "objcopy ($testname)"
+	return
+    }
+    send_log "cmp ${testfile}.o ${copyfile}zstd.o\n"
+    verbose "cmp ${testfile}.o ${copyfile}zstd.o"
+    set src1 ${testfile}.o
+    set src2 ${copyfile}zstd.o
+    set status [remote_exec build cmp "${src1} ${src2}"]
+    set exec_output [lindex $status 1]
+    set exec_output [prune_warnings $exec_output]
+    if ![string match "" $exec_output] then {
+	send_log "$exec_output\n"
+	verbose "$exec_output" 1
+	fail "objcopy ($testname)"
+    } else {
+	pass "objcopy ($testname)"
+    }
+}
+
 proc convert_test { testname  as_flags  objcop_flags } {
     global srcdir
     global subdir
diff --git a/config/zstd.m4 b/config/zstd.m4
new file mode 100644
index 00000000000..4a20c49a2ef
--- /dev/null
+++ b/config/zstd.m4
@@ -0,0 +1,23 @@
+dnl Copyright (C) 2022 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl Enable features using the zstd library.
+AC_DEFUN([AM_ZSTD], [
+AC_ARG_WITH(zstd,
+  [AS_HELP_STRING([--with-zstd], [support zstd compressed debug sections (default=auto)])],
+  [], [with_zstd=auto])
+
+AS_IF(["$with_zstd" != no],
+  [PKG_CHECK_MODULES(ZSTD, [libzstd], [
+    AC_DEFINE(HAVE_ZSTD, 1, [Define to 1 if zstd is enabled.])
+  ], [
+    if test "$with_zstd" = yes; then
+      AC_MSG_ERROR([--with-zstd was given, but pkgconfig/libzstd.pc is not found])
+    fi
+  ])
+  ])
+])
diff --git a/configure b/configure
index d75f47a1e95..f14e0efd675 100755
--- a/configure
+++ b/configure
@@ -785,6 +785,7 @@ ac_user_opts='
 enable_option_checking
 with_build_libsubdir
 with_system_zlib
+with_zstd
 enable_as_accelerator_for
 enable_offload_targets
 enable_gold
@@ -1567,6 +1568,8 @@ Optional Packages:
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
   --with-build-libsubdir=DIR  Directory where to find libraries for build system
   --with-system-zlib      use installed libz
+  --with-zstd             Support zstd compressed debug sections
+                          (default=auto)
   --with-mpc=PATH         specify prefix directory for installed MPC package.
                           Equivalent to --with-mpc-include=PATH/include plus
                           --with-mpc-lib=PATH/lib
@@ -2925,6 +2928,13 @@ if test x$with_system_zlib = xyes ; then
   noconfigdirs="$noconfigdirs zlib"
 fi
 
+
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+fi
+
+
 # Don't compile the bundled readline/libreadline.a if --with-system-readline
 # is provided.
 if test x$with_system_readline = xyes ; then
diff --git a/configure.ac b/configure.ac
index ae18d436aca..0152c69292e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -246,6 +246,9 @@ if test x$with_system_zlib = xyes ; then
   noconfigdirs="$noconfigdirs zlib"
 fi
 
+AC_ARG_WITH(zstd,
+[AS_HELP_STRING([--with-zstd], [Support zstd compressed debug sections (default=auto)])])
+
 # Don't compile the bundled readline/libreadline.a if --with-system-readline
 # is provided.
 if test x$with_system_readline = xyes ; then
diff --git a/gas/Makefile.am b/gas/Makefile.am
index bd597398671..5f0f24abf8d 100644
--- a/gas/Makefile.am
+++ b/gas/Makefile.am
@@ -42,7 +42,7 @@ am__skipyacc =
 
 WARN_CFLAGS = @WARN_CFLAGS@ @WARN_WRITE_STRINGS@
 NO_WERROR = @NO_WERROR@
-AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
+AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
 
 TARG_CPU = @target_cpu_type@
 TARG_CPU_C = $(srcdir)/config/tc-@target_cpu_type@.c
@@ -407,7 +407,7 @@ STAGESTUFF = *.@OBJEXT@ $(noinst_PROGRAMS)
 
 as_new_SOURCES = $(GAS_CFILES)
 as_new_LDADD = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
-	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB)
+	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB) $(ZSTD_LIBS)
 as_new_DEPENDENCIES = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
 	$(extra_objects) $(GASLIBS) $(LIBINTL_DEP)
 EXTRA_as_new_SOURCES = $(CFILES) $(HFILES) $(TARGET_CPU_CFILES) \
diff --git a/gas/Makefile.in b/gas/Makefile.in
index c57d78f82c4..5a4dd702252 100644
--- a/gas/Makefile.in
+++ b/gas/Makefile.in
@@ -140,10 +140,12 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
 	$(top_srcdir)/../config/nls.m4 \
 	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/pkg.m4 \
 	$(top_srcdir)/../config/plugins.m4 \
 	$(top_srcdir)/../config/po.m4 \
 	$(top_srcdir)/../config/progtest.m4 \
-	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../config/zlib.m4 \
+	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
 	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
 	$(top_srcdir)/acinclude.m4 $(top_srcdir)/../bfd/version.m4 \
@@ -429,6 +431,9 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
 PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
 POSUB = @POSUB@
 RANLIB = @RANLIB@
 SED = @SED@
@@ -443,6 +448,8 @@ WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
 XGETTEXT = @XGETTEXT@
 YACC = `if [ -f ../bison/bison ] ; then echo ../bison/bison -y -L../bison/bison ; else echo @YACC@ ; fi`
 YFLAGS = @YFLAGS@
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
@@ -524,7 +531,7 @@ ZLIBINC = @zlibinc@
 # maintainer mode is disabled.  Avoid this.
 am__skiplex = 
 am__skipyacc = 
-AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
+AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
 TARG_CPU = @target_cpu_type@
 TARG_CPU_C = $(srcdir)/config/tc-@target_cpu_type@.c
 TARG_CPU_O = config/tc-@target_cpu_type@.@OBJEXT@
@@ -874,7 +881,7 @@ GASLIBS = @OPCODES_LIB@ ../bfd/libbfd.la ../libiberty/libiberty.a
 STAGESTUFF = *.@OBJEXT@ $(noinst_PROGRAMS)
 as_new_SOURCES = $(GAS_CFILES)
 as_new_LDADD = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
-	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB)
+	$(extra_objects) $(GASLIBS) $(LIBINTL) $(LIBM) $(ZLIB) $(ZSTD_LIBS)
 
 as_new_DEPENDENCIES = $(TARG_CPU_O) $(OBJ_FORMAT_O) $(ATOF_TARG_O) \
 	$(extra_objects) $(GASLIBS) $(LIBINTL_DEP)
diff --git a/gas/NEWS b/gas/NEWS
index d61cdb9edd4..9a8b726b942 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* gas now supports --compress-debug-sections=zstd to compress
+  debug sections with zstd.
+
 Changes in 2.39:
 
 * Remove (rudimentary) support for the x86-64 sub-architectures Intel L1OM and
diff --git a/gas/aclocal.m4 b/gas/aclocal.m4
index 70183124da7..722030c776f 100644
--- a/gas/aclocal.m4
+++ b/gas/aclocal.m4
@@ -1196,10 +1196,12 @@ m4_include([../config/lcmessage.m4])
 m4_include([../config/lead-dot.m4])
 m4_include([../config/nls.m4])
 m4_include([../config/override.m4])
+m4_include([../config/pkg.m4])
 m4_include([../config/plugins.m4])
 m4_include([../config/po.m4])
 m4_include([../config/progtest.m4])
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/gas/as.c b/gas/as.c
index 6268779cf90..35ad6b3ab3b 100644
--- a/gas/as.c
+++ b/gas/as.c
@@ -252,14 +252,14 @@ Options:\n\
   --alternate             initially turn on alternate macro syntax\n"));
 #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
   fprintf (stream, _("\
-  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
+  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
                           compress DWARF debug sections using zlib [default]\n"));
   fprintf (stream, _("\
   --nocompress-debug-sections\n\
                           don't compress DWARF debug sections\n"));
 #else
   fprintf (stream, _("\
-  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
+  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
                           compress DWARF debug sections using zlib\n"));
   fprintf (stream, _("\
   --nocompress-debug-sections\n\
@@ -736,6 +736,15 @@ This program has absolutely no warranty.\n"));
 		flag_compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
 	      else if (strcasecmp (optarg, "zlib-gabi") == 0)
 		flag_compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
+	      else if (strcasecmp (optarg, "zstd") == 0)
+		{
+#ifdef HAVE_ZSTD
+		  flag_compress_debug = COMPRESS_DEBUG_ZSTD;
+#else
+		  as_fatal (_ ("--compress-debug-sections=zstd: gas is not "
+			       "built with zstd support"));
+#endif
+		}
 	      else
 		as_fatal (_("Invalid --compress-debug-sections option: `%s'"),
 			  optarg);
diff --git a/gas/compress-debug.c b/gas/compress-debug.c
index c80dbeec4e7..3cd175f6e57 100644
--- a/gas/compress-debug.c
+++ b/gas/compress-debug.c
@@ -21,14 +21,23 @@
 #include "config.h"
 #include <stdio.h>
 #include <zlib.h>
+#if HAVE_ZSTD
+#include <zstd.h>
+#endif
 #include "ansidecl.h"
 #include "compress-debug.h"
 
 /* Initialize the compression engine.  */
 
-struct z_stream_s *
-compress_init (void)
+void *
+compress_init (bool use_zstd)
 {
+  if (use_zstd) {
+#if HAVE_ZSTD
+    return ZSTD_createCCtx ();
+#endif
+  }
+
   static struct z_stream_s strm;
 
   strm.zalloc = NULL;
@@ -42,22 +51,37 @@ compress_init (void)
    from the engine goes into the current frag on the obstack.  */
 
 int
-compress_data (struct z_stream_s *strm, const char **next_in,
-	       int *avail_in, char **next_out, int *avail_out)
+compress_data (bool use_zstd, void *ctx, const char **next_in, int *avail_in,
+	       char **next_out, int *avail_out)
 {
-  int out_size = 0;
-  int x;
+  if (use_zstd)
+    {
+#if HAVE_ZSTD
+      ZSTD_outBuffer ob = { *next_out, *avail_out, 0 };
+      ZSTD_inBuffer ib = { *next_in, *avail_in, 0 };
+      size_t ret = ZSTD_compressStream2 (ctx, &ob, &ib, ZSTD_e_continue);
+      *next_in += ib.pos;
+      *avail_in -= ib.pos;
+      *next_out += ob.pos;
+      *avail_out -= ob.pos;
+      if (ZSTD_isError (ret))
+	return -1;
+      return (int)ob.pos;
+#endif
+    }
+
+  struct z_stream_s *strm = ctx;
 
   strm->next_in = (Bytef *) (*next_in);
   strm->avail_in = *avail_in;
   strm->next_out = (Bytef *) (*next_out);
   strm->avail_out = *avail_out;
 
-  x = deflate (strm, Z_NO_FLUSH);
+  int x = deflate (strm, Z_NO_FLUSH);
   if (x != Z_OK)
     return -1;
 
-  out_size = *avail_out - strm->avail_out;
+  int out_size = *avail_out - strm->avail_out;
   *next_in = (char *) (strm->next_in);
   *avail_in = strm->avail_in;
   *next_out = (char *) (strm->next_out);
@@ -71,10 +95,28 @@ compress_data (struct z_stream_s *strm, const char **next_in,
    needed.  */
 
 int
-compress_finish (struct z_stream_s *strm, char **next_out,
+compress_finish (bool use_zstd, void *ctx, char **next_out,
 		 int *avail_out, int *out_size)
 {
+  if (use_zstd)
+    {
+#if HAVE_ZSTD
+      ZSTD_outBuffer ob = { *next_out, *avail_out, 0 };
+      ZSTD_inBuffer ib = { 0 };
+      size_t ret = ZSTD_compressStream2 (ctx, &ob, &ib, ZSTD_e_end);
+      *out_size = ob.pos;
+      *next_out += ob.pos;
+      *avail_out -= ob.pos;
+      if (ZSTD_isError (ret))
+	return -1;
+      if (ret == 0)
+	ZSTD_freeCCtx (ctx);
+      return ret ? 1 : 0;
+#endif
+    }
+
   int x;
+  struct z_stream_s *strm = ctx;
 
   strm->avail_in = 0;
   strm->next_out = (Bytef *) (*next_out);
diff --git a/gas/compress-debug.h b/gas/compress-debug.h
index 0183e269fef..87de0f8444e 100644
--- a/gas/compress-debug.h
+++ b/gas/compress-debug.h
@@ -21,19 +21,19 @@
 #ifndef COMPRESS_DEBUG_H
 #define COMPRESS_DEBUG_H
 
+#include <stdbool.h>
+
 struct z_stream_s;
 
 /* Initialize the compression engine.  */
-extern struct z_stream_s *
-compress_init (void);
+extern void *compress_init (bool);
 
 /* Stream the contents of a frag to the compression engine.  Output
    from the engine goes into the current frag on the obstack.  */
-extern int
-compress_data (struct z_stream_s *, const char **, int *, char **, int *);
+extern int compress_data (bool, void *, const char **, int *, char **, int *);
 
 /* Finish the compression and consume the remaining compressed output.  */
 extern int
-compress_finish (struct z_stream_s *, char **, int *, int *);
+compress_finish (bool, void *, char **, int *, int *);
 
 #endif /* COMPRESS_DEBUG_H */
diff --git a/gas/config.in b/gas/config.in
index e243fd277ee..0d1668a3eac 100644
--- a/gas/config.in
+++ b/gas/config.in
@@ -134,6 +134,9 @@
 /* Define to 1 if you have the <windows.h> header file. */
 #undef HAVE_WINDOWS_H
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Using i386 COFF? */
 #undef I386COFF
 
diff --git a/gas/configure b/gas/configure
index d0449a1d7ab..c4d5ba6f994 100755
--- a/gas/configure
+++ b/gas/configure
@@ -633,6 +633,11 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+ZSTD_LIBS
+ZSTD_CFLAGS
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
 zlibinc
 zlibdir
 LIBM
@@ -817,6 +822,7 @@ with_cpu
 enable_nls
 enable_maintainer_mode
 with_system_zlib
+with_zstd
 '
       ac_precious_vars='build_alias
 host_alias
@@ -828,7 +834,12 @@ LIBS
 CPPFLAGS
 CPP
 YACC
-YFLAGS'
+YFLAGS
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
+ZSTD_CFLAGS
+ZSTD_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1493,6 +1504,8 @@ Optional Packages:
   --with-cpu=CPU          default cpu variant is CPU (currently only supported
                           on ARC)
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
 
 Some influential environment variables:
   CC          C compiler command
@@ -1509,6 +1522,13 @@ Some influential environment variables:
   YFLAGS      The list of arguments that will be passed by default to $YACC.
               This script will default YFLAGS to the empty string to avoid a
               default value of `-d' given by some make applications.
+  PKG_CONFIG  path to pkg-config utility
+  PKG_CONFIG_PATH
+              directories to add to pkg-config's search path
+  PKG_CONFIG_LIBDIR
+              path overriding pkg-config's built-in search path
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -10702,7 +10722,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10705 "configure"
+#line 10725 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10808,7 +10828,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10811 "configure"
+#line 10831 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13945,7 +13965,7 @@ $as_echo "#define USE_BINARY_FOPEN 1" >>confdefs.h
  ;;
 esac
 
-# Link in zlib if we can.  This allows us to write compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to write compressed debug sections.
 
   # Use the system's zlib library.
   zlibdir="-L\$(top_builddir)/../zlib"
@@ -13964,6 +13984,247 @@ fi
 
 
 
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=0.9.0
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	else
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		PKG_CONFIG=""
+	fi
+fi
+
+
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if "$with_zstd" != no; then :
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+
+fi
+
+
 # Support for VMS timestamps via cross compile
 
 if test "$ac_cv_header_time_h" = yes; then
diff --git a/gas/configure.ac b/gas/configure.ac
index 21795a82bdd..8750ea21381 100644
--- a/gas/configure.ac
+++ b/gas/configure.ac
@@ -1004,8 +1004,9 @@ AC_CHECK_DECLS([asprintf, mempcpy, stpcpy])
 
 BFD_BINARY_FOPEN
 
-# Link in zlib if we can.  This allows us to write compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to write compressed debug sections.
 AM_ZLIB
+AM_ZSTD
 
 # Support for VMS timestamps via cross compile
 
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index e915893da86..01f49434021 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -711,16 +711,19 @@ given section @emph{larger} then it is not compressed.
 @itemx --compress-debug-sections=zlib
 @itemx --compress-debug-sections=zlib-gnu
 @itemx --compress-debug-sections=zlib-gabi
+@itemx --compress-debug-sections=zstd
 These options control how DWARF debug sections are compressed.
 @option{--compress-debug-sections=none} is equivalent to
 @option{--nocompress-debug-sections}.
 @option{--compress-debug-sections=zlib} and
 @option{--compress-debug-sections=zlib-gabi} are equivalent to
 @option{--compress-debug-sections}.
-@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug
-sections using zlib.  The debug sections are renamed to begin with
-@samp{.zdebug}.  Note if compression would make a given section
-@emph{larger} then it is not compressed nor renamed.
+@option{--compress-debug-sections=zlib-gnu} compresses DWARF debug sections
+using the obsoleted zlib-gnu format.  The debug sections are renamed to begin
+with @samp{.zdebug}.
+@option{--compress-debug-sections=zstd} compresses DWARF debug
+sections using zstd.  Note - if compression would actually make a section
+@emph{larger}, then it is not compressed nor renamed.
 
 @end ifset
 
diff --git a/gas/write.c b/gas/write.c
index f76bbdb706e..0e49df7c03f 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -1413,7 +1413,7 @@ write_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
 }
 
 static int
-compress_frag (struct z_stream_s *strm, const char *contents, int in_size,
+compress_frag (bool use_zstd, void *ctx, const char *contents, int in_size,
 	       fragS **last_newf, struct obstack *ob)
 {
   int out_size;
@@ -1442,10 +1442,10 @@ compress_frag (struct z_stream_s *strm, const char *contents, int in_size,
 	as_fatal (_("can't extend frag"));
       next_out = obstack_next_free (ob);
       obstack_blank_fast (ob, avail_out);
-      out_size = compress_data (strm, &contents, &in_size,
-				&next_out, &avail_out);
+      out_size = compress_data (use_zstd, ctx, &contents, &in_size, &next_out,
+				&avail_out);
       if (out_size < 0)
-        return -1;
+	return -1;
 
       f->fr_fix += out_size;
       total_out_size += out_size;
@@ -1471,7 +1471,6 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   const char *section_name;
   char *compressed_name;
   char *header;
-  struct z_stream_s *strm;
   int x;
   flagword flags = bfd_section_flags (sec);
   unsigned int header_size, compression_header_size;
@@ -1485,21 +1484,22 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   if (!startswith (section_name, ".debug_"))
     return;
 
-  strm = compress_init ();
-  if (strm == NULL)
+  bool use_zstd = abfd->flags & BFD_COMPRESS_ZSTD;
+  void *ctx = compress_init (use_zstd);
+  if (ctx == NULL)
     return;
 
-  if (flag_compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
+  if (flag_compress_debug == COMPRESS_DEBUG_GNU_ZLIB)
+    {
+      compression_header_size = 0;
+      header_size = 12;
+    }
+  else
     {
       compression_header_size
 	= bfd_get_compression_header_size (stdoutput, NULL);
       header_size = compression_header_size;
     }
-  else
-    {
-      compression_header_size = 0;
-      header_size = 12;
-    }
 
   /* Create a new frag to contain the compression header.  */
   first_newf = frag_alloc (ob);
@@ -1531,7 +1531,7 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
       gas_assert (f->fr_type == rs_fill);
       if (f->fr_fix)
 	{
-	  out_size = compress_frag (strm, f->fr_literal, f->fr_fix,
+	  out_size = compress_frag (use_zstd, ctx, f->fr_literal, f->fr_fix,
 				    &last_newf, ob);
 	  if (out_size < 0)
 	    return;
@@ -1545,8 +1545,8 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
 	{
 	  while (count--)
 	    {
-	      out_size = compress_frag (strm, fill_literal, (int) fill_size,
-				        &last_newf, ob);
+	      out_size = compress_frag (use_zstd, ctx, fill_literal,
+					(int)fill_size, &last_newf, ob);
 	      if (out_size < 0)
 		return;
 	      compressed_size += out_size;
@@ -1579,7 +1579,7 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
 	as_fatal (_("can't extend frag"));
       next_out = obstack_next_free (ob);
       obstack_blank_fast (ob, avail_out);
-      x = compress_finish (strm, &next_out, &avail_out, &out_size);
+      x = compress_finish (use_zstd, ctx, &next_out, &avail_out, &out_size);
       if (x < 0)
 	return;
 
@@ -2540,6 +2540,8 @@ write_object_file (void)
     {
       if (flag_compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
 	stdoutput->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI;
+      else if (flag_compress_debug == COMPRESS_DEBUG_ZSTD)
+	stdoutput->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD;
       else
 	stdoutput->flags |= BFD_COMPRESS;
       bfd_map_over_sections (stdoutput, compress_debug, (char *) 0);
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2598b81d205..c528ee5aa80 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -173,6 +173,9 @@ BFD_CFLAGS = -I$(BFD_DIR) -I$(BFD_SRC)
 ZLIB = @zlibdir@ -lz
 ZLIBINC = @zlibinc@
 
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
+
 # Where is the decnumber library?  Typically in ../libdecnumber.
 LIBDECNUMBER_DIR = ../libdecnumber
 LIBDECNUMBER = $(LIBDECNUMBER_DIR)/libdecnumber.a
@@ -625,7 +628,7 @@ INTERNAL_CPPFLAGS = $(CPPFLAGS) @GUILE_CPPFLAGS@ @PYTHON_CPPFLAGS@ \
 INTERNAL_CFLAGS_BASE = \
 	$(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \
 	$(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) $(ZLIBINC) \
-	$(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
+	$(ZSTD_CFLAGS) $(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
 	$(INTL_CFLAGS) $(INCGNU) $(INCSUPPORT) $(LIBBACKTRACE_INC) \
 	$(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) $(SRCHIGH_CFLAGS) \
 	$(TOP_CFLAGS) $(PTHREAD_CFLAGS) $(DEBUGINFOD_CFLAGS)
@@ -647,7 +650,7 @@ INTERNAL_LDFLAGS = \
 # Libraries and corresponding dependencies for compiling gdb.
 # XM_CLIBS, defined in *config files, have host-dependent libs.
 # LIBIBERTY appears twice on purpose.
-CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) \
+CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) $(ZSTD_LIBS) \
         $(LIBSUPPORT) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
 	$(XM_CLIBS) $(GDBTKLIBS)  $(LIBBACKTRACE_LIB) \
 	@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
@@ -2298,6 +2301,7 @@ aclocal_m4_deps = \
 	../config/lcmessage.m4 \
 	../config/codeset.m4 \
 	../config/zlib.m4 \
+	../config/zstd.m4 \
 	../config/ax_pthread.m4
 
 $(srcdir)/aclocal.m4: @MAINTAINER_MODE_TRUE@ $(aclocal_m4_deps)
diff --git a/gdb/NEWS b/gdb/NEWS
index 9619842bc03..1457c99ff04 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -57,6 +57,8 @@
 
 * The Windows native target now supports target async.
 
+* gdb now supports zstd compressed debug sections (ELFCOMPRESS_ZSTD) for ELF.
+
 * New commands
 
 maintenance set ignore-prologue-end-flag on|off
diff --git a/gdb/acinclude.m4 b/gdb/acinclude.m4
index 95ff2b6f35e..28846119dcb 100644
--- a/gdb/acinclude.m4
+++ b/gdb/acinclude.m4
@@ -43,6 +43,7 @@ m4_include([../config/lib-link.m4])
 m4_include([../config/iconv.m4])
 
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 
 m4_include([../gdbsupport/common.m4])
 
@@ -233,7 +234,7 @@ AC_DEFUN([GDB_AC_CHECK_BFD], [
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
   LIBS="-lbfd -liberty -lz $intl $LIBS"
   AC_CACHE_CHECK(
diff --git a/gdb/config.in b/gdb/config.in
index a4975c68aad..e13a409ec2d 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -589,6 +589,9 @@
 /* Define to 1 if you have the `XML_StopParser' function. */
 #undef HAVE_XML_STOPPARSER
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Define to 1 if your system has the _etext variable. */
 #undef HAVE__ETEXT
 
diff --git a/gdb/configure b/gdb/configure
index 4dbd0c3b13c..5d49b3eba5a 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -747,6 +747,8 @@ READLINE_DEPS
 READLINE
 LTLIBICONV
 LIBICONV
+ZSTD_LIBS
+ZSTD_CFLAGS
 zlibinc
 zlibdir
 MIG
@@ -893,6 +895,7 @@ enable_codesign
 with_pkgversion
 with_bugurl
 with_system_zlib
+with_zstd
 with_gnu_ld
 enable_rpath
 with_libiconv_prefix
@@ -961,6 +964,8 @@ DEBUGINFOD_CFLAGS
 DEBUGINFOD_LIBS
 YACC
 YFLAGS
+ZSTD_CFLAGS
+ZSTD_LIBS
 XMKMF'
 ac_subdirs_all='testsuite
 gdbtk'
@@ -1641,6 +1646,8 @@ Optional Packages:
   --with-pkgversion=PKG   Use PKG in the version string in place of "GDB"
   --with-bugurl=URL       Direct users to URL to report a bug
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
   --with-gnu-ld           assume the C compiler uses GNU ld default=no
   --with-libiconv-prefix[=DIR]  search for libiconv in DIR/include and DIR/lib
   --without-libiconv-prefix     don't search for libiconv in includedir and libdir
@@ -1721,6 +1728,8 @@ Some influential environment variables:
   YFLAGS      The list of arguments that will be passed by default to $YACC.
               This script will default YFLAGS to the empty string to avoid a
               default value of `-d' given by some make applications.
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
   XMKMF       Path to xmkmf, Makefile generator for X Window System
 
 Use these variables to override the choices made by `configure' or to help
@@ -8242,7 +8251,8 @@ if test "$ac_res" != no; then :
 fi
 
 
-# Link in zlib if we can.  This allows us to read compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to read compressed debug
+# sections.
 
   # Use the system's zlib library.
   zlibdir="-L\$(top_builddir)/../zlib"
@@ -8262,6 +8272,127 @@ fi
 
 
 
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if "$with_zstd" != no; then :
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+
+fi
+
+
+
       if test "X$prefix" = "XNONE"; then
     acl_final_prefix="$ac_default_prefix"
   else
@@ -17281,7 +17412,7 @@ WIN32LIBS="$WIN32LIBS $WIN32APILIBS"
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
   LIBS="-lbfd -liberty -lz $intl $LIBS"
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ELF support in BFD" >&5
@@ -17396,7 +17527,7 @@ fi
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
   LIBS="-lbfd -liberty -lz $intl $LIBS"
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Mach-O support in BFD" >&5
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 215a91c5b27..e8cf808d280 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -460,8 +460,10 @@ AC_SEARCH_LIBS(gethostbyname, nsl)
 # Some systems (e.g. Solaris) have `socketpair' in libsocket.
 AC_SEARCH_LIBS(socketpair, socket)
 
-# Link in zlib if we can.  This allows us to read compressed debug sections.
+# Link in zlib/zstd if we can.  This allows us to read compressed debug
+# sections.
 AM_ZLIB
+AM_ZSTD
 
 AM_ICONV
 
diff --git a/ld/Makefile.am b/ld/Makefile.am
index d31021c13e2..bbe25f3aca2 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -45,7 +45,7 @@ ELF_CLFAGS=-DELF_LIST_OPTIONS=@elf_list_options@ \
 	   -DELF_PLT_UNWIND_LIST_OPTIONS=@elf_plt_unwind_list_options@
 WARN_CFLAGS = @WARN_CFLAGS@
 NO_WERROR = @NO_WERROR@
-AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS)
+AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS) $(ZSTD_CFLAGS)
 
 # We put the scripts in the directory $(scriptdir)/ldscripts.
 # We can't put the scripts in $(datadir) because the SEARCH_DIR
@@ -959,7 +959,8 @@ ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmai
 	ldbuildid.c
 ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) \
 		      $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL_DEP) $(JANSSON_LIBS)
-ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(JANSSON_LIBS)
+ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) \
+	       $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(ZSTD_LIBS) $(JANSSON_LIBS)
 
 # Dependency tracking for the generated emulation files.
 EXTRA_ld_new_SOURCES += $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES)
diff --git a/ld/Makefile.in b/ld/Makefile.in
index ee0c98f65b0..400eed2717e 100644
--- a/ld/Makefile.in
+++ b/ld/Makefile.in
@@ -126,7 +126,8 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/plugins.m4 \
 	$(top_srcdir)/../config/po.m4 \
 	$(top_srcdir)/../config/progtest.m4 \
-	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../config/zlib.m4 \
+	$(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
 	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
 	$(top_srcdir)/../bfd/version.m4 $(top_srcdir)/configure.ac
@@ -477,6 +478,8 @@ WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
 XGETTEXT = @XGETTEXT@
 YACC = `if [ -f ../bison/bison ]; then echo ../bison/bison -y -L$(srcdir)/../bison/; else echo @YACC@; fi`
 YFLAGS = -d
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
@@ -564,7 +567,7 @@ ELF_CLFAGS = -DELF_LIST_OPTIONS=@elf_list_options@ \
 	   -DELF_SHLIB_LIST_OPTIONS=@elf_shlib_list_options@ \
 	   -DELF_PLT_UNWIND_LIST_OPTIONS=@elf_plt_unwind_list_options@
 
-AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS)
+AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS) $(ZSTD_CFLAGS)
 
 # We put the scripts in the directory $(scriptdir)/ldscripts.
 # We can't put the scripts in $(datadir) because the SEARCH_DIR
@@ -1011,7 +1014,9 @@ ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmai
 ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) \
 		      $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL_DEP) $(JANSSON_LIBS)
 
-ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(JANSSON_LIBS)
+ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) \
+	       $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(ZSTD_LIBS) $(JANSSON_LIBS)
+
 #
 #
 # Build a dummy plugin using libtool.
diff --git a/ld/NEWS b/ld/NEWS
index 355752e6b24..dfe2690d9f2 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* ld now supports zstd compressed debug sections.  The new option
+  --compress-debug-sections=zstd compresses debug sections with zstd.
+
 Changes in 2.39:
 
 * The ELF linker will now generate a warning message if the stack is made
diff --git a/ld/aclocal.m4 b/ld/aclocal.m4
index d20c542eed5..893e973e4f2 100644
--- a/ld/aclocal.m4
+++ b/ld/aclocal.m4
@@ -1203,6 +1203,7 @@ m4_include([../config/plugins.m4])
 m4_include([../config/po.m4])
 m4_include([../config/progtest.m4])
 m4_include([../config/zlib.m4])
+m4_include([../config/zstd.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/ld/config.in b/ld/config.in
index 0ccd79d59cd..3916740eee4 100644
--- a/ld/config.in
+++ b/ld/config.in
@@ -162,6 +162,9 @@
 /* Define to 1 if you have the <windows.h> header file. */
 #undef HAVE_WINDOWS_H
 
+/* Define to 1 if zstd is enabled. */
+#undef HAVE_ZSTD
+
 /* Define to the sub-directory in which libtool stores uninstalled libraries.
    */
 #undef LT_OBJDIR
diff --git a/ld/configure b/ld/configure
index 4efe3ef5dfc..80472f9342e 100755
--- a/ld/configure
+++ b/ld/configure
@@ -646,6 +646,8 @@ elf_plt_unwind_list_options
 elf_shlib_list_options
 elf_list_options
 STRINGIFY
+ZSTD_LIBS
+ZSTD_CFLAGS
 zlibinc
 zlibdir
 NATIVE_LIB_DIRS
@@ -679,9 +681,6 @@ WARN_CFLAGS_FOR_BUILD
 WARN_CFLAGS
 JANSSON_LIBS
 JANSSON_CFLAGS
-PKG_CONFIG_LIBDIR
-PKG_CONFIG_PATH
-PKG_CONFIG
 enable_libctf
 ENABLE_LIBCTF_FALSE
 ENABLE_LIBCTF_TRUE
@@ -711,6 +710,9 @@ LD
 FGREP
 SED
 LIBTOOL
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
 EGREP
 CPP
 GREP
@@ -855,6 +857,7 @@ enable_werror
 enable_build_warnings
 enable_nls
 with_system_zlib
+with_zstd
 '
       ac_precious_vars='build_alias
 host_alias
@@ -868,14 +871,16 @@ CXX
 CXXFLAGS
 CCC
 CPP
-CXXCPP
 PKG_CONFIG
 PKG_CONFIG_PATH
 PKG_CONFIG_LIBDIR
+CXXCPP
 JANSSON_CFLAGS
 JANSSON_LIBS
 YACC
-YFLAGS'
+YFLAGS
+ZSTD_CFLAGS
+ZSTD_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1552,6 +1557,8 @@ Optional Packages:
   --with-lib-path=dir1:dir2...  set default LIB_PATH
   --with-sysroot=DIR Search for usr/lib et al within DIR.
   --with-system-zlib      use installed libz
+  --with-zstd             support zstd compressed debug sections
+                          (default=auto)
 
 Some influential environment variables:
   CC          C compiler command
@@ -1564,12 +1571,12 @@ Some influential environment variables:
   CXX         C++ compiler command
   CXXFLAGS    C++ compiler flags
   CPP         C preprocessor
-  CXXCPP      C++ preprocessor
   PKG_CONFIG  path to pkg-config utility
   PKG_CONFIG_PATH
               directories to add to pkg-config's search path
   PKG_CONFIG_LIBDIR
               path overriding pkg-config's built-in search path
+  CXXCPP      C++ preprocessor
   JANSSON_CFLAGS
               C compiler flags for JANSSON, overriding pkg-config
   JANSSON_LIBS
@@ -1580,6 +1587,8 @@ Some influential environment variables:
   YFLAGS      The list of arguments that will be passed by default to $YACC.
               This script will default YFLAGS to the empty string to avoid a
               default value of `-d' given by some make applications.
+  ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config
+  ZSTD_LIBS   linker flags for ZSTD, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -5388,6 +5397,126 @@ $as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
 
 
 
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=0.9.0
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	else
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		PKG_CONFIG=""
+	fi
+fi
+
 case `pwd` in
   *\ * | *\	*)
     { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
@@ -11491,7 +11620,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11494 "configure"
+#line 11623 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11597,7 +11726,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11600 "configure"
+#line 11729 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -15585,126 +15714,6 @@ else
 fi
 
 
-
-
-
-
-
-
-
-if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
-	if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
-set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PKG_CONFIG+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $PKG_CONFIG in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-PKG_CONFIG=$ac_cv_path_PKG_CONFIG
-if test -n "$PKG_CONFIG"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
-$as_echo "$PKG_CONFIG" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_path_PKG_CONFIG"; then
-  ac_pt_PKG_CONFIG=$PKG_CONFIG
-  # Extract the first word of "pkg-config", so it can be a program name with args.
-set dummy pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $ac_pt_PKG_CONFIG in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
-if test -n "$ac_pt_PKG_CONFIG"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
-$as_echo "$ac_pt_PKG_CONFIG" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_pt_PKG_CONFIG" = x; then
-    PKG_CONFIG=""
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    PKG_CONFIG=$ac_pt_PKG_CONFIG
-  fi
-else
-  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
-fi
-
-fi
-if test -n "$PKG_CONFIG"; then
-	_pkg_min_version=0.9.0
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
-$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
-	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-	else
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-		PKG_CONFIG=""
-	fi
-fi
 if test "x$enable_jansson" != "xno"; then :
 
 pkg_failed=no
@@ -17041,8 +17050,8 @@ $as_echo "#define HAVE_DECL_GETOPT 1" >>confdefs.h
 
 fi
 
-# Link in zlib if we can.  This allows us to read and write
-# compressed CTF sections.
+# Link in zlib/zstd if we can.  This allows us to read and write
+# compressed debug sections.
 
   # Use the system's zlib library.
   zlibdir="-L\$(top_builddir)/../zlib"
@@ -17061,6 +17070,127 @@ fi
 
 
 
+
+# Check whether --with-zstd was given.
+if test "${with_zstd+set}" = set; then :
+  withval=$with_zstd;
+else
+  with_zstd=auto
+fi
+
+
+if "$with_zstd" != no; then :
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5
+$as_echo_n "checking for libzstd... " >&6; }
+
+if test -n "$ZSTD_CFLAGS"; then
+    pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ZSTD_LIBS"; then
+    pkg_cv_ZSTD_LIBS="$ZSTD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+if test $pkg_failed = no; then
+  pkg_save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS $pkg_cv_ZSTD_LIBS"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  pkg_failed=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$pkg_save_LDFLAGS
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1`
+        else
+	        ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ZSTD_PKG_ERRORS" >&5
+
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+elif test $pkg_failed = untried; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+    if test "$with_zstd" = yes; then
+      as_fn_error $? "--with-zstd was given, but pkgconfig/libzstd.pc is not found" "$LINENO" 5
+    fi
+
+else
+	ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS
+	ZSTD_LIBS=$pkg_cv_ZSTD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_ZSTD 1" >>confdefs.h
+
+
+fi
+
+fi
+
+
 # When converting linker scripts into strings for use in emulation
 # files, use astring.sed if the compiler supports ANSI string
 # concatenation, or ostring.sed otherwise.  This is to support the
diff --git a/ld/configure.ac b/ld/configure.ac
index 8a8bfc9a14e..5a6e16764cc 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -34,6 +34,7 @@ AC_PROG_GREP
 AC_GNU_SOURCE
 AC_USE_SYSTEM_EXTENSIONS
 AC_PROG_INSTALL
+PKG_PROG_PKG_CONFIG
 
 LT_INIT
 ACX_LARGEFILE
@@ -377,9 +378,10 @@ if test $ld_cv_decl_getopt_unistd_h = yes; then
 	    [Is the prototype for getopt in <unistd.h> in the expected format?])
 fi
 
-# Link in zlib if we can.  This allows us to read and write
-# compressed CTF sections.
+# Link in zlib/zstd if we can.  This allows us to read and write
+# compressed debug sections.
 AM_ZLIB
+AM_ZSTD
 
 # When converting linker scripts into strings for use in emulation
 # files, use astring.sed if the compiler supports ANSI string
diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
index c52484f35d3..acd66f907d1 100644
--- a/ld/emultempl/elf.em
+++ b/ld/emultempl/elf.em
@@ -668,6 +668,15 @@ gld${EMULATION_NAME}_handle_option (int optc)
 	link_info.compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
       else if (strcasecmp (optarg, "zlib-gabi") == 0)
 	link_info.compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
+      else if (strcasecmp (optarg, "zstd") == 0)
+	{
+#ifdef HAVE_ZSTD
+	  link_info.compress_debug = COMPRESS_DEBUG_ZSTD;
+#else
+	  einfo (_ ("%F%P: --compress-debug-sections=zstd: ld is not built "
+		    "with zstd support\n"));
+#endif
+	}
       else
 	einfo (_("%F%P: invalid --compress-debug-sections option: \`%s'\n"),
 	       optarg);
diff --git a/ld/ld.texi b/ld/ld.texi
index eabbec8faa9..9daed2e7e9f 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -2863,10 +2863,12 @@ but for most Linux based systems it will be @code{both}.
 @kindex --compress-debug-sections=zlib
 @kindex --compress-debug-sections=zlib-gnu
 @kindex --compress-debug-sections=zlib-gabi
+@kindex --compress-debug-sections=zstd
 @item --compress-debug-sections=none
 @itemx --compress-debug-sections=zlib
 @itemx --compress-debug-sections=zlib-gnu
 @itemx --compress-debug-sections=zlib-gabi
+@itemx --compress-debug-sections=zstd
 On ELF platforms, these options control how DWARF debug sections are
 compressed using zlib.
 
@@ -2880,6 +2882,9 @@ sets the SHF_COMPRESSED flag in the sections' headers.
 The @option{--compress-debug-sections=zlib} option is an alias for
 @option{--compress-debug-sections=zlib-gabi}.
 
+@option{--compress-debug-sections=zstd} compresses DWARF debug sections using
+zstd.
+
 Note that this option overrides any compression in input debug
 sections, so if a binary is linked with @option{--compress-debug-sections=none}
 for example, then any compressed debug sections in input files will be
diff --git a/ld/ldmain.c b/ld/ldmain.c
index 1bbddaaad32..71af5935b74 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -506,8 +506,12 @@ main (int argc, char **argv)
   if ((link_info.compress_debug & COMPRESS_DEBUG))
     {
       link_info.output_bfd->flags |= BFD_COMPRESS;
-      if (link_info.compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
-	link_info.output_bfd->flags |= BFD_COMPRESS_GABI;
+      if (link_info.compress_debug != COMPRESS_DEBUG_GNU_ZLIB)
+	{
+	  link_info.output_bfd->flags |= BFD_COMPRESS_GABI;
+	  if (link_info.compress_debug == COMPRESS_DEBUG_ZSTD)
+	    link_info.output_bfd->flags |= BFD_COMPRESS_ZSTD;
+	}
     }
 
   ldwrite ();
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 9225f71b3ce..299371fb775 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -2146,8 +2146,8 @@ elf_static_list_options (FILE *file)
   fprintf (file, _("\
   --package-metadata[=JSON]   Generate package metadata note\n"));
   fprintf (file, _("\
-  --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi]\n\
-                              Compress DWARF debug sections using zlib\n"));
+  --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi|zstd]\n\
+			      Compress DWARF debug sections\n"));
 #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
   fprintf (file, _("\
                                 Default: zlib-gabi\n"));
diff --git a/ld/testsuite/ld-elf/compress.exp b/ld/testsuite/ld-elf/compress.exp
index cfdd767b8ab..7b8a31cc41d 100644
--- a/ld/testsuite/ld-elf/compress.exp
+++ b/ld/testsuite/ld-elf/compress.exp
@@ -254,3 +254,20 @@ if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rt] } then {
 } else {
     pass "$test_name"
 }
+
+if { ![ld_assemble $as "--compress-debug-sections=zstd $srcdir/$subdir/empty.s" tmpdir/emptyzstd.o ] } {
+    return
+}
+set build_tests {
+  {"Build libzstdfoo.so with zstd compressed debug sections"
+   "-shared" "-fPIC -g -Wa,--compress-debug-sections=zstd -Wl,--compress-debug-sections=zstd"
+   {foo.c} {} "libzstdfoo.so"}
+}
+set run_tests {
+    {"Run zstdnormal with libzstdfoo.so with zstd compressed debug sections"
+     "tmpdir/begin.o tmpdir/libzstdfoo.so tmpdir/end.o -Wl,--compress-debug-sections=zstd" ""
+     {main.c} "zstdnormal" "normal.out" "-Wa,--compress-debug-sections=zstd"}
+}
+
+run_cc_link_tests $build_tests
+run_ld_link_exec_tests $run_tests
-- 
2.37.3.998.g577e59143f-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-26  7:20     ` Fangrui Song
@ 2022-09-26 13:30       ` Alan Modra
  0 siblings, 0 replies; 32+ messages in thread
From: Alan Modra @ 2022-09-26 13:30 UTC (permalink / raw)
  To: Fangrui Song
  Cc: Simon Marchi, Jan Beulich, Nick Clifton, binutils, gdb-patches

On Mon, Sep 26, 2022 at 12:20:27AM -0700, Fangrui Song wrote:
> On 2022-09-26, Alan Modra wrote:
> > Better to avoid the need..
> > 
> > binutils/
> > 	* configure.ac (msgpack): Use "AS_IF" rather than "if".
> > 	* configure: Regenerate.
> > ld/
> > 	* configure.ac (jansson): Use "AS_IF" rather than "if".
> > 	* configure: Regenerate.
> > 
> 
> Thanks.  I've changed the zstd patch to use AS_IF, too.

It probably wasn't necessary inside AC_DEFUN, but won't hurt either.

> BTW: I think the `!= xno` trick for ancient shells is not needed.  `!=
> no` is used many times in binutils-gdb.

Quite possibly true nowadays.  I'm not going to be the one that
removes them all.  :-)

Your patch looks OK to me, apart from a few formatting nits.  Here are
two examples:

> @@ -150,9 +163,10 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
>        sec->size = orig_uncompressed_size;
>        if (decompress)
>  	{
> -	  if (!decompress_contents (uncompressed_buffer
> -				    + orig_compression_header_size,
> -				    zlib_size, buffer, buffer_size))
> +	  if (!decompress_contents (
> +		  sec->compress_status == DECOMPRESS_SECTION_ZSTD,
> +		  uncompressed_buffer + orig_compression_header_size,
> +		  zlib_size, buffer, buffer_size))
>  	    {
>  	      bfd_set_error (bfd_error_bad_value);
>  	      bfd_release (abfd, buffer);

One of the formatting guidelines in
https://www.gnu.org/prep/standards/html_node/Formatting.html#Formatting
talks about emacs indenting of code.  The above looks reasonable with
your indenting by hand, but auto-indent will turn it into

	  if (!decompress_contents (
				    sec->compress_status == DECOMPRESS_SECTION_ZSTD,
				    uncompressed_buffer + orig_compression_header_size,
				    zlib_size, buffer, buffer_size))

lining up function args with the open parenthesis.  Inserting a couple
of temporary vars is the nicest solution to keeping line length
manageable.

	  bool is_z = sec->compress_status == DECOMPRESS_SECTION_ZSTD;
	  bfd_byte *p = uncompressed_buffer + orig_compression_header_size;
	  if (!decompress_contents (is_z, p, zlib_size, buffer, buffer_size))

> @@ -569,7 +604,8 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
>    sec->compressed_size = sec->size;
>    sec->size = uncompressed_size;
>    bfd_set_section_alignment (sec, uncompressed_alignment_power);
> -  sec->compress_status = DECOMPRESS_SECTION_SIZED;
> +  sec->compress_status = ch_type == ELFCOMPRESS_ZSTD ? DECOMPRESS_SECTION_ZSTD
> +						     : DECOMPRESS_SECTION_ZLIB;
>  
>    return true;
>  }

The same emacs auto-indent will ruin the above.  Write

  sec->compress_status = (ch_type == ELFCOMPRESS_ZSTD
			  ? DECOMPRESS_SECTION_ZSTD : DECOMPRESS_SECTION_ZLIB);

with unnecessary parentheses to guide indentation.
OK to commit with those things fixed.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-26  5:12   ` Alan Modra
  2022-09-26  7:20     ` Fangrui Song
@ 2022-09-26 14:08     ` Simon Marchi
  2022-09-27  0:33       ` Alan Modra
  1 sibling, 1 reply; 32+ messages in thread
From: Simon Marchi @ 2022-09-26 14:08 UTC (permalink / raw)
  To: Alan Modra; +Cc: Fangrui Song, Jan Beulich, Nick Clifton, binutils, gdb-patches


>>  But what about the other configure.ac files, don't
>> they need PKG_PROG_PKG_CONFIG too?  gdb/configure.ac, for instance, uses
>> pkg-config for debuginfod.  So if the user passes --without-debuginfod
>> --with-zstd, I expect things to fail, as the pkg-config will be skipped.
> 
> No, that will be fine, I think  The reason being that
> PKG_CHECK_MODULES AC_REQUIREs PKG_PROG_PKG_CONFIG.  So the expansion
> of AC_DEBUGINFOD will emit an expansion of PKG_PROG_PKG_CONFIG if that
> has not already occurred, before the entire AC_DEBUGINFOD expansion.

Ah, makes sense.  Thanks for the explanation Alan.

> 
>> binutils/configure.ac probably has the same problem, since it uses
>> PKG_CHECK_MODULES for msgpack.
> 
> I'll fix this one even though it isn't a problem now because
> AC_DEBUGINFOD and AM_ZSTD preceed it.  We should use AS_IF more often,
> particularly when autoconf macros are invoked.

Silly question but... AM_ZSTD was clearly named after AM_ZLIB.  But why
does AM_ZLIB have the "AM" (automake, I suppose) prefix?  It doesn't
seem to have anything to do with automake.

Ack about AS_IF, I will try to remember this for top-level configure
code.

Simon

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-26 14:08     ` Simon Marchi
@ 2022-09-27  0:33       ` Alan Modra
  0 siblings, 0 replies; 32+ messages in thread
From: Alan Modra @ 2022-09-27  0:33 UTC (permalink / raw)
  To: Simon Marchi
  Cc: Fangrui Song, Jan Beulich, Nick Clifton, binutils, gdb-patches

On Mon, Sep 26, 2022 at 10:08:30AM -0400, Simon Marchi wrote:
> Silly question but... AM_ZSTD was clearly named after AM_ZLIB.  But why
> does AM_ZLIB have the "AM" (automake, I suppose) prefix?  It doesn't
> seem to have anything to do with automake.

You'll have to ask Joel.  The original patch is at
https://sourceware.org/pipermail/binutils/2009-October/063904.html

As far as I can see, we get to choose user-defined autoconf macro
naming conventions ourselves.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-24  7:13   ` Fangrui Song
@ 2022-09-27 18:06     ` Tom Tromey
  0 siblings, 0 replies; 32+ messages in thread
From: Tom Tromey @ 2022-09-27 18:06 UTC (permalink / raw)
  To: Fangrui Song via Gdb-patches
  Cc: Enze Li, Fangrui Song, Nick Clifton, Alan Modra, binutils, Jan Beulich

> In binutils, there isn't such a convention and there is no commit using
> "Bug:".  So I will keep using the umbrella link PR29397.

I think the commit script only looks for strings matching "PR name/NUM",
like "PR binutils/29397" in this case.  Just "PR29397" may not end up
putting the commit info into the bug.

Tom

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-23  4:08 [PATCH v3] binutils, gdb: support zstd compressed debug sections Fangrui Song
                   ` (2 preceding siblings ...)
  2022-09-24  6:53 ` Enze Li
@ 2022-09-27 18:08 ` Tom Tromey
  2022-09-27 18:53   ` Fangrui Song
  2022-09-29 11:43 ` Martin Liška
  4 siblings, 1 reply; 32+ messages in thread
From: Tom Tromey @ 2022-09-27 18:08 UTC (permalink / raw)
  To: Fangrui Song via Gdb-patches
  Cc: Alan Modra, Jan Beulich, Nick Clifton, Simon Marchi,
	Fangrui Song, binutils

>>>>> Fangrui Song via Gdb-patches <gdb-patches@sourceware.org> writes:

> PR29397 PR29563: The new configure option --with-zstd defaults to auto.
> If pkgconfig/libzstd.pc is found, define HAVE_ZSTD and support zstd
> compressed debug sections for most tools.

> * bfd: for addr2line, objdump --dwarf, gdb, etc
> * gas: support --compress-debug-sections=zstd
> * ld: support ELFCOMPRESS_ZSTD input and --compress-debug-sections=zstd
> * objcopy: support ELFCOMPRESS_ZSTD input for
>   --decompress-debug-sections and --compress-debug-sections=zstd
> * gdb: support ELFCOMPRESS_ZSTD input.  The bfd change references zstd
>   symbols, so gdb has to link against -lzstd in this patch.

This also needs some change to the sims.
I see failures like this with git master:

make[4]: Entering directory '/home/tromey/gdb/build/sim/bpf'
  CCLD   run
../../bfd/libbfd.a(compress.o):compress.c:function decompress_contents: error: undefined reference to 'ZSTD_decompress'
../../bfd/libbfd.a(compress.o):compress.c:function decompress_contents: error: undefined reference to 'ZSTD_isError'
(unknown):176: error: undefined reference to 'ZSTD_compress'
(unknown):179: error: undefined reference to 'ZSTD_isError'
collect2: error: ld returned 1 exit status

You'll see them all if you do a build with all sims enabled.

thanks,
Tom

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-27 18:08 ` Tom Tromey
@ 2022-09-27 18:53   ` Fangrui Song
  0 siblings, 0 replies; 32+ messages in thread
From: Fangrui Song @ 2022-09-27 18:53 UTC (permalink / raw)
  To: Tom Tromey
  Cc: Fangrui Song via Gdb-patches, Alan Modra, Jan Beulich,
	Nick Clifton, Simon Marchi, binutils

On Tue, Sep 27, 2022 at 11:08 AM Tom Tromey <tom@tromey.com> wrote:
>
> >>>>> Fangrui Song via Gdb-patches <gdb-patches@sourceware.org> writes:
>
> > PR29397 PR29563: The new configure option --with-zstd defaults to auto.
> > If pkgconfig/libzstd.pc is found, define HAVE_ZSTD and support zstd
> > compressed debug sections for most tools.
>
> > * bfd: for addr2line, objdump --dwarf, gdb, etc
> > * gas: support --compress-debug-sections=zstd
> > * ld: support ELFCOMPRESS_ZSTD input and --compress-debug-sections=zstd
> > * objcopy: support ELFCOMPRESS_ZSTD input for
> >   --decompress-debug-sections and --compress-debug-sections=zstd
> > * gdb: support ELFCOMPRESS_ZSTD input.  The bfd change references zstd
> >   symbols, so gdb has to link against -lzstd in this patch.
>
> This also needs some change to the sims.
> I see failures like this with git master:
>
> make[4]: Entering directory '/home/tromey/gdb/build/sim/bpf'
>   CCLD   run
> ../../bfd/libbfd.a(compress.o):compress.c:function decompress_contents: error: undefined reference to 'ZSTD_decompress'
> ../../bfd/libbfd.a(compress.o):compress.c:function decompress_contents: error: undefined reference to 'ZSTD_isError'
> (unknown):176: error: undefined reference to 'ZSTD_compress'
> (unknown):179: error: undefined reference to 'ZSTD_isError'
> collect2: error: ld returned 1 exit status
>
> You'll see them all if you do a build with all sims enabled.
>
> thanks,
> Tom

Thanks for the report and Tom's IRC chat with me about the
`../../configure --enable-targets --enable-sim; make all-gdb` build.
Tom confirmed that the latest commit `sim: Link ZSTD_LIBS` has fixed
the problem.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-23  4:08 [PATCH v3] binutils, gdb: support zstd compressed debug sections Fangrui Song
                   ` (3 preceding siblings ...)
  2022-09-27 18:08 ` Tom Tromey
@ 2022-09-29 11:43 ` Martin Liška
  2022-09-29 20:17   ` Fangrui Song
  4 siblings, 1 reply; 32+ messages in thread
From: Martin Liška @ 2022-09-29 11:43 UTC (permalink / raw)
  To: Fangrui Song, Alan Modra, Jan Beulich, Nick Clifton, Simon Marchi
  Cc: binutils, gdb-patches, Richard Biener, Michael Matz

Hello.

Thanks for the patch set. Right now, we configure our binutils package with:
--enable-compressed-debug-sections=gas and we would appreciate a new configure
option that will selected default compression algorithm. Having that, we will
proudly switch to zstd.

Can you please prepare such patch?

Thanks,
Martin


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections
  2022-09-29 11:43 ` Martin Liška
@ 2022-09-29 20:17   ` Fangrui Song
  2022-09-30  9:48     ` [PATCH][RFC] add --enable-zstd-compressed-debug-sections configure option Martin Liška
  0 siblings, 1 reply; 32+ messages in thread
From: Fangrui Song @ 2022-09-29 20:17 UTC (permalink / raw)
  To: Martin Liška
  Cc: Alan Modra, Jan Beulich, Nick Clifton, Simon Marchi, binutils,
	gdb-patches, Richard Biener, Michael Matz

On 2022-09-29, Martin Liška wrote:
>Hello.
>
>Thanks for the patch set. Right now, we configure our binutils package with:
>--enable-compressed-debug-sections=gas and we would appreciate a new configure
>option that will selected default compression algorithm. Having that, we will
>proudly switch to zstd.
>
>Can you please prepare such patch?
>
>Thanks,
>Martin
>

I left a comment on https://sourceware.org/bugzilla/show_bug.cgi?id=19109 that
the --enable-compressed-debug-sections=gas syntax needs extension to
support zstd.

Perhaps the easiest solution (and circumvents the syntax problem) is to
add a new option: --enable-zstd-compressed-debug-sections, but then
there is some duplication...

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH][RFC] add --enable-zstd-compressed-debug-sections configure option
  2022-09-29 20:17   ` Fangrui Song
@ 2022-09-30  9:48     ` Martin Liška
  2022-09-30 11:25       ` Pedro Alves
  0 siblings, 1 reply; 32+ messages in thread
From: Martin Liška @ 2022-09-30  9:48 UTC (permalink / raw)
  To: binutils; +Cc: Fangrui Song

Hello.

The patch can set up default compression algorithm as zstd instead of the
default zlib-gabi.

The patch is lightly tested as readelf can't decompress debug sections:
https://sourceware.org/bugzilla/show_bug.cgi?id=29640

Thoughts?

ChangeLog:

	* configure.ac: Add --enable-zstd-compressed-debug-sections
	configure option.
	* configure: Regenerate.

gas/ChangeLog:

	* NEWS: Mention --enable-zstd-compressed-debug-sections.
	* as.c: Respect FLAG_ZSTD_COMPRESS_DEBUG and should it in
	--help.
	* configure.ac: Add --enable-zstd-compressed-debug-sections
	configure option.
	* configure: Regenerate.
	* config.in: Regenerate.

ld/ChangeLog:

	* NEWS: Mention --enable-zstd-compressed-debug-sections.
	* configure.ac: Add --enable-zstd-compressed-debug-sections
	configure option.
	* configure: Regenerate.
	* config.in: Regenerate.
	* ldmain.c: Respenct FLAG_ZSTD_COMPRESS_DEBUG.
	* lexsup.c: Likewise.
---
 configure        | 17 +++++++++++++++++
 configure.ac     |  6 ++++++
 gas/NEWS         |  3 +++
 gas/as.c         | 24 ++++++++++++++++--------
 gas/config.in    |  3 +++
 gas/configure    | 20 ++++++++++++++++++--
 gas/configure.ac | 10 ++++++++++
 ld/NEWS          |  3 +++
 ld/config.in     |  3 +++
 ld/configure     | 20 ++++++++++++++++++--
 ld/configure.ac  | 10 ++++++++++
 ld/ldmain.c      |  4 ++++
 ld/lexsup.c      |  5 +++++
 13 files changed, 116 insertions(+), 12 deletions(-)

diff --git a/configure b/configure
index f14e0efd675..03c26c455c7 100755
--- a/configure
+++ b/configure
@@ -792,6 +792,7 @@ enable_gold
 enable_ld
 enable_gprofng
 enable_compressed_debug_sections
+enable_zstd_compressed_debug_sections
 enable_year2038
 enable_libquadmath
 enable_libquadmath_support
@@ -1523,6 +1524,9 @@ Optional Features:
   --enable-compressed-debug-sections={all,gas,gold,ld,none}
                           Enable compressed debug sections for gas, gold or ld
                           by default
+  --enable-zstd-compressed-debug-sections
+                          Use zstd for debug info sections compression by
+                          default.
   --enable-year2038       enable support for timestamps past the year 2038
   --disable-libquadmath   do not build libquadmath directory
   --disable-libquadmath-support
@@ -3119,6 +3123,19 @@ else
 fi
 
 
+
+# Check whether --enable-zstd_compressed_debug_sections was given.
+if test "${enable_zstd_compressed_debug_sections+set}" = set; then :
+  enableval=$enable_zstd_compressed_debug_sections;
+  if test x"$enable_compressed_debug_sections" = xyes; then
+    as_fn_error $? "no program with compressed debug sections specified" "$LINENO" 5
+  fi
+
+else
+  zstd_compressed_debug_sections=
+fi
+
+
 # Configure extra directories which are host specific
 
 case "${host}" in
diff --git a/configure.ac b/configure.ac
index 0152c69292e..1728991ab8a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -422,6 +422,12 @@ AC_ARG_ENABLE(compressed_debug_sections,
   fi
 ], [enable_compressed_debug_sections=])
 
+
+AC_ARG_ENABLE(zstd_compressed_debug_sections,
+[AS_HELP_STRING([--enable-zstd-compressed-debug-sections],
+		[Use zstd for debug info sections compression by default.])],
+[], [zstd_compressed_debug_sections=])
+
 # Configure extra directories which are host specific
 
 case "${host}" in
diff --git a/gas/NEWS b/gas/NEWS
index 9a8b726b942..8f509f3aebf 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -2,6 +2,9 @@
 
 * gas now supports --compress-debug-sections=zstd to compress
   debug sections with zstd.
+* Add a configure option --enable-zstd-compressed-debug-sections
+  in order to use zstd as a default compression algorithm when
+  --compress-debug-sections is used (or enabled by default).
 
 Changes in 2.39:
 
diff --git a/gas/as.c b/gas/as.c
index 9ce3d622f95..8c9c1d7abfd 100644
--- a/gas/as.c
+++ b/gas/as.c
@@ -226,8 +226,12 @@ print_version_id (void)
 
 #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
 enum compressed_debug_section_type flag_compress_debug
+#if FLAG_ZSTD_COMPRESS_DEBUG
+  = COMPRESS_DEBUG_ZSTD;
+#else
   = COMPRESS_DEBUG_GABI_ZLIB;
 #endif
+#endif
 
 static void
 show_usage (FILE * stream)
@@ -250,21 +254,25 @@ Options:\n\
 
   fprintf (stream, _("\
   --alternate             initially turn on alternate macro syntax\n"));
-#ifdef DEFAULT_FLAG_COMPRESS_DEBUG
   fprintf (stream, _("\
   --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
-                          compress DWARF debug sections using zlib [default]\n"));
+                          compress DWARF debug sections\n"));
+#ifdef DEFAULT_FLAG_COMPRESS_DEBUG
+#if FLAG_ZSTD_COMPRESS_DEBUG
   fprintf (stream, _("\
-  --nocompress-debug-sections\n\
-                          don't compress DWARF debug sections\n"));
+                            Default: zstd\n"));
 #else
   fprintf (stream, _("\
-  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
-                          compress DWARF debug sections using zlib\n"));
+                            Default: zlib-gabi\n"));
+#endif
+#else
   fprintf (stream, _("\
-  --nocompress-debug-sections\n\
-                          don't compress DWARF debug sections [default]\n"));
+                            Default: none\n"));
 #endif
+
+  fprintf (stream, _("\
+  --nocompress-debug-sections\n\
+                          don't compress DWARF debug sections\n"));
   fprintf (stream, _("\
   -D                      produce assembler debugging messages\n"));
   fprintf (stream, _("\
diff --git a/gas/config.in b/gas/config.in
index 0d1668a3eac..35b8c0cc26a 100644
--- a/gas/config.in
+++ b/gas/config.in
@@ -71,6 +71,9 @@
    language is requested. */
 #undef ENABLE_NLS
 
+/* Define to 1 if you want compressed debug sections with zstd by default. */
+#undef FLAG_ZSTD_COMPRESS_DEBUG
+
 /* Define to 1 if you have the declaration of `asprintf', and to 0 if you
    don't. */
 #undef HAVE_DECL_ASPRINTF
diff --git a/gas/configure b/gas/configure
index 02cded59b6a..10a095f89c7 100755
--- a/gas/configure
+++ b/gas/configure
@@ -810,6 +810,7 @@ enable_largefile
 enable_targets
 enable_checking
 enable_compressed_debug_sections
+enable_zstd_compressed_debug_sections
 enable_x86_relax_relocations
 enable_elf_stt_common
 enable_generate_build_notes
@@ -1476,6 +1477,9 @@ Optional Features:
   --enable-checking       enable run-time checks
   --enable-compressed-debug-sections={all,gas,none}
                           compress debug sections by default
+  --enable-zstd-compressed-debug-sections
+                          Use zstd for debug info sections compression by
+                          default
   --enable-x86-relax-relocations
                           generate x86 relax relocations by default
   --enable-elf-stt-common generate ELF common symbols with STT_COMMON type by
@@ -10722,7 +10726,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10725 "configure"
+#line 10729 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10828,7 +10832,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10831 "configure"
+#line 10835 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11502,6 +11506,12 @@ if test "${enable_compressed_debug_sections+set}" = set; then :
 esac
 fi
 
+# Use zstd compression algorithm by default.
+# Check whether --enable-zstd_compressed_debug_sections was given.
+if test "${enable_zstd_compressed_debug_sections+set}" = set; then :
+  enableval=$enable_zstd_compressed_debug_sections; ac_zstd_compressed_debug_sections=$enableval
+fi
+
 # PR gas/19520
 # Decide if x86 assembler should generate relax relocations.
 ac_default_x86_relax_relocations=unset
@@ -12671,6 +12681,12 @@ $as_echo "#define DEFAULT_FLAG_COMPRESS_DEBUG 1" >>confdefs.h
 
 fi
 
+if test x$ac_zstd_compressed_debug_sections = xyes ; then
+
+$as_echo "#define FLAG_ZSTD_COMPRESS_DEBUG 1" >>confdefs.h
+
+fi
+
 # Turn on all targets if possible
 if test ${all_targets} = "yes"; then
   case ${target_cpu_type} in
diff --git a/gas/configure.ac b/gas/configure.ac
index e6f3298cb3e..b46acfe9033 100644
--- a/gas/configure.ac
+++ b/gas/configure.ac
@@ -76,6 +76,12 @@ AC_ARG_ENABLE(compressed_debug_sections,
   *)   ac_default_compressed_debug_sections=unset ;;
 esac])dnl
 
+# Use zstd compression algorithm by default.
+AC_ARG_ENABLE(zstd_compressed_debug_sections,
+	      AS_HELP_STRING([--enable-zstd-compressed-debug-sections],
+	      [Use zstd for debug info sections compression by default]),
+[ac_zstd_compressed_debug_sections=$enableval])dnl
+
 # PR gas/19520
 # Decide if x86 assembler should generate relax relocations.
 ac_default_x86_relax_relocations=unset
@@ -755,6 +761,10 @@ if test x$ac_default_compressed_debug_sections = xyes ; then
   AC_DEFINE(DEFAULT_FLAG_COMPRESS_DEBUG, 1, [Define if you want compressed debug sections by default.])
 fi
 
+if test x$ac_zstd_compressed_debug_sections = xyes ; then
+  AC_DEFINE(FLAG_ZSTD_COMPRESS_DEBUG, 1, [Define to 1 if you want compressed debug sections with zstd by default.])
+fi
+
 # Turn on all targets if possible
 if test ${all_targets} = "yes"; then
   case ${target_cpu_type} in
diff --git a/ld/NEWS b/ld/NEWS
index dfe2690d9f2..82619b3625e 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -2,6 +2,9 @@
 
 * ld now supports zstd compressed debug sections.  The new option
   --compress-debug-sections=zstd compresses debug sections with zstd.
+* Add a configure option --enable-zstd-compressed-debug-sections
+  in order to use zstd as a default compression algorithm when
+  --compress-debug-sections is used (or enabled by default).
 
 Changes in 2.39:
 
diff --git a/ld/config.in b/ld/config.in
index 3916740eee4..93ec9cee232 100644
--- a/ld/config.in
+++ b/ld/config.in
@@ -58,6 +58,9 @@
 /* Additional extension a shared object might have. */
 #undef EXTRA_SHLIB_EXTENSION
 
+/* Define to 1 if you want compressed debug sections with zstd by default. */
+#undef FLAG_ZSTD_COMPRESS_DEBUG
+
 /* Define to choose default GOT handling scheme */
 #undef GOT_HANDLING_DEFAULT
 
diff --git a/ld/configure b/ld/configure
index 9dd3ed5f1e7..fa21b5de04e 100755
--- a/ld/configure
+++ b/ld/configure
@@ -841,6 +841,7 @@ with_sysroot
 enable_gold
 enable_got
 enable_compressed_debug_sections
+enable_zstd_compressed_debug_sections
 enable_new_dtags
 enable_relro
 enable_textrel_check
@@ -1524,6 +1525,9 @@ Optional Features:
                           multigot)
   --enable-compressed-debug-sections={all,ld,none}
                           compress debug sections by default]
+  --enable-zstd-compressed-debug-sections
+                          Use zstd for debug info sections compression by
+                          default
   --enable-new-dtags      set DT_RUNPATH instead of DT_RPATH by default]
   --enable-relro          enable -z relro in ELF linker by default
   --enable-textrel-check=[yes|no|warning|error]
@@ -11620,7 +11624,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11623 "configure"
+#line 11627 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11726,7 +11730,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11729 "configure"
+#line 11733 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -15544,6 +15548,12 @@ if test "${enable_compressed_debug_sections+set}" = set; then :
 esac
 fi
 
+# Use zstd compression algorithm by default.
+# Check whether --enable-zstd_compressed_debug_sections was given.
+if test "${enable_zstd_compressed_debug_sections+set}" = set; then :
+  enableval=$enable_zstd_compressed_debug_sections; ac_zstd_compressed_debug_sections=$enableval
+fi
+
 # Decide setting DT_RUNPATH instead of DT_RPATH by default
 ac_default_new_dtags=unset
 # Provide a configure time option to override our default.
@@ -17340,6 +17350,12 @@ $as_echo "#define DEFAULT_FLAG_COMPRESS_DEBUG 1" >>confdefs.h
 
 fi
 
+if test x$ac_zstd_compressed_debug_sections = xyes ; then
+
+$as_echo "#define FLAG_ZSTD_COMPRESS_DEBUG 1" >>confdefs.h
+
+fi
+
 if test "${ac_default_new_dtags}" = unset; then
   ac_default_new_dtags=0
 fi
diff --git a/ld/configure.ac b/ld/configure.ac
index f1b2f9897f8..729f07343aa 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -163,6 +163,12 @@ AC_ARG_ENABLE(compressed_debug_sections,
   ,no, | ,none,)  ac_default_compressed_debug_sections=no ;;
 esac])dnl
 
+# Use zstd compression algorithm by default.
+AC_ARG_ENABLE(zstd_compressed_debug_sections,
+	      AS_HELP_STRING([--enable-zstd-compressed-debug-sections],
+	      [Use zstd for debug info sections compression by default]),
+[ac_zstd_compressed_debug_sections=$enableval])dnl
+
 # Decide setting DT_RUNPATH instead of DT_RPATH by default
 ac_default_new_dtags=unset
 # Provide a configure time option to override our default.
@@ -510,6 +516,10 @@ if test x$ac_default_compressed_debug_sections = xyes ; then
   AC_DEFINE(DEFAULT_FLAG_COMPRESS_DEBUG, 1, [Define if you want compressed debug sections by default.])
 fi
 
+if test x$ac_zstd_compressed_debug_sections = xyes ; then
+  AC_DEFINE(FLAG_ZSTD_COMPRESS_DEBUG, 1, [Define to 1 if you want compressed debug sections with zstd by default.])
+fi
+
 if test "${ac_default_new_dtags}" = unset; then
   ac_default_new_dtags=0
 fi
diff --git a/ld/ldmain.c b/ld/ldmain.c
index d63002c994a..d0ad5f3d797 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -352,8 +352,12 @@ main (int argc, char **argv)
   link_info.spare_dynamic_tags = 5;
   link_info.path_separator = ':';
 #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
+#if FLAG_ZSTD_COMPRESS_DEBUG
+  link_info.compress_debug = COMPRESS_DEBUG_ZSTD;
+#else
   link_info.compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
 #endif
+#endif
 #ifdef DEFAULT_NEW_DTAGS
   link_info.new_dtags = DEFAULT_NEW_DTAGS;
 #endif
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 299371fb775..c46f1f822a8 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -2149,8 +2149,13 @@ elf_static_list_options (FILE *file)
   --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi|zstd]\n\
 			      Compress DWARF debug sections\n"));
 #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
+#if FLAG_ZSTD_COMPRESS_DEBUG
+  fprintf (file, _("\
+                                Default: zstd\n"));
+#else
   fprintf (file, _("\
                                 Default: zlib-gabi\n"));
+#endif
 #else
   fprintf (file, _("\
                                 Default: none\n"));
-- 
2.37.3


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH][RFC] add --enable-zstd-compressed-debug-sections configure option
  2022-09-30  9:48     ` [PATCH][RFC] add --enable-zstd-compressed-debug-sections configure option Martin Liška
@ 2022-09-30 11:25       ` Pedro Alves
  2022-09-30 12:42         ` Martin Liška
  0 siblings, 1 reply; 32+ messages in thread
From: Pedro Alves @ 2022-09-30 11:25 UTC (permalink / raw)
  To: Martin Liška, binutils; +Cc: Fangrui Song

On 2022-09-30 10:48 a.m., Martin Liška wrote:
> Hello.
> 
> The patch can set up default compression algorithm as zstd instead of the
> default zlib-gabi.
> 
> The patch is lightly tested as readelf can't decompress debug sections:
> https://sourceware.org/bugzilla/show_bug.cgi?id=29640
> 
> Thoughts?
> 
> ChangeLog:
> 
> 	* configure.ac: Add --enable-zstd-compressed-debug-sections
> 	configure option.
> 	* configure: Regenerate.

This may become a bit awkward in the future when other better format appears, and you want to
switch to use it by default.  Like, imagine zstd2 is invented.  At that point we'd have to decide
whether to add code to error out if the user specifies both
   "--enable-zstd-compressed-debug-sections --enable-zstd2-compressed-debug-sections",
or always pick the latter option, or some such.  

IMHO, it seems cleaner and more future proof to add instead:

  --enable-default-compressed-debug-sections=zlib|zlib-gnu|zlib-gabi|zstd

WDYT?

Pedro Alves

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH][RFC] add --enable-zstd-compressed-debug-sections configure option
  2022-09-30 11:25       ` Pedro Alves
@ 2022-09-30 12:42         ` Martin Liška
  2022-10-01  7:31           ` Fangrui Song
  0 siblings, 1 reply; 32+ messages in thread
From: Martin Liška @ 2022-09-30 12:42 UTC (permalink / raw)
  To: Pedro Alves, binutils; +Cc: Fangrui Song

On 9/30/22 13:25, Pedro Alves wrote:
> On 2022-09-30 10:48 a.m., Martin Liška wrote:
>> Hello.
>>
>> The patch can set up default compression algorithm as zstd instead of the
>> default zlib-gabi.
>>
>> The patch is lightly tested as readelf can't decompress debug sections:
>> https://sourceware.org/bugzilla/show_bug.cgi?id=29640
>>
>> Thoughts?
>>
>> ChangeLog:
>>
>> 	* configure.ac: Add --enable-zstd-compressed-debug-sections
>> 	configure option.
>> 	* configure: Regenerate.
> 
> This may become a bit awkward in the future when other better format appears, and you want to
> switch to use it by default.  Like, imagine zstd2 is invented.  At that point we'd have to decide
> whether to add code to error out if the user specifies both
>    "--enable-zstd-compressed-debug-sections --enable-zstd2-compressed-debug-sections",
> or always pick the latter option, or some such.  

Understood.

> 
> IMHO, it seems cleaner and more future proof to add instead:
> 
>   --enable-default-compressed-debug-sections=zlib|zlib-gnu|zlib-gabi|zstd
> 
> WDYT?

Yep, it's much nicer. Anyway, lemme try preparing a patch that does a bit of refactoring
before I introduce such a patch.

Martin

> 
> Pedro Alves


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH][RFC] add --enable-zstd-compressed-debug-sections configure option
  2022-09-30 12:42         ` Martin Liška
@ 2022-10-01  7:31           ` Fangrui Song
  2022-10-03  7:49             ` Martin Liška
  0 siblings, 1 reply; 32+ messages in thread
From: Fangrui Song @ 2022-10-01  7:31 UTC (permalink / raw)
  To: Martin Liška; +Cc: Pedro Alves, binutils

On 2022-09-30, Martin Liška wrote:
>On 9/30/22 13:25, Pedro Alves wrote:
>> On 2022-09-30 10:48 a.m., Martin Liška wrote:
>>> Hello.
>>>
>>> The patch can set up default compression algorithm as zstd instead of the
>>> default zlib-gabi.
>>>
>>> The patch is lightly tested as readelf can't decompress debug sections:
>>> https://sourceware.org/bugzilla/show_bug.cgi?id=29640
>>>
>>> Thoughts?
>>>
>>> ChangeLog:
>>>
>>> 	* configure.ac: Add --enable-zstd-compressed-debug-sections
>>> 	configure option.
>>> 	* configure: Regenerate.
>>
>> This may become a bit awkward in the future when other better format appears, and you want to
>> switch to use it by default.  Like, imagine zstd2 is invented.  At that point we'd have to decide
>> whether to add code to error out if the user specifies both
>>    "--enable-zstd-compressed-debug-sections --enable-zstd2-compressed-debug-sections",
>> or always pick the latter option, or some such.
>
>Understood.
>
>>
>> IMHO, it seems cleaner and more future proof to add instead:
>>
>>   --enable-default-compressed-debug-sections=zlib|zlib-gnu|zlib-gabi|zstd
>>
>> WDYT?
>
>Yep, it's much nicer. Anyway, lemme try preparing a patch that does a bit of refactoring
>before I introduce such a patch.
>
>Martin

Personally I'll prefer that the compiler drivers (GCC and Clang) pass
the default options to ld/as, and they have good infrastructure for
customization...  (Clang recently got better configuration file
(https://clang.llvm.org/docs/UsersManual.html#configuration-files)
support which enables more convenient default driver options.)

Setting default options in ld/as allow very few projects which bypass
the compiler driver to use zstd compressed debug sections but the
benefit is probably low...

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH][RFC] add --enable-zstd-compressed-debug-sections configure option
  2022-10-01  7:31           ` Fangrui Song
@ 2022-10-03  7:49             ` Martin Liška
  2022-10-03  7:50               ` [PATCH 1/2] refactor usage of compressed_debug_section_type Martin Liška
  2022-10-03  7:50               ` [PATCH 2/2] add --enable-default-compressed-debug-sections-algorithm configure option Martin Liška
  0 siblings, 2 replies; 32+ messages in thread
From: Martin Liška @ 2022-10-03  7:49 UTC (permalink / raw)
  To: Fangrui Song; +Cc: Pedro Alves, binutils

On 10/1/22 09:31, Fangrui Song wrote:
> On 2022-09-30, Martin Liška wrote:
>> On 9/30/22 13:25, Pedro Alves wrote:
>>> On 2022-09-30 10:48 a.m., Martin Liška wrote:
>>>> Hello.
>>>>
>>>> The patch can set up default compression algorithm as zstd instead of the
>>>> default zlib-gabi.
>>>>
>>>> The patch is lightly tested as readelf can't decompress debug sections:
>>>> https://sourceware.org/bugzilla/show_bug.cgi?id=29640
>>>>
>>>> Thoughts?
>>>>
>>>> ChangeLog:
>>>>
>>>>     * configure.ac: Add --enable-zstd-compressed-debug-sections
>>>>     configure option.
>>>>     * configure: Regenerate.
>>>
>>> This may become a bit awkward in the future when other better format appears, and you want to
>>> switch to use it by default.  Like, imagine zstd2 is invented.  At that point we'd have to decide
>>> whether to add code to error out if the user specifies both
>>>    "--enable-zstd-compressed-debug-sections --enable-zstd2-compressed-debug-sections",
>>> or always pick the latter option, or some such.
>>
>> Understood.
>>
>>>
>>> IMHO, it seems cleaner and more future proof to add instead:
>>>
>>>   --enable-default-compressed-debug-sections=zlib|zlib-gnu|zlib-gabi|zstd
>>>
>>> WDYT?
>>
>> Yep, it's much nicer. Anyway, lemme try preparing a patch that does a bit of refactoring
>> before I introduce such a patch.
>>
>> Martin
> 
> Personally I'll prefer that the compiler drivers (GCC and Clang) pass
> the default options to ld/as, and they have good infrastructure for
> customization...  (Clang recently got better configuration file
> (https://clang.llvm.org/docs/UsersManual.html#configuration-files)
> support which enables more convenient default driver options.)
> 
> Setting default options in ld/as allow very few projects which bypass
> the compiler driver to use zstd compressed debug sections but the
> benefit is probably low...

Well, I would prefer having the configure option, similar to 
--enable-compressed-debug-sections, we as openSUSE rely on that where
we select the corresponding option value in binutils package.

Martin

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 1/2] refactor usage of compressed_debug_section_type
  2022-10-03  7:49             ` Martin Liška
@ 2022-10-03  7:50               ` Martin Liška
  2022-10-11  7:14                 ` Martin Liška
  2022-10-03  7:50               ` [PATCH 2/2] add --enable-default-compressed-debug-sections-algorithm configure option Martin Liška
  1 sibling, 1 reply; 32+ messages in thread
From: Martin Liška @ 2022-10-03  7:50 UTC (permalink / raw)
  To: binutils; +Cc: Fangrui Song

bfd/ChangeLog:

	* bfd-in.h (bfd_hash_set_default_size): Add COMPRESS_UNKNOWN
	  enum value.
	(struct compressed_type_tuple): New.
	* bfd-in2.h (bfd_hash_set_default_size): Regenerate.
	(struct compressed_type_tuple): Likewise.
	* libbfd.c (ARRAY_SIZE): New macro.
	(bfd_get_compression_algorithm): New function.
	(bfd_get_compression_algorithm_name): Likewise.

gas/ChangeLog:

	* as.c: Do not special-case, use the new functions.

ld/ChangeLog:

	* emultempl/elf.em: Do not special-case, use the new functions.
	* lexsup.c (elf_static_list_options): Likewise.
---
 bfd/bfd-in.h        | 20 +++++++++++++++++---
 bfd/bfd-in2.h       | 20 +++++++++++++++++---
 bfd/libbfd.c        | 36 ++++++++++++++++++++++++++++++++++++
 gas/as.c            | 34 +++++++++-------------------------
 ld/emultempl/elf.em | 22 +++++++---------------
 ld/lexsup.c         |  8 ++------
 6 files changed, 88 insertions(+), 52 deletions(-)

diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index 4765ea80536..82e33d400f3 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -335,15 +335,23 @@ extern void bfd_hash_traverse
    this size.  */
 extern unsigned long bfd_hash_set_default_size (unsigned long);
 
-/* Types of compressed DWARF debug sections.  We currently support
-   zlib.  */
+/* Types of compressed DWARF debug sections.  */
 enum compressed_debug_section_type
 {
   COMPRESS_DEBUG_NONE = 0,
   COMPRESS_DEBUG = 1 << 0,
   COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1,
   COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2,
-  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3
+  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3,
+  COMPRESS_UNKNOWN = 1 << 4
+};
+
+/* Tuple for compressed_debug_section_type and their name.  */
+
+struct compressed_type_tuple
+{
+  enum compressed_debug_section_type type;
+  const char *name;
 };
 
 /* This structure is used to keep track of stabs in sections
@@ -456,6 +464,12 @@ extern void bfd_free_window
   (bfd_window *);
 extern bool bfd_get_file_window
   (bfd *, file_ptr, bfd_size_type, bfd_window *, bool);
+
+
+extern enum compressed_debug_section_type bfd_get_compression_algorithm
+  (const char *);
+extern const char *bfd_get_compression_algorithm_name
+  (enum compressed_debug_section_type);
 \f
 /* Externally visible ELF routines.  */
 
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 5c80956c79c..39f925362e0 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -342,15 +342,23 @@ extern void bfd_hash_traverse
    this size.  */
 extern unsigned long bfd_hash_set_default_size (unsigned long);
 
-/* Types of compressed DWARF debug sections.  We currently support
-   zlib.  */
+/* Types of compressed DWARF debug sections.  */
 enum compressed_debug_section_type
 {
   COMPRESS_DEBUG_NONE = 0,
   COMPRESS_DEBUG = 1 << 0,
   COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1,
   COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2,
-  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3
+  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3,
+  COMPRESS_UNKNOWN = 1 << 4
+};
+
+/* Tuple for compressed_debug_section_type and their name.  */
+
+struct compressed_type_tuple
+{
+  enum compressed_debug_section_type type;
+  const char *name;
 };
 
 /* This structure is used to keep track of stabs in sections
@@ -463,6 +471,12 @@ extern void bfd_free_window
   (bfd_window *);
 extern bool bfd_get_file_window
   (bfd *, file_ptr, bfd_size_type, bfd_window *, bool);
+
+
+extern enum compressed_debug_section_type bfd_get_compression_algorithm
+  (const char *);
+extern const char *bfd_get_compression_algorithm_name
+  (enum compressed_debug_section_type);
 \f
 /* Externally visible ELF routines.  */
 
diff --git a/bfd/libbfd.c b/bfd/libbfd.c
index d33f3416206..14e7d8ef34f 100644
--- a/bfd/libbfd.c
+++ b/bfd/libbfd.c
@@ -1244,3 +1244,39 @@ _bfd_generic_init_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED,
 {
   return true;
 }
+
+/* Display texts for type of compressed DWARF debug sections.  */
+static const struct compressed_type_tuple compressed_debug_section_names[] =
+{
+  { COMPRESS_DEBUG_NONE, "none" },
+  { COMPRESS_DEBUG, "zlib" },
+  { COMPRESS_DEBUG_GNU_ZLIB, "zlib-gnu" },
+  { COMPRESS_DEBUG_GABI_ZLIB, "zlib-gabi" },
+  { COMPRESS_DEBUG_ZSTD, "zstd" },
+};
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+#endif
+
+/* Return compressed_debug_section_type from a string representation.  */
+enum compressed_debug_section_type
+bfd_get_compression_algorithm (const char *name)
+{
+  for (unsigned i = 0; i < ARRAY_SIZE (compressed_debug_section_names); ++i)
+    if (strcasecmp (compressed_debug_section_names[i].name, name) == 0)
+      return compressed_debug_section_names[i].type;
+
+  return COMPRESS_UNKNOWN;
+}
+
+/* Return compression algorithm name based on the type.  */
+const char *
+bfd_get_compression_algorithm_name (enum compressed_debug_section_type type)
+{
+  for (unsigned i = 0; i < ARRAY_SIZE (compressed_debug_section_names); ++i)
+    if (type == compressed_debug_section_names[i].type)
+      return compressed_debug_section_names[i].name;
+
+  return NULL;
+}
diff --git a/gas/as.c b/gas/as.c
index 9ce3d622f95..a5c2d2459f7 100644
--- a/gas/as.c
+++ b/gas/as.c
@@ -250,21 +250,16 @@ Options:\n\
 
   fprintf (stream, _("\
   --alternate             initially turn on alternate macro syntax\n"));
-#ifdef DEFAULT_FLAG_COMPRESS_DEBUG
   fprintf (stream, _("\
   --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
-                          compress DWARF debug sections using zlib [default]\n"));
+                          compress DWARF debug sections\n")),
   fprintf (stream, _("\
-  --nocompress-debug-sections\n\
-                          don't compress DWARF debug sections\n"));
-#else
-  fprintf (stream, _("\
-  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
-                          compress DWARF debug sections using zlib\n"));
+		            Default: %s\n"),
+	   bfd_get_compression_algorithm_name (flag_compress_debug));
+
   fprintf (stream, _("\
   --nocompress-debug-sections\n\
-                          don't compress DWARF debug sections [default]\n"));
-#endif
+                          don't compress DWARF debug sections\n"));
   fprintf (stream, _("\
   -D                      produce assembler debugging messages\n"));
   fprintf (stream, _("\
@@ -741,24 +736,13 @@ This program has absolutely no warranty.\n"));
 	  if (optarg)
 	    {
 #if defined OBJ_ELF || defined OBJ_MAYBE_ELF
-	      if (strcasecmp (optarg, "none") == 0)
-		flag_compress_debug = COMPRESS_DEBUG_NONE;
-	      else if (strcasecmp (optarg, "zlib") == 0)
-		flag_compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
-	      else if (strcasecmp (optarg, "zlib-gnu") == 0)
-		flag_compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
-	      else if (strcasecmp (optarg, "zlib-gabi") == 0)
-		flag_compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
-	      else if (strcasecmp (optarg, "zstd") == 0)
-		{
-#ifdef HAVE_ZSTD
-		  flag_compress_debug = COMPRESS_DEBUG_ZSTD;
-#else
+	      flag_compress_debug = bfd_get_compression_algorithm (optarg);
+#ifndef HAVE_ZSTD
+	      if (flag_compress_debug == COMPRESS_DEBUG_ZSTD)
 		  as_fatal (_ ("--compress-debug-sections=zstd: gas is not "
 			       "built with zstd support"));
 #endif
-		}
-	      else
+	      if (flag_compress_debug == COMPRESS_UNKNOWN)
 		as_fatal (_("Invalid --compress-debug-sections option: `%s'"),
 			  optarg);
 #else
diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
index acd66f907d1..5dfc03a740c 100644
--- a/ld/emultempl/elf.em
+++ b/ld/emultempl/elf.em
@@ -660,24 +660,16 @@ gld${EMULATION_NAME}_handle_option (int optc)
       break;
 
     case OPTION_COMPRESS_DEBUG:
-      if (strcasecmp (optarg, "none") == 0)
-	link_info.compress_debug = COMPRESS_DEBUG_NONE;
-      else if (strcasecmp (optarg, "zlib") == 0)
-	link_info.compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
-      else if (strcasecmp (optarg, "zlib-gnu") == 0)
-	link_info.compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
-      else if (strcasecmp (optarg, "zlib-gabi") == 0)
-	link_info.compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
-      else if (strcasecmp (optarg, "zstd") == 0)
+      link_info.compress_debug = bfd_get_compression_algorithm (optarg);
+      if (strcasecmp (optarg, "zstd") == 0)
 	{
-#ifdef HAVE_ZSTD
-	  link_info.compress_debug = COMPRESS_DEBUG_ZSTD;
-#else
-	  einfo (_ ("%F%P: --compress-debug-sections=zstd: ld is not built "
-		    "with zstd support\n"));
+#ifndef HAVE_ZSTD
+	  if (link_info.compress_debug == COMPRESS_DEBUG_ZSTD)
+	    einfo (_ ("%F%P: --compress-debug-sections=zstd: ld is not built "
+		  "with zstd support\n"));
 #endif
 	}
-      else
+      if (link_info.compress_debug == COMPRESS_UNKNOWN)
 	einfo (_("%F%P: invalid --compress-debug-sections option: \`%s'\n"),
 	       optarg);
       break;
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 299371fb775..0c01c9966e0 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -2148,13 +2148,9 @@ elf_static_list_options (FILE *file)
   fprintf (file, _("\
   --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi|zstd]\n\
 			      Compress DWARF debug sections\n"));
-#ifdef DEFAULT_FLAG_COMPRESS_DEBUG
   fprintf (file, _("\
-                                Default: zlib-gabi\n"));
-#else
-  fprintf (file, _("\
-                                Default: none\n"));
-#endif
+                                Default: %s\n"),
+	   bfd_get_compression_algorithm_name (link_info.compress_debug));
   fprintf (file, _("\
   -z common-page-size=SIZE    Set common page size to SIZE\n"));
   fprintf (file, _("\
-- 
2.37.3



^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH 2/2] add --enable-default-compressed-debug-sections-algorithm configure option
  2022-10-03  7:49             ` Martin Liška
  2022-10-03  7:50               ` [PATCH 1/2] refactor usage of compressed_debug_section_type Martin Liška
@ 2022-10-03  7:50               ` Martin Liška
  2022-10-11  7:14                 ` Martin Liška
  1 sibling, 1 reply; 32+ messages in thread
From: Martin Liška @ 2022-10-03  7:50 UTC (permalink / raw)
  To: binutils; +Cc: Fangrui Song

ChangeLog:

	* configure.ac: Add --enable-default-compressed-debug-sections-algorithm.
	* configure: Regenerate.

gas/ChangeLog:

	* NEWS: Document the new option.
	* as.c (flag_compress_debug): Set default algorithm based
	on the configure option.
	* configure.ac: Add --enable-default-compressed-debug-sections-algorithm.
	* configure: Regenerate.
	* config.in: Likewise.

ld/ChangeLog:

	* NEWS: Document the new option.
	* configure.ac: Add --enable-default-compressed-debug-sections-algorithm.
	* configure: Regenerate.
	* config.in: Likewise.
	* ldmain.c: Set default algorithm based
	on the configure option.
---
 configure        | 13 +++++++++++++
 configure.ac     |  6 ++++++
 gas/NEWS         |  3 +++
 gas/as.c         |  2 +-
 gas/config.in    |  3 +++
 gas/configure    | 23 +++++++++++++++++++++--
 gas/configure.ac | 12 ++++++++++++
 ld/NEWS          |  3 +++
 ld/config.in     |  3 +++
 ld/configure     | 23 +++++++++++++++++++++--
 ld/configure.ac  | 12 ++++++++++++
 ld/ldmain.c      |  2 +-
 12 files changed, 99 insertions(+), 6 deletions(-)

diff --git a/configure b/configure
index f14e0efd675..a430e625c75 100755
--- a/configure
+++ b/configure
@@ -792,6 +792,7 @@ enable_gold
 enable_ld
 enable_gprofng
 enable_compressed_debug_sections
+enable_default_compressed_debug_sections_algorithm
 enable_year2038
 enable_libquadmath
 enable_libquadmath_support
@@ -1523,6 +1524,9 @@ Optional Features:
   --enable-compressed-debug-sections={all,gas,gold,ld,none}
                           Enable compressed debug sections for gas, gold or ld
                           by default
+  --enable-default-compressed-debug-sections-algorithm={zlib,zstd}
+                          Default compression algorithm for
+                          --enable-compressed-debug-sections.
   --enable-year2038       enable support for timestamps past the year 2038
   --disable-libquadmath   do not build libquadmath directory
   --disable-libquadmath-support
@@ -3119,6 +3123,15 @@ else
 fi
 
 
+# Select default compression algorithm.
+# Check whether --enable-default_compressed_debug_sections_algorithm was given.
+if test "${enable_default_compressed_debug_sections_algorithm+set}" = set; then :
+  enableval=$enable_default_compressed_debug_sections_algorithm;
+else
+  default_compressed_debug_sections_algorithm=
+fi
+
+
 # Configure extra directories which are host specific
 
 case "${host}" in
diff --git a/configure.ac b/configure.ac
index 0152c69292e..9c4c9e13907 100644
--- a/configure.ac
+++ b/configure.ac
@@ -422,6 +422,12 @@ AC_ARG_ENABLE(compressed_debug_sections,
   fi
 ], [enable_compressed_debug_sections=])
 
+# Select default compression algorithm.
+AC_ARG_ENABLE(default_compressed_debug_sections_algorithm,
+[AS_HELP_STRING([--enable-default-compressed-debug-sections-algorithm={zlib,zstd}],
+		[Default compression algorithm for --enable-compressed-debug-sections.])],
+[], [default_compressed_debug_sections_algorithm=])
+
 # Configure extra directories which are host specific
 
 case "${host}" in
diff --git a/gas/NEWS b/gas/NEWS
index 9a8b726b942..d9043d9d469 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -2,6 +2,9 @@
 
 * gas now supports --compress-debug-sections=zstd to compress
   debug sections with zstd.
+* Add --enable-default-compressed-debug-sections-algorithm={zlib,zstd}
+  that selects the default compression algorithm
+  for --enable-compressed-debug-sections.
 
 Changes in 2.39:
 
diff --git a/gas/as.c b/gas/as.c
index a5c2d2459f7..d42dd5394b5 100644
--- a/gas/as.c
+++ b/gas/as.c
@@ -226,7 +226,7 @@ print_version_id (void)
 
 #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
 enum compressed_debug_section_type flag_compress_debug
-  = COMPRESS_DEBUG_GABI_ZLIB;
+  = DEFAULT_COMPRESSED_DEBUG_ALGORITHM;
 #endif
 
 static void
diff --git a/gas/config.in b/gas/config.in
index 0d1668a3eac..232bc350759 100644
--- a/gas/config.in
+++ b/gas/config.in
@@ -22,6 +22,9 @@
 /* Default architecture. */
 #undef DEFAULT_ARCH
 
+/* Default compression algorithm for --enable-compressed-debug-sections. */
+#undef DEFAULT_COMPRESSED_DEBUG_ALGORITHM
+
 /* Default CRIS architecture. */
 #undef DEFAULT_CRIS_ARCH
 
diff --git a/gas/configure b/gas/configure
index 02cded59b6a..cae14c066d2 100755
--- a/gas/configure
+++ b/gas/configure
@@ -810,6 +810,7 @@ enable_largefile
 enable_targets
 enable_checking
 enable_compressed_debug_sections
+enable_default_compressed_debug_sections_algorithm
 enable_x86_relax_relocations
 enable_elf_stt_common
 enable_generate_build_notes
@@ -1476,6 +1477,9 @@ Optional Features:
   --enable-checking       enable run-time checks
   --enable-compressed-debug-sections={all,gas,none}
                           compress debug sections by default
+  --enable-default-compressed-debug-sections-algorithm={zlib,zstd}
+                          Default compression algorithm for
+                          --enable-compressed-debug-sections.
   --enable-x86-relax-relocations
                           generate x86 relax relocations by default
   --enable-elf-stt-common generate ELF common symbols with STT_COMMON type by
@@ -10722,7 +10726,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10725 "configure"
+#line 10729 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10828,7 +10832,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10831 "configure"
+#line 10835 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11502,6 +11506,15 @@ if test "${enable_compressed_debug_sections+set}" = set; then :
 esac
 fi
 
+# Select default compression algorithm.
+ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_GABI_ZLIB
+# Check whether --enable-default_compressed_debug_sections_algorithm was given.
+if test "${enable_default_compressed_debug_sections_algorithm+set}" = set; then :
+  enableval=$enable_default_compressed_debug_sections_algorithm; case "${enableval}" in
+   zstd) ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_ZSTD ;;
+esac
+fi
+
 # PR gas/19520
 # Decide if x86 assembler should generate relax relocations.
 ac_default_x86_relax_relocations=unset
@@ -12671,6 +12684,12 @@ $as_echo "#define DEFAULT_FLAG_COMPRESS_DEBUG 1" >>confdefs.h
 
 fi
 
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_COMPRESSED_DEBUG_ALGORITHM $ac_default_compressed_debug_sections_algorithm
+_ACEOF
+
+
 # Turn on all targets if possible
 if test ${all_targets} = "yes"; then
   case ${target_cpu_type} in
diff --git a/gas/configure.ac b/gas/configure.ac
index e6f3298cb3e..feb43399ce8 100644
--- a/gas/configure.ac
+++ b/gas/configure.ac
@@ -76,6 +76,15 @@ AC_ARG_ENABLE(compressed_debug_sections,
   *)   ac_default_compressed_debug_sections=unset ;;
 esac])dnl
 
+# Select default compression algorithm.
+ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_GABI_ZLIB
+AC_ARG_ENABLE(default_compressed_debug_sections_algorithm,
+	      AS_HELP_STRING([--enable-default-compressed-debug-sections-algorithm={zlib,zstd}],
+	      [Default compression algorithm for --enable-compressed-debug-sections.]),
+[case "${enableval}" in
+   zstd) ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_ZSTD ;;
+esac])dnl
+
 # PR gas/19520
 # Decide if x86 assembler should generate relax relocations.
 ac_default_x86_relax_relocations=unset
@@ -755,6 +764,9 @@ if test x$ac_default_compressed_debug_sections = xyes ; then
   AC_DEFINE(DEFAULT_FLAG_COMPRESS_DEBUG, 1, [Define if you want compressed debug sections by default.])
 fi
 
+AC_DEFINE_UNQUOTED(DEFAULT_COMPRESSED_DEBUG_ALGORITHM, $ac_default_compressed_debug_sections_algorithm,
+		   [Default compression algorithm for --enable-compressed-debug-sections.])
+
 # Turn on all targets if possible
 if test ${all_targets} = "yes"; then
   case ${target_cpu_type} in
diff --git a/ld/NEWS b/ld/NEWS
index dfe2690d9f2..d7ceb0c68b6 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -2,6 +2,9 @@
 
 * ld now supports zstd compressed debug sections.  The new option
   --compress-debug-sections=zstd compresses debug sections with zstd.
+* Add --enable-default-compressed-debug-sections-algorithm={zlib,zstd}
+  that selects the default compression algorithm
+  for --enable-compressed-debug-sections.
 
 Changes in 2.39:
 
diff --git a/ld/config.in b/ld/config.in
index 3916740eee4..ad0dc6a106c 100644
--- a/ld/config.in
+++ b/ld/config.in
@@ -7,6 +7,9 @@
 #endif
 #define __CONFIG_H__ 1
 
+/* Default compression algorithm for --enable-compressed-debug-sections. */
+#undef DEFAULT_COMPRESSED_DEBUG_ALGORITHM
+
 /* 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 9dd3ed5f1e7..7906f52aadf 100755
--- a/ld/configure
+++ b/ld/configure
@@ -841,6 +841,7 @@ with_sysroot
 enable_gold
 enable_got
 enable_compressed_debug_sections
+enable_default_compressed_debug_sections_algorithm
 enable_new_dtags
 enable_relro
 enable_textrel_check
@@ -1524,6 +1525,9 @@ Optional Features:
                           multigot)
   --enable-compressed-debug-sections={all,ld,none}
                           compress debug sections by default]
+  --enable-default-compressed-debug-sections-algorithm={zlib,zstd}
+                          Default compression algorithm for
+                          --enable-compressed-debug-sections.
   --enable-new-dtags      set DT_RUNPATH instead of DT_RPATH by default]
   --enable-relro          enable -z relro in ELF linker by default
   --enable-textrel-check=[yes|no|warning|error]
@@ -11620,7 +11624,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11623 "configure"
+#line 11627 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11726,7 +11730,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11729 "configure"
+#line 11733 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -15544,6 +15548,15 @@ if test "${enable_compressed_debug_sections+set}" = set; then :
 esac
 fi
 
+# Select default compression algorithm.
+ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_GABI_ZLIB
+# Check whether --enable-default_compressed_debug_sections_algorithm was given.
+if test "${enable_default_compressed_debug_sections_algorithm+set}" = set; then :
+  enableval=$enable_default_compressed_debug_sections_algorithm; case "${enableval}" in
+   zstd) ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_ZSTD ;;
+esac
+fi
+
 # Decide setting DT_RUNPATH instead of DT_RPATH by default
 ac_default_new_dtags=unset
 # Provide a configure time option to override our default.
@@ -17340,6 +17353,12 @@ $as_echo "#define DEFAULT_FLAG_COMPRESS_DEBUG 1" >>confdefs.h
 
 fi
 
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_COMPRESSED_DEBUG_ALGORITHM $ac_default_compressed_debug_sections_algorithm
+_ACEOF
+
+
 if test "${ac_default_new_dtags}" = unset; then
   ac_default_new_dtags=0
 fi
diff --git a/ld/configure.ac b/ld/configure.ac
index f1b2f9897f8..6123ea78611 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -163,6 +163,15 @@ AC_ARG_ENABLE(compressed_debug_sections,
   ,no, | ,none,)  ac_default_compressed_debug_sections=no ;;
 esac])dnl
 
+# Select default compression algorithm.
+ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_GABI_ZLIB
+AC_ARG_ENABLE(default_compressed_debug_sections_algorithm,
+	      AS_HELP_STRING([--enable-default-compressed-debug-sections-algorithm={zlib,zstd}],
+	      [Default compression algorithm for --enable-compressed-debug-sections.]),
+[case "${enableval}" in
+   zstd) ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_ZSTD ;;
+esac])dnl
+
 # Decide setting DT_RUNPATH instead of DT_RPATH by default
 ac_default_new_dtags=unset
 # Provide a configure time option to override our default.
@@ -510,6 +519,9 @@ if test x$ac_default_compressed_debug_sections = xyes ; then
   AC_DEFINE(DEFAULT_FLAG_COMPRESS_DEBUG, 1, [Define if you want compressed debug sections by default.])
 fi
 
+AC_DEFINE_UNQUOTED(DEFAULT_COMPRESSED_DEBUG_ALGORITHM, $ac_default_compressed_debug_sections_algorithm,
+		   [Default compression algorithm for --enable-compressed-debug-sections.])
+
 if test "${ac_default_new_dtags}" = unset; then
   ac_default_new_dtags=0
 fi
diff --git a/ld/ldmain.c b/ld/ldmain.c
index d63002c994a..10f7a0538aa 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -352,7 +352,7 @@ main (int argc, char **argv)
   link_info.spare_dynamic_tags = 5;
   link_info.path_separator = ':';
 #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
-  link_info.compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
+  link_info.compress_debug = DEFAULT_COMPRESSED_DEBUG_ALGORITHM;
 #endif
 #ifdef DEFAULT_NEW_DTAGS
   link_info.new_dtags = DEFAULT_NEW_DTAGS;
-- 
2.37.3


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 1/2] refactor usage of compressed_debug_section_type
  2022-10-03  7:50               ` [PATCH 1/2] refactor usage of compressed_debug_section_type Martin Liška
@ 2022-10-11  7:14                 ` Martin Liška
  2022-10-11 12:06                   ` Nick Clifton
  0 siblings, 1 reply; 32+ messages in thread
From: Martin Liška @ 2022-10-11  7:14 UTC (permalink / raw)
  To: binutils; +Cc: Fangrui Song

PING^1

On 10/3/22 09:50, Martin Liška wrote:
> bfd/ChangeLog:
> 
> 	* bfd-in.h (bfd_hash_set_default_size): Add COMPRESS_UNKNOWN
> 	  enum value.
> 	(struct compressed_type_tuple): New.
> 	* bfd-in2.h (bfd_hash_set_default_size): Regenerate.
> 	(struct compressed_type_tuple): Likewise.
> 	* libbfd.c (ARRAY_SIZE): New macro.
> 	(bfd_get_compression_algorithm): New function.
> 	(bfd_get_compression_algorithm_name): Likewise.
> 
> gas/ChangeLog:
> 
> 	* as.c: Do not special-case, use the new functions.
> 
> ld/ChangeLog:
> 
> 	* emultempl/elf.em: Do not special-case, use the new functions.
> 	* lexsup.c (elf_static_list_options): Likewise.
> ---
>  bfd/bfd-in.h        | 20 +++++++++++++++++---
>  bfd/bfd-in2.h       | 20 +++++++++++++++++---
>  bfd/libbfd.c        | 36 ++++++++++++++++++++++++++++++++++++
>  gas/as.c            | 34 +++++++++-------------------------
>  ld/emultempl/elf.em | 22 +++++++---------------
>  ld/lexsup.c         |  8 ++------
>  6 files changed, 88 insertions(+), 52 deletions(-)
> 
> diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
> index 4765ea80536..82e33d400f3 100644
> --- a/bfd/bfd-in.h
> +++ b/bfd/bfd-in.h
> @@ -335,15 +335,23 @@ extern void bfd_hash_traverse
>     this size.  */
>  extern unsigned long bfd_hash_set_default_size (unsigned long);
>  
> -/* Types of compressed DWARF debug sections.  We currently support
> -   zlib.  */
> +/* Types of compressed DWARF debug sections.  */
>  enum compressed_debug_section_type
>  {
>    COMPRESS_DEBUG_NONE = 0,
>    COMPRESS_DEBUG = 1 << 0,
>    COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1,
>    COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2,
> -  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3
> +  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3,
> +  COMPRESS_UNKNOWN = 1 << 4
> +};
> +
> +/* Tuple for compressed_debug_section_type and their name.  */
> +
> +struct compressed_type_tuple
> +{
> +  enum compressed_debug_section_type type;
> +  const char *name;
>  };
>  
>  /* This structure is used to keep track of stabs in sections
> @@ -456,6 +464,12 @@ extern void bfd_free_window
>    (bfd_window *);
>  extern bool bfd_get_file_window
>    (bfd *, file_ptr, bfd_size_type, bfd_window *, bool);
> +
> +
> +extern enum compressed_debug_section_type bfd_get_compression_algorithm
> +  (const char *);
> +extern const char *bfd_get_compression_algorithm_name
> +  (enum compressed_debug_section_type);
>  \f
>  /* Externally visible ELF routines.  */
>  
> diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
> index 5c80956c79c..39f925362e0 100644
> --- a/bfd/bfd-in2.h
> +++ b/bfd/bfd-in2.h
> @@ -342,15 +342,23 @@ extern void bfd_hash_traverse
>     this size.  */
>  extern unsigned long bfd_hash_set_default_size (unsigned long);
>  
> -/* Types of compressed DWARF debug sections.  We currently support
> -   zlib.  */
> +/* Types of compressed DWARF debug sections.  */
>  enum compressed_debug_section_type
>  {
>    COMPRESS_DEBUG_NONE = 0,
>    COMPRESS_DEBUG = 1 << 0,
>    COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1,
>    COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2,
> -  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3
> +  COMPRESS_DEBUG_ZSTD = COMPRESS_DEBUG | 1 << 3,
> +  COMPRESS_UNKNOWN = 1 << 4
> +};
> +
> +/* Tuple for compressed_debug_section_type and their name.  */
> +
> +struct compressed_type_tuple
> +{
> +  enum compressed_debug_section_type type;
> +  const char *name;
>  };
>  
>  /* This structure is used to keep track of stabs in sections
> @@ -463,6 +471,12 @@ extern void bfd_free_window
>    (bfd_window *);
>  extern bool bfd_get_file_window
>    (bfd *, file_ptr, bfd_size_type, bfd_window *, bool);
> +
> +
> +extern enum compressed_debug_section_type bfd_get_compression_algorithm
> +  (const char *);
> +extern const char *bfd_get_compression_algorithm_name
> +  (enum compressed_debug_section_type);
>  \f
>  /* Externally visible ELF routines.  */
>  
> diff --git a/bfd/libbfd.c b/bfd/libbfd.c
> index d33f3416206..14e7d8ef34f 100644
> --- a/bfd/libbfd.c
> +++ b/bfd/libbfd.c
> @@ -1244,3 +1244,39 @@ _bfd_generic_init_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED,
>  {
>    return true;
>  }
> +
> +/* Display texts for type of compressed DWARF debug sections.  */
> +static const struct compressed_type_tuple compressed_debug_section_names[] =
> +{
> +  { COMPRESS_DEBUG_NONE, "none" },
> +  { COMPRESS_DEBUG, "zlib" },
> +  { COMPRESS_DEBUG_GNU_ZLIB, "zlib-gnu" },
> +  { COMPRESS_DEBUG_GABI_ZLIB, "zlib-gabi" },
> +  { COMPRESS_DEBUG_ZSTD, "zstd" },
> +};
> +
> +#ifndef ARRAY_SIZE
> +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
> +#endif
> +
> +/* Return compressed_debug_section_type from a string representation.  */
> +enum compressed_debug_section_type
> +bfd_get_compression_algorithm (const char *name)
> +{
> +  for (unsigned i = 0; i < ARRAY_SIZE (compressed_debug_section_names); ++i)
> +    if (strcasecmp (compressed_debug_section_names[i].name, name) == 0)
> +      return compressed_debug_section_names[i].type;
> +
> +  return COMPRESS_UNKNOWN;
> +}
> +
> +/* Return compression algorithm name based on the type.  */
> +const char *
> +bfd_get_compression_algorithm_name (enum compressed_debug_section_type type)
> +{
> +  for (unsigned i = 0; i < ARRAY_SIZE (compressed_debug_section_names); ++i)
> +    if (type == compressed_debug_section_names[i].type)
> +      return compressed_debug_section_names[i].name;
> +
> +  return NULL;
> +}
> diff --git a/gas/as.c b/gas/as.c
> index 9ce3d622f95..a5c2d2459f7 100644
> --- a/gas/as.c
> +++ b/gas/as.c
> @@ -250,21 +250,16 @@ Options:\n\
>  
>    fprintf (stream, _("\
>    --alternate             initially turn on alternate macro syntax\n"));
> -#ifdef DEFAULT_FLAG_COMPRESS_DEBUG
>    fprintf (stream, _("\
>    --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
> -                          compress DWARF debug sections using zlib [default]\n"));
> +                          compress DWARF debug sections\n")),
>    fprintf (stream, _("\
> -  --nocompress-debug-sections\n\
> -                          don't compress DWARF debug sections\n"));
> -#else
> -  fprintf (stream, _("\
> -  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi|zstd}]\n\
> -                          compress DWARF debug sections using zlib\n"));
> +		            Default: %s\n"),
> +	   bfd_get_compression_algorithm_name (flag_compress_debug));
> +
>    fprintf (stream, _("\
>    --nocompress-debug-sections\n\
> -                          don't compress DWARF debug sections [default]\n"));
> -#endif
> +                          don't compress DWARF debug sections\n"));
>    fprintf (stream, _("\
>    -D                      produce assembler debugging messages\n"));
>    fprintf (stream, _("\
> @@ -741,24 +736,13 @@ This program has absolutely no warranty.\n"));
>  	  if (optarg)
>  	    {
>  #if defined OBJ_ELF || defined OBJ_MAYBE_ELF
> -	      if (strcasecmp (optarg, "none") == 0)
> -		flag_compress_debug = COMPRESS_DEBUG_NONE;
> -	      else if (strcasecmp (optarg, "zlib") == 0)
> -		flag_compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
> -	      else if (strcasecmp (optarg, "zlib-gnu") == 0)
> -		flag_compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
> -	      else if (strcasecmp (optarg, "zlib-gabi") == 0)
> -		flag_compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
> -	      else if (strcasecmp (optarg, "zstd") == 0)
> -		{
> -#ifdef HAVE_ZSTD
> -		  flag_compress_debug = COMPRESS_DEBUG_ZSTD;
> -#else
> +	      flag_compress_debug = bfd_get_compression_algorithm (optarg);
> +#ifndef HAVE_ZSTD
> +	      if (flag_compress_debug == COMPRESS_DEBUG_ZSTD)
>  		  as_fatal (_ ("--compress-debug-sections=zstd: gas is not "
>  			       "built with zstd support"));
>  #endif
> -		}
> -	      else
> +	      if (flag_compress_debug == COMPRESS_UNKNOWN)
>  		as_fatal (_("Invalid --compress-debug-sections option: `%s'"),
>  			  optarg);
>  #else
> diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
> index acd66f907d1..5dfc03a740c 100644
> --- a/ld/emultempl/elf.em
> +++ b/ld/emultempl/elf.em
> @@ -660,24 +660,16 @@ gld${EMULATION_NAME}_handle_option (int optc)
>        break;
>  
>      case OPTION_COMPRESS_DEBUG:
> -      if (strcasecmp (optarg, "none") == 0)
> -	link_info.compress_debug = COMPRESS_DEBUG_NONE;
> -      else if (strcasecmp (optarg, "zlib") == 0)
> -	link_info.compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
> -      else if (strcasecmp (optarg, "zlib-gnu") == 0)
> -	link_info.compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
> -      else if (strcasecmp (optarg, "zlib-gabi") == 0)
> -	link_info.compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
> -      else if (strcasecmp (optarg, "zstd") == 0)
> +      link_info.compress_debug = bfd_get_compression_algorithm (optarg);
> +      if (strcasecmp (optarg, "zstd") == 0)
>  	{
> -#ifdef HAVE_ZSTD
> -	  link_info.compress_debug = COMPRESS_DEBUG_ZSTD;
> -#else
> -	  einfo (_ ("%F%P: --compress-debug-sections=zstd: ld is not built "
> -		    "with zstd support\n"));
> +#ifndef HAVE_ZSTD
> +	  if (link_info.compress_debug == COMPRESS_DEBUG_ZSTD)
> +	    einfo (_ ("%F%P: --compress-debug-sections=zstd: ld is not built "
> +		  "with zstd support\n"));
>  #endif
>  	}
> -      else
> +      if (link_info.compress_debug == COMPRESS_UNKNOWN)
>  	einfo (_("%F%P: invalid --compress-debug-sections option: \`%s'\n"),
>  	       optarg);
>        break;
> diff --git a/ld/lexsup.c b/ld/lexsup.c
> index 299371fb775..0c01c9966e0 100644
> --- a/ld/lexsup.c
> +++ b/ld/lexsup.c
> @@ -2148,13 +2148,9 @@ elf_static_list_options (FILE *file)
>    fprintf (file, _("\
>    --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi|zstd]\n\
>  			      Compress DWARF debug sections\n"));
> -#ifdef DEFAULT_FLAG_COMPRESS_DEBUG
>    fprintf (file, _("\
> -                                Default: zlib-gabi\n"));
> -#else
> -  fprintf (file, _("\
> -                                Default: none\n"));
> -#endif
> +                                Default: %s\n"),
> +	   bfd_get_compression_algorithm_name (link_info.compress_debug));
>    fprintf (file, _("\
>    -z common-page-size=SIZE    Set common page size to SIZE\n"));
>    fprintf (file, _("\


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 2/2] add --enable-default-compressed-debug-sections-algorithm configure option
  2022-10-03  7:50               ` [PATCH 2/2] add --enable-default-compressed-debug-sections-algorithm configure option Martin Liška
@ 2022-10-11  7:14                 ` Martin Liška
  2022-10-11 12:08                   ` Nick Clifton
  0 siblings, 1 reply; 32+ messages in thread
From: Martin Liška @ 2022-10-11  7:14 UTC (permalink / raw)
  To: binutils; +Cc: Fangrui Song

PING^1

On 10/3/22 09:50, Martin Liška wrote:
> ChangeLog:
> 
> 	* configure.ac: Add --enable-default-compressed-debug-sections-algorithm.
> 	* configure: Regenerate.
> 
> gas/ChangeLog:
> 
> 	* NEWS: Document the new option.
> 	* as.c (flag_compress_debug): Set default algorithm based
> 	on the configure option.
> 	* configure.ac: Add --enable-default-compressed-debug-sections-algorithm.
> 	* configure: Regenerate.
> 	* config.in: Likewise.
> 
> ld/ChangeLog:
> 
> 	* NEWS: Document the new option.
> 	* configure.ac: Add --enable-default-compressed-debug-sections-algorithm.
> 	* configure: Regenerate.
> 	* config.in: Likewise.
> 	* ldmain.c: Set default algorithm based
> 	on the configure option.
> ---
>  configure        | 13 +++++++++++++
>  configure.ac     |  6 ++++++
>  gas/NEWS         |  3 +++
>  gas/as.c         |  2 +-
>  gas/config.in    |  3 +++
>  gas/configure    | 23 +++++++++++++++++++++--
>  gas/configure.ac | 12 ++++++++++++
>  ld/NEWS          |  3 +++
>  ld/config.in     |  3 +++
>  ld/configure     | 23 +++++++++++++++++++++--
>  ld/configure.ac  | 12 ++++++++++++
>  ld/ldmain.c      |  2 +-
>  12 files changed, 99 insertions(+), 6 deletions(-)
> 
> diff --git a/configure b/configure
> index f14e0efd675..a430e625c75 100755
> --- a/configure
> +++ b/configure
> @@ -792,6 +792,7 @@ enable_gold
>  enable_ld
>  enable_gprofng
>  enable_compressed_debug_sections
> +enable_default_compressed_debug_sections_algorithm
>  enable_year2038
>  enable_libquadmath
>  enable_libquadmath_support
> @@ -1523,6 +1524,9 @@ Optional Features:
>    --enable-compressed-debug-sections={all,gas,gold,ld,none}
>                            Enable compressed debug sections for gas, gold or ld
>                            by default
> +  --enable-default-compressed-debug-sections-algorithm={zlib,zstd}
> +                          Default compression algorithm for
> +                          --enable-compressed-debug-sections.
>    --enable-year2038       enable support for timestamps past the year 2038
>    --disable-libquadmath   do not build libquadmath directory
>    --disable-libquadmath-support
> @@ -3119,6 +3123,15 @@ else
>  fi
>  
>  
> +# Select default compression algorithm.
> +# Check whether --enable-default_compressed_debug_sections_algorithm was given.
> +if test "${enable_default_compressed_debug_sections_algorithm+set}" = set; then :
> +  enableval=$enable_default_compressed_debug_sections_algorithm;
> +else
> +  default_compressed_debug_sections_algorithm=
> +fi
> +
> +
>  # Configure extra directories which are host specific
>  
>  case "${host}" in
> diff --git a/configure.ac b/configure.ac
> index 0152c69292e..9c4c9e13907 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -422,6 +422,12 @@ AC_ARG_ENABLE(compressed_debug_sections,
>    fi
>  ], [enable_compressed_debug_sections=])
>  
> +# Select default compression algorithm.
> +AC_ARG_ENABLE(default_compressed_debug_sections_algorithm,
> +[AS_HELP_STRING([--enable-default-compressed-debug-sections-algorithm={zlib,zstd}],
> +		[Default compression algorithm for --enable-compressed-debug-sections.])],
> +[], [default_compressed_debug_sections_algorithm=])
> +
>  # Configure extra directories which are host specific
>  
>  case "${host}" in
> diff --git a/gas/NEWS b/gas/NEWS
> index 9a8b726b942..d9043d9d469 100644
> --- a/gas/NEWS
> +++ b/gas/NEWS
> @@ -2,6 +2,9 @@
>  
>  * gas now supports --compress-debug-sections=zstd to compress
>    debug sections with zstd.
> +* Add --enable-default-compressed-debug-sections-algorithm={zlib,zstd}
> +  that selects the default compression algorithm
> +  for --enable-compressed-debug-sections.
>  
>  Changes in 2.39:
>  
> diff --git a/gas/as.c b/gas/as.c
> index a5c2d2459f7..d42dd5394b5 100644
> --- a/gas/as.c
> +++ b/gas/as.c
> @@ -226,7 +226,7 @@ print_version_id (void)
>  
>  #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
>  enum compressed_debug_section_type flag_compress_debug
> -  = COMPRESS_DEBUG_GABI_ZLIB;
> +  = DEFAULT_COMPRESSED_DEBUG_ALGORITHM;
>  #endif
>  
>  static void
> diff --git a/gas/config.in b/gas/config.in
> index 0d1668a3eac..232bc350759 100644
> --- a/gas/config.in
> +++ b/gas/config.in
> @@ -22,6 +22,9 @@
>  /* Default architecture. */
>  #undef DEFAULT_ARCH
>  
> +/* Default compression algorithm for --enable-compressed-debug-sections. */
> +#undef DEFAULT_COMPRESSED_DEBUG_ALGORITHM
> +
>  /* Default CRIS architecture. */
>  #undef DEFAULT_CRIS_ARCH
>  
> diff --git a/gas/configure b/gas/configure
> index 02cded59b6a..cae14c066d2 100755
> --- a/gas/configure
> +++ b/gas/configure
> @@ -810,6 +810,7 @@ enable_largefile
>  enable_targets
>  enable_checking
>  enable_compressed_debug_sections
> +enable_default_compressed_debug_sections_algorithm
>  enable_x86_relax_relocations
>  enable_elf_stt_common
>  enable_generate_build_notes
> @@ -1476,6 +1477,9 @@ Optional Features:
>    --enable-checking       enable run-time checks
>    --enable-compressed-debug-sections={all,gas,none}
>                            compress debug sections by default
> +  --enable-default-compressed-debug-sections-algorithm={zlib,zstd}
> +                          Default compression algorithm for
> +                          --enable-compressed-debug-sections.
>    --enable-x86-relax-relocations
>                            generate x86 relax relocations by default
>    --enable-elf-stt-common generate ELF common symbols with STT_COMMON type by
> @@ -10722,7 +10726,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 10725 "configure"
> +#line 10729 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -10828,7 +10832,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 10831 "configure"
> +#line 10835 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -11502,6 +11506,15 @@ if test "${enable_compressed_debug_sections+set}" = set; then :
>  esac
>  fi
>  
> +# Select default compression algorithm.
> +ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_GABI_ZLIB
> +# Check whether --enable-default_compressed_debug_sections_algorithm was given.
> +if test "${enable_default_compressed_debug_sections_algorithm+set}" = set; then :
> +  enableval=$enable_default_compressed_debug_sections_algorithm; case "${enableval}" in
> +   zstd) ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_ZSTD ;;
> +esac
> +fi
> +
>  # PR gas/19520
>  # Decide if x86 assembler should generate relax relocations.
>  ac_default_x86_relax_relocations=unset
> @@ -12671,6 +12684,12 @@ $as_echo "#define DEFAULT_FLAG_COMPRESS_DEBUG 1" >>confdefs.h
>  
>  fi
>  
> +
> +cat >>confdefs.h <<_ACEOF
> +#define DEFAULT_COMPRESSED_DEBUG_ALGORITHM $ac_default_compressed_debug_sections_algorithm
> +_ACEOF
> +
> +
>  # Turn on all targets if possible
>  if test ${all_targets} = "yes"; then
>    case ${target_cpu_type} in
> diff --git a/gas/configure.ac b/gas/configure.ac
> index e6f3298cb3e..feb43399ce8 100644
> --- a/gas/configure.ac
> +++ b/gas/configure.ac
> @@ -76,6 +76,15 @@ AC_ARG_ENABLE(compressed_debug_sections,
>    *)   ac_default_compressed_debug_sections=unset ;;
>  esac])dnl
>  
> +# Select default compression algorithm.
> +ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_GABI_ZLIB
> +AC_ARG_ENABLE(default_compressed_debug_sections_algorithm,
> +	      AS_HELP_STRING([--enable-default-compressed-debug-sections-algorithm={zlib,zstd}],
> +	      [Default compression algorithm for --enable-compressed-debug-sections.]),
> +[case "${enableval}" in
> +   zstd) ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_ZSTD ;;
> +esac])dnl
> +
>  # PR gas/19520
>  # Decide if x86 assembler should generate relax relocations.
>  ac_default_x86_relax_relocations=unset
> @@ -755,6 +764,9 @@ if test x$ac_default_compressed_debug_sections = xyes ; then
>    AC_DEFINE(DEFAULT_FLAG_COMPRESS_DEBUG, 1, [Define if you want compressed debug sections by default.])
>  fi
>  
> +AC_DEFINE_UNQUOTED(DEFAULT_COMPRESSED_DEBUG_ALGORITHM, $ac_default_compressed_debug_sections_algorithm,
> +		   [Default compression algorithm for --enable-compressed-debug-sections.])
> +
>  # Turn on all targets if possible
>  if test ${all_targets} = "yes"; then
>    case ${target_cpu_type} in
> diff --git a/ld/NEWS b/ld/NEWS
> index dfe2690d9f2..d7ceb0c68b6 100644
> --- a/ld/NEWS
> +++ b/ld/NEWS
> @@ -2,6 +2,9 @@
>  
>  * ld now supports zstd compressed debug sections.  The new option
>    --compress-debug-sections=zstd compresses debug sections with zstd.
> +* Add --enable-default-compressed-debug-sections-algorithm={zlib,zstd}
> +  that selects the default compression algorithm
> +  for --enable-compressed-debug-sections.
>  
>  Changes in 2.39:
>  
> diff --git a/ld/config.in b/ld/config.in
> index 3916740eee4..ad0dc6a106c 100644
> --- a/ld/config.in
> +++ b/ld/config.in
> @@ -7,6 +7,9 @@
>  #endif
>  #define __CONFIG_H__ 1
>  
> +/* Default compression algorithm for --enable-compressed-debug-sections. */
> +#undef DEFAULT_COMPRESSED_DEBUG_ALGORITHM
> +
>  /* 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 9dd3ed5f1e7..7906f52aadf 100755
> --- a/ld/configure
> +++ b/ld/configure
> @@ -841,6 +841,7 @@ with_sysroot
>  enable_gold
>  enable_got
>  enable_compressed_debug_sections
> +enable_default_compressed_debug_sections_algorithm
>  enable_new_dtags
>  enable_relro
>  enable_textrel_check
> @@ -1524,6 +1525,9 @@ Optional Features:
>                            multigot)
>    --enable-compressed-debug-sections={all,ld,none}
>                            compress debug sections by default]
> +  --enable-default-compressed-debug-sections-algorithm={zlib,zstd}
> +                          Default compression algorithm for
> +                          --enable-compressed-debug-sections.
>    --enable-new-dtags      set DT_RUNPATH instead of DT_RPATH by default]
>    --enable-relro          enable -z relro in ELF linker by default
>    --enable-textrel-check=[yes|no|warning|error]
> @@ -11620,7 +11624,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 11623 "configure"
> +#line 11627 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -11726,7 +11730,7 @@ else
>    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
>    lt_status=$lt_dlunknown
>    cat > conftest.$ac_ext <<_LT_EOF
> -#line 11729 "configure"
> +#line 11733 "configure"
>  #include "confdefs.h"
>  
>  #if HAVE_DLFCN_H
> @@ -15544,6 +15548,15 @@ if test "${enable_compressed_debug_sections+set}" = set; then :
>  esac
>  fi
>  
> +# Select default compression algorithm.
> +ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_GABI_ZLIB
> +# Check whether --enable-default_compressed_debug_sections_algorithm was given.
> +if test "${enable_default_compressed_debug_sections_algorithm+set}" = set; then :
> +  enableval=$enable_default_compressed_debug_sections_algorithm; case "${enableval}" in
> +   zstd) ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_ZSTD ;;
> +esac
> +fi
> +
>  # Decide setting DT_RUNPATH instead of DT_RPATH by default
>  ac_default_new_dtags=unset
>  # Provide a configure time option to override our default.
> @@ -17340,6 +17353,12 @@ $as_echo "#define DEFAULT_FLAG_COMPRESS_DEBUG 1" >>confdefs.h
>  
>  fi
>  
> +
> +cat >>confdefs.h <<_ACEOF
> +#define DEFAULT_COMPRESSED_DEBUG_ALGORITHM $ac_default_compressed_debug_sections_algorithm
> +_ACEOF
> +
> +
>  if test "${ac_default_new_dtags}" = unset; then
>    ac_default_new_dtags=0
>  fi
> diff --git a/ld/configure.ac b/ld/configure.ac
> index f1b2f9897f8..6123ea78611 100644
> --- a/ld/configure.ac
> +++ b/ld/configure.ac
> @@ -163,6 +163,15 @@ AC_ARG_ENABLE(compressed_debug_sections,
>    ,no, | ,none,)  ac_default_compressed_debug_sections=no ;;
>  esac])dnl
>  
> +# Select default compression algorithm.
> +ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_GABI_ZLIB
> +AC_ARG_ENABLE(default_compressed_debug_sections_algorithm,
> +	      AS_HELP_STRING([--enable-default-compressed-debug-sections-algorithm={zlib,zstd}],
> +	      [Default compression algorithm for --enable-compressed-debug-sections.]),
> +[case "${enableval}" in
> +   zstd) ac_default_compressed_debug_sections_algorithm=COMPRESS_DEBUG_ZSTD ;;
> +esac])dnl
> +
>  # Decide setting DT_RUNPATH instead of DT_RPATH by default
>  ac_default_new_dtags=unset
>  # Provide a configure time option to override our default.
> @@ -510,6 +519,9 @@ if test x$ac_default_compressed_debug_sections = xyes ; then
>    AC_DEFINE(DEFAULT_FLAG_COMPRESS_DEBUG, 1, [Define if you want compressed debug sections by default.])
>  fi
>  
> +AC_DEFINE_UNQUOTED(DEFAULT_COMPRESSED_DEBUG_ALGORITHM, $ac_default_compressed_debug_sections_algorithm,
> +		   [Default compression algorithm for --enable-compressed-debug-sections.])
> +
>  if test "${ac_default_new_dtags}" = unset; then
>    ac_default_new_dtags=0
>  fi
> diff --git a/ld/ldmain.c b/ld/ldmain.c
> index d63002c994a..10f7a0538aa 100644
> --- a/ld/ldmain.c
> +++ b/ld/ldmain.c
> @@ -352,7 +352,7 @@ main (int argc, char **argv)
>    link_info.spare_dynamic_tags = 5;
>    link_info.path_separator = ':';
>  #ifdef DEFAULT_FLAG_COMPRESS_DEBUG
> -  link_info.compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
> +  link_info.compress_debug = DEFAULT_COMPRESSED_DEBUG_ALGORITHM;
>  #endif
>  #ifdef DEFAULT_NEW_DTAGS
>    link_info.new_dtags = DEFAULT_NEW_DTAGS;


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 1/2] refactor usage of compressed_debug_section_type
  2022-10-11  7:14                 ` Martin Liška
@ 2022-10-11 12:06                   ` Nick Clifton
  2022-10-11 13:27                     ` Martin Liška
  0 siblings, 1 reply; 32+ messages in thread
From: Nick Clifton @ 2022-10-11 12:06 UTC (permalink / raw)
  To: Martin Liška, binutils; +Cc: Fangrui Song

Hi Martin,

> PING^1
Sorry!


> On 10/3/22 09:50, Martin Liška wrote:
>> bfd/ChangeLog:
>>
>> 	* bfd-in.h (bfd_hash_set_default_size): Add COMPRESS_UNKNOWN
>> 	  enum value.
>> 	(struct compressed_type_tuple): New.
>> 	* bfd-in2.h (bfd_hash_set_default_size): Regenerate.
>> 	(struct compressed_type_tuple): Likewise.
>> 	* libbfd.c (ARRAY_SIZE): New macro.
>> 	(bfd_get_compression_algorithm): New function.
>> 	(bfd_get_compression_algorithm_name): Likewise.
>>
>> gas/ChangeLog:
>>
>> 	* as.c: Do not special-case, use the new functions.
>>
>> ld/ChangeLog:
>>
>> 	* emultempl/elf.em: Do not special-case, use the new functions.
>> 	* lexsup.c (elf_static_list_options): Likewise.

Approved - please apply.

Cheers
   Nick



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 2/2] add --enable-default-compressed-debug-sections-algorithm configure option
  2022-10-11  7:14                 ` Martin Liška
@ 2022-10-11 12:08                   ` Nick Clifton
  0 siblings, 0 replies; 32+ messages in thread
From: Nick Clifton @ 2022-10-11 12:08 UTC (permalink / raw)
  To: Martin Liška, binutils; +Cc: Fangrui Song

Hi Martin,

> PING^1
Sorry!

> On 10/3/22 09:50, Martin Liška wrote:
>> ChangeLog:
>>
>> 	* configure.ac: Add --enable-default-compressed-debug-sections-algorithm.
>> 	* configure: Regenerate.
>>
>> gas/ChangeLog:
>>
>> 	* NEWS: Document the new option.
>> 	* as.c (flag_compress_debug): Set default algorithm based
>> 	on the configure option.
>> 	* configure.ac: Add --enable-default-compressed-debug-sections-algorithm.
>> 	* configure: Regenerate.
>> 	* config.in: Likewise.
>>
>> ld/ChangeLog:
>>
>> 	* NEWS: Document the new option.
>> 	* configure.ac: Add --enable-default-compressed-debug-sections-algorithm.
>> 	* configure: Regenerate.
>> 	* config.in: Likewise.
>> 	* ldmain.c: Set default algorithm based
>> 	on the configure option.
  Approved - please apply.

Cheers
   Nick


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH 1/2] refactor usage of compressed_debug_section_type
  2022-10-11 12:06                   ` Nick Clifton
@ 2022-10-11 13:27                     ` Martin Liška
  0 siblings, 0 replies; 32+ messages in thread
From: Martin Liška @ 2022-10-11 13:27 UTC (permalink / raw)
  To: Nick Clifton, binutils; +Cc: Fangrui Song

[-- Attachment #1: Type: text/plain, Size: 1024 bytes --]

On 10/11/22 14:06, Nick Clifton wrote:
> Hi Martin,
> 
>> PING^1
> Sorry!
> 
> 
>> On 10/3/22 09:50, Martin Liška wrote:
>>> bfd/ChangeLog:
>>>
>>>     * bfd-in.h (bfd_hash_set_default_size): Add COMPRESS_UNKNOWN
>>>       enum value.
>>>     (struct compressed_type_tuple): New.
>>>     * bfd-in2.h (bfd_hash_set_default_size): Regenerate.
>>>     (struct compressed_type_tuple): Likewise.
>>>     * libbfd.c (ARRAY_SIZE): New macro.
>>>     (bfd_get_compression_algorithm): New function.
>>>     (bfd_get_compression_algorithm_name): Likewise.
>>>
>>> gas/ChangeLog:
>>>
>>>     * as.c: Do not special-case, use the new functions.
>>>
>>> ld/ChangeLog:
>>>
>>>     * emultempl/elf.em: Do not special-case, use the new functions.
>>>     * lexsup.c (elf_static_list_options): Likewise.
> 
> Approved - please apply.
> 
> Cheers
>   Nick
> 
> 

Hello.

Thanks, I've installed the patches and noticed the following obvious fix is needed.
I'm going to install it.

Cheers,
Martin

[-- Attachment #2: 0001-fix-compressed_debug_section_names-definition-for-zl.patch --]
[-- Type: text/x-patch, Size: 903 bytes --]

From 735fab23d68d66678eaa19e5751c49091c3bd299 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Tue, 11 Oct 2022 15:25:06 +0200
Subject: [PATCH] fix compressed_debug_section_names definition for "zlib"

bfd/ChangeLog:

	* libbfd.c: Set COMPRESS_DEBUG_GABI_ZLIB for "zlib" value.
---
 bfd/libbfd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bfd/libbfd.c b/bfd/libbfd.c
index 14e7d8ef34f..3090e0ae64b 100644
--- a/bfd/libbfd.c
+++ b/bfd/libbfd.c
@@ -1249,7 +1249,7 @@ _bfd_generic_init_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED,
 static const struct compressed_type_tuple compressed_debug_section_names[] =
 {
   { COMPRESS_DEBUG_NONE, "none" },
-  { COMPRESS_DEBUG, "zlib" },
+  { COMPRESS_DEBUG_GABI_ZLIB, "zlib" },
   { COMPRESS_DEBUG_GNU_ZLIB, "zlib-gnu" },
   { COMPRESS_DEBUG_GABI_ZLIB, "zlib-gabi" },
   { COMPRESS_DEBUG_ZSTD, "zstd" },
-- 
2.37.3


^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2022-10-11 13:27 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-23  4:08 [PATCH v3] binutils, gdb: support zstd compressed debug sections Fangrui Song
2022-09-23 14:32 ` Simon Marchi
2022-09-26  5:12   ` Alan Modra
2022-09-26  7:20     ` Fangrui Song
2022-09-26 13:30       ` Alan Modra
2022-09-26 14:08     ` Simon Marchi
2022-09-27  0:33       ` Alan Modra
2022-09-23 15:45 ` Nick Clifton
2022-09-23 15:58   ` Simon Marchi
2022-09-23 18:20     ` Fangrui Song
2022-09-23 18:57       ` Simon Marchi
2022-09-23 20:34         ` Fangrui Song
2022-09-24  5:43           ` Eli Zaretskii
2022-09-24  6:53 ` Enze Li
2022-09-24  7:13   ` Fangrui Song
2022-09-27 18:06     ` Tom Tromey
2022-09-27 18:08 ` Tom Tromey
2022-09-27 18:53   ` Fangrui Song
2022-09-29 11:43 ` Martin Liška
2022-09-29 20:17   ` Fangrui Song
2022-09-30  9:48     ` [PATCH][RFC] add --enable-zstd-compressed-debug-sections configure option Martin Liška
2022-09-30 11:25       ` Pedro Alves
2022-09-30 12:42         ` Martin Liška
2022-10-01  7:31           ` Fangrui Song
2022-10-03  7:49             ` Martin Liška
2022-10-03  7:50               ` [PATCH 1/2] refactor usage of compressed_debug_section_type Martin Liška
2022-10-11  7:14                 ` Martin Liška
2022-10-11 12:06                   ` Nick Clifton
2022-10-11 13:27                     ` Martin Liška
2022-10-03  7:50               ` [PATCH 2/2] add --enable-default-compressed-debug-sections-algorithm configure option Martin Liška
2022-10-11  7:14                 ` Martin Liška
2022-10-11 12:08                   ` Nick Clifton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).