Re: [PATCH v3] binutils, gdb: support zstd compressed debug sections

Fangrui Song via Gdb-patches
2022-09-23T18:22:24Z

[-- 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