This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PATCH: Add --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi] to ld
- From: "H.J. Lu" <hjl dot tools at gmail dot com>
- To: Binutils <binutils at sourceware dot org>
- Date: Mon, 13 Apr 2015 05:38:24 -0700
- Subject: PATCH: Add --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi] to ld
- Authentication-results: sourceware.org; auth=none
On Sun, Apr 12, 2015 at 6:13 PM, Alan Modra <amodra@gmail.com> wrote:
> On Thu, Apr 09, 2015 at 03:07:20PM -0700, H.J. Lu wrote:
>> + if (arg->link_info
>> + && (arg->link_info->compress_debug & COMPRESS_DEBUG)
>> + && arg->link_info->compress_debug != COMPRESS_DEBUG_GABI_ZLIB
>> + && (asect->flags & SEC_DEBUGGING)
>> + && name[1] == 'd'
>> + && name[6] == '_')
>
> Here and in a couple of other places you omit checking the full prefix
> of the name. Are you certain you won't see something like a ".de"
> section here? It you might, then name[6] is a buffer overflow and a
> potential segfault.
elf.c has
if ((flags & SEC_ALLOC) == 0)
{
/* The debugging sections appear to be recognized only by name,
not any sort of flag. Their SEC_ALLOC bits are cleared. */
if (name [0] == '.')
{
const char *p;
int n;
if (name[1] == 'd')
p = ".debug", n = 6;
else if (name[1] == 'g' && name[2] == 'n')
p = ".gnu.linkonce.wi.", n = 17;
else if (name[1] == 'g' && name[2] == 'd')
p = ".gdb_index", n = 11; /* yes we really do mean 11. */
else if (name[1] == 'l')
p = ".line", n = 5;
else if (name[1] == 's')
p = ".stab", n = 5;
else if (name[1] == 'z')
p = ".zdebug", n = 7;
else
p = NULL, n = 0;
if (p != NULL && strncmp (name, p, n) == 0)
flags |= SEC_DEBUGGING;
}
}
and
/* Compress/decompress DWARF debug sections with names: .debug_* and
.zdebug_*, after the section flags is set. */
if ((flags & SEC_DEBUGGING)
&& ((name[1] == 'd' && name[6] == '_')
|| (name[1] == 'z' && name[7] == '_')))
{
When name[1] == 'd'. It is pretty safe to check name[1] == 'd' &&
name[6] == '_'
when SEC_DEBUGGING is set.
Here is the completed patch. OK for master?
Thanks.
--
H.J.
From f6134092f395177cedbca1a2cb519e9f1b3c6ffb Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Mon, 13 Apr 2015 05:30:52 -0700
Subject: [PATCH] Add --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi]
This patch adds --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi]
to ld for ELF targets to support generating compressed DWARF debug
sections. We always generate .zdebug_* section since section names have
been finalized and they can't be changed easily when compression is
being performed.
bfd/
* bfd-in.h (compressed_debug_section_type): New.
* compress.c (bfd_compress_section_contents): Add an argument
for linker write compression and always generate .zdebug_*
section when linking.
(bfd_init_section_compress_status): Pass FALSE to
bfd_compress_section_contents.
(bfd_compress_section): New function.
* elf.c (elf_fake_sections): For linking, set SEC_ELF_COMPRESS
on DWARF debug sections if COMPRESS_DEBUG is set and rename
section if COMPRESS_DEBUG_GABI_ZLIB isn't set.
(assign_file_positions_for_non_load_sections): Set sh_offset
to -1 if SEC_ELF_COMPRESS is set.
(assign_file_positions_except_relocs): Likwise.
(_bfd_elf_assign_file_positions_for_relocs): Renamed to ...
(_bfd_elf_assign_file_positions_for_non_load): This. Change
return time to bfd_boolean. Compress the section if
SEC_ELF_COMPRESS is set.
(_bfd_elf_write_object_contents): Updated.
(_bfd_elf_set_section_contents): Allocate the buffer for contents
if SEC_ELF_COMPRESS is set.
* merge.c: Include "elf-bfd.h".
(sec_merge_emit): Add an argument for offset. For ELF, write
to contents if sh_offset is -1.
(_bfd_write_merged_section): Allocate the buffer for contents
if SEC_ELF_COMPRESS is set. Pass output_offset to
sec_merge_emit.
* section.c (SEC_ELF_COMPRESS): New.
* bfd-in2.h: Regenerated.
gas/
* as.h (compressed_debug_section_type): Removed.
include/
* bfdlink.h (bfd_link_info): Add compress_debug.
ld/
* ld.texinfo: Document --compress-debug-sections=.
* ldmain.c (main): Set BFD_COMPRESS on output_bfd if
COMPRESS_DEBUG is set. Set BFD_COMPRESS_GABI on output_bfd
for COMPRESS_DEBUG_GABI_ZLIB.
* lexsup.c (elf_static_list_options): Add
--compress-debug-sections=.
* emultempl/elf32.em (OPTION_COMPRESS_DEBUG): New.
(xtra_long): Add "compress-debug-sections".
(gld${EMULATION_NAME}_handle_option): Handle
OPTION_COMPRESS_DEBUG.
ld/testsuite/
* ld-elf/compress.exp (build_tests): Add tests for
--compress-debug-sections=.
(run_tests): Likewise.
Add additonal tests for --compress-debug-sections=.
* ld-elf/gabiend.rt: New file.
* ld-elf/gabinormal.rt: Likewise.
* ld-elf/gnubegin.rS: Likewise.
* ld-elf/gnunormal.rS: Likewise.
* ld-elf/zlibbegin.rS: Likewise.
* ld-elf/zlibnormal.rS: Likewise.
---
bfd/bfd-in.h | 11 +++
bfd/bfd-in2.h | 18 ++++
bfd/compress.c | 51 +++++++++++-
bfd/elf.c | 97 ++++++++++++++++++++--
bfd/merge.c | 76 ++++++++++++++---
bfd/section.c | 4 +
gas/as.h | 10 ---
include/bfdlink.h | 3 +
ld/emultempl/elf32.em | 15 ++++
ld/ld.texinfo | 16 ++++
ld/ldmain.c | 7 ++
ld/lexsup.c | 3 +
ld/testsuite/ld-elf/compress.exp | 167 +++++++++++++++++++++++++++++++++++++-
ld/testsuite/ld-elf/gabiend.rt | 4 +
ld/testsuite/ld-elf/gabinormal.rt | 4 +
ld/testsuite/ld-elf/gnubegin.rS | 3 +
ld/testsuite/ld-elf/gnunormal.rS | 3 +
ld/testsuite/ld-elf/zlibbegin.rS | 3 +
ld/testsuite/ld-elf/zlibnormal.rS | 3 +
19 files changed, 466 insertions(+), 32 deletions(-)
create mode 100644 ld/testsuite/ld-elf/gabiend.rt
create mode 100644 ld/testsuite/ld-elf/gabinormal.rt
create mode 100644 ld/testsuite/ld-elf/gnubegin.rS
create mode 100644 ld/testsuite/ld-elf/gnunormal.rS
create mode 100644 ld/testsuite/ld-elf/zlibbegin.rS
create mode 100644 ld/testsuite/ld-elf/zlibnormal.rS
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index 1f8a72c..2e324cd 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -437,6 +437,17 @@ extern void bfd_hash_traverse
this size. */
extern unsigned long bfd_hash_set_default_size (unsigned long);
+/* Types of compressed DWARF debug sections. We currently support
+ zlib. */
+enum compressed_debug_section_type
+{
+ COMPRESS_DEBUG_NONE = 0,
+ COMPRESS_DEBUG = 1 << 0,
+ COMPRESS_DEBUG_ZLIB = COMPRESS_DEBUG | 1 << 1,
+ COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 2,
+ COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 3
+};
+
/* This structure is used to keep track of stabs in sections
information while linking. */
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 679595e..122caa0 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -444,6 +444,17 @@ extern void bfd_hash_traverse
this size. */
extern unsigned long bfd_hash_set_default_size (unsigned long);
+/* Types of compressed DWARF debug sections. We currently support
+ zlib. */
+enum compressed_debug_section_type
+{
+ COMPRESS_DEBUG_NONE = 0,
+ COMPRESS_DEBUG = 1 << 0,
+ COMPRESS_DEBUG_ZLIB = COMPRESS_DEBUG | 1 << 1,
+ COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 2,
+ COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 3
+};
+
/* This structure is used to keep track of stabs in sections
information while linking. */
@@ -1378,6 +1389,10 @@ typedef struct bfd_section
executables or shared objects. This is for COFF only. */
#define SEC_COFF_SHARED 0x8000000
+ /* This section should be compressed. This is for ELF linker
+ internal use only. */
+#define SEC_ELF_COMPRESS 0x8000000
+
/* When a section with this flag is being linked, then if the size of
the input section is less than a page, it should not cross a page
boundary. If the size of the input section is one page or more,
@@ -7316,6 +7331,9 @@ bfd_boolean bfd_init_section_decompress_status
bfd_boolean bfd_init_section_compress_status
(bfd *abfd, asection *section);
+bfd_boolean bfd_compress_section
+ (bfd *abfd, asection *section, bfd_byte *uncompressed_buffer);
+
#ifdef __cplusplus
}
#endif
diff --git a/bfd/compress.c b/bfd/compress.c
index 770ea57..dfde50e 100644
--- a/bfd/compress.c
+++ b/bfd/compress.c
@@ -72,7 +72,8 @@ decompress_contents (bfd_byte *compressed_buffer,
static bfd_size_type
bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
bfd_byte *uncompressed_buffer,
- bfd_size_type uncompressed_size)
+ bfd_size_type uncompressed_size,
+ bfd_boolean write_compress)
{
uLong compressed_size;
bfd_byte *buffer;
@@ -176,8 +177,11 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
compressed_size += header_size;
/* PR binutils/18087: If compression didn't make the section smaller,
- just keep it uncompressed. */
- if (compressed_size < uncompressed_size)
+ just keep it uncompressed. We always generate .zdebug_* section
+ when linking since section names have been finalized and they
+ can't be changed easily. */
+ if ((write_compress && compression_header_size == 0)
+ || compressed_size < uncompressed_size)
{
bfd_update_compression_header (abfd, buffer, sec);
@@ -543,9 +547,48 @@ bfd_init_section_compress_status (bfd *abfd, sec_ptr sec)
{
uncompressed_size = bfd_compress_section_contents (abfd, sec,
uncompressed_buffer,
- uncompressed_size);
+ uncompressed_size,
+ FALSE);
ret = uncompressed_size != 0;
}
return ret;
}
+
+/*
+FUNCTION
+ bfd_compress_section
+
+SYNOPSIS
+ bfd_boolean bfd_compress_section
+ (bfd *abfd, asection *section, bfd_byte *uncompressed_buffer);
+
+DESCRIPTION
+ If open for write, compress section, update section size with
+ compressed size and set compress_status to COMPRESS_SECTION_DONE.
+
+ Return @code{FALSE} if compression fail. Otherwise, return
+ @code{TRUE}.
+*/
+
+bfd_boolean
+bfd_compress_section (bfd *abfd, sec_ptr sec, bfd_byte *uncompressed_buffer)
+{
+ bfd_size_type uncompressed_size = sec->size;
+
+ /* Error if not opened for write. */
+ if (abfd->direction != write_direction
+ || uncompressed_size == 0
+ || uncompressed_buffer == NULL
+ || sec->contents != NULL
+ || sec->compressed_size != 0
+ || sec->compress_status != COMPRESS_SECTION_NONE)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return FALSE;
+ }
+
+ /* Compress it. */
+ return bfd_compress_section_contents (abfd, sec, uncompressed_buffer,
+ uncompressed_size, TRUE) != 0;
+}
diff --git a/bfd/elf.c b/bfd/elf.c
index a031b9e..dcd24c1 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -2752,6 +2752,7 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
struct bfd_elf_section_data *esd = elf_section_data (asect);
Elf_Internal_Shdr *this_hdr;
unsigned int sh_type;
+ const char *name = asect->name;
if (arg->failed)
{
@@ -2762,8 +2763,38 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
this_hdr = &esd->this_hdr;
+ /* For linking, compress DWARF debug sections with names: .debug_*. */
+ if (arg->link_info
+ && (arg->link_info->compress_debug & COMPRESS_DEBUG)
+ && (asect->flags & SEC_DEBUGGING)
+ && name[1] == 'd'
+ && name[6] == '_')
+ {
+ /* Set SEC_ELF_COMPRESS to indicate this section should be
+ compressed. */
+ asect->flags |= SEC_ELF_COMPRESS;
+
+ if (arg->link_info->compress_debug != COMPRESS_DEBUG_GABI_ZLIB)
+ {
+ /* If SHF_COMPRESSED isn't used, rename compressed DWARF
+ debug section to .zdebug_*. */
+ unsigned int len = strlen (name);
+ char *new_name = bfd_alloc (abfd, len + 2);
+ if (new_name == NULL)
+ {
+ arg->failed = TRUE;
+ return;
+ }
+ new_name[0] = '.';
+ new_name[1] = 'z';
+ memcpy (new_name + 2, name + 1, len);
+ bfd_rename_section (abfd, asect, new_name);
+ name = asect->name;
+ }
+ }
+
this_hdr->sh_name = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
- asect->name, FALSE);
+ name, FALSE);
if (this_hdr->sh_name == (unsigned int) -1)
{
arg->failed = TRUE;
@@ -5116,6 +5147,9 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
}
else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
&& hdr->bfd_section == NULL)
+ || (hdr->bfd_section != NULL
+ && (hdr->bfd_section->flags & SEC_ELF_COMPRESS))
+ /* Compress DWARF debug sections. */
|| hdr == i_shdrpp[elf_onesymtab (abfd)]
|| hdr == i_shdrpp[elf_symtab_shndx (abfd)]
|| hdr == i_shdrpp[elf_strtab_sec (abfd)])
@@ -5365,6 +5399,9 @@ assign_file_positions_except_relocs (bfd *abfd,
hdr = *hdrpp;
if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
&& hdr->bfd_section == NULL)
+ || (hdr->bfd_section != NULL
+ && (hdr->bfd_section->flags & SEC_ELF_COMPRESS))
+ /* Compress DWARF debug sections. */
|| i == elf_onesymtab (abfd)
|| i == elf_symtab_shndx (abfd)
|| i == elf_strtab_sec (abfd))
@@ -5518,8 +5555,8 @@ prep_headers (bfd *abfd)
/* Assign file positions for all the reloc sections which are not part
of the loadable file image, and the file position of section headers. */
-static void
-_bfd_elf_assign_file_positions_for_relocs (bfd *abfd)
+static bfd_boolean
+_bfd_elf_assign_file_positions_for_non_load (bfd *abfd)
{
file_ptr off;
unsigned int i, num_sec;
@@ -5535,9 +5572,30 @@ _bfd_elf_assign_file_positions_for_relocs (bfd *abfd)
Elf_Internal_Shdr *shdrp;
shdrp = *shdrpp;
- if ((shdrp->sh_type == SHT_REL || shdrp->sh_type == SHT_RELA)
- && shdrp->sh_offset == -1)
- off = _bfd_elf_assign_file_position_for_section (shdrp, off, TRUE);
+ if (shdrp->sh_offset == -1)
+ {
+ bfd_boolean is_rel = (shdrp->sh_type == SHT_REL
+ || shdrp->sh_type == SHT_RELA);
+ if (is_rel
+ || (shdrp->bfd_section != NULL
+ && (shdrp->bfd_section->flags & SEC_ELF_COMPRESS)))
+ {
+ if (!is_rel)
+ {
+ /* Compress DWARF debug sections. */
+ if (!bfd_compress_section (abfd, shdrp->bfd_section,
+ shdrp->contents))
+ return FALSE;
+ /* Update section size and contents. */
+ shdrp->sh_size = shdrp->bfd_section->size;
+ shdrp->contents = shdrp->bfd_section->contents;
+ shdrp->bfd_section->contents = NULL;
+ }
+ off = _bfd_elf_assign_file_position_for_section (shdrp,
+ off,
+ TRUE);
+ }
+ }
}
/* Place the section headers. */
@@ -5547,6 +5605,8 @@ _bfd_elf_assign_file_positions_for_relocs (bfd *abfd)
i_ehdrp->e_shoff = off;
off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize;
elf_next_file_pos (abfd) = off;
+
+ return TRUE;
}
bfd_boolean
@@ -5569,7 +5629,8 @@ _bfd_elf_write_object_contents (bfd *abfd)
if (failed)
return FALSE;
- _bfd_elf_assign_file_positions_for_relocs (abfd);
+ if (!_bfd_elf_assign_file_positions_for_non_load (abfd))
+ return FALSE;
/* After writing the headers, we need to write the sections too... */
num_sec = elf_numsections (abfd);
@@ -7922,7 +7983,29 @@ _bfd_elf_set_section_contents (bfd *abfd,
&& ! _bfd_elf_compute_section_file_positions (abfd, NULL))
return FALSE;
+ if (!count)
+ return TRUE;
+
hdr = &elf_section_data (section)->this_hdr;
+ if (hdr->sh_offset == (file_ptr) -1)
+ {
+ /* We must compress this section. Write output to a buffer. */
+ unsigned char *contents = hdr->contents;
+ if ((offset + count) > hdr->sh_size
+ || (section->flags & SEC_ELF_COMPRESS) == 0)
+ abort ();
+ if (contents == NULL)
+ {
+ /* Use bfd_malloc since it will be freed by
+ bfd_compress_section_contents. */
+ contents = (unsigned char *) bfd_malloc (hdr->sh_size);
+ if (contents == NULL)
+ return FALSE;
+ hdr->contents = contents;
+ }
+ memcpy (contents + offset, location, count);
+ return TRUE;
+ }
pos = hdr->sh_offset + offset;
if (bfd_seek (abfd, pos, SEEK_SET) != 0
|| bfd_bwrite (location, count, abfd) != count)
diff --git a/bfd/merge.c b/bfd/merge.c
index 5f45ba6..b77a346 100644
--- a/bfd/merge.c
+++ b/bfd/merge.c
@@ -25,6 +25,7 @@
#include "sysdep.h"
#include "bfd.h"
+#include "elf-bfd.h"
#include "libbfd.h"
#include "hashtab.h"
#include "libiberty.h"
@@ -283,13 +284,15 @@ sec_merge_add (struct sec_merge_hash *tab, const char *str,
}
static bfd_boolean
-sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
+sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry,
+ file_ptr offset)
{
struct sec_merge_sec_info *secinfo = entry->secinfo;
asection *sec = secinfo->sec;
char *pad = NULL;
bfd_size_type off = 0;
int alignment_power = sec->output_section->alignment_power;
+ unsigned char *contents = NULL;
if (alignment_power)
{
@@ -298,6 +301,14 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
return FALSE;
}
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+ {
+ Elf_Internal_Shdr *hdr
+ = &elf_section_data (sec->output_section)->this_hdr;
+ if (hdr->sh_offset == (file_ptr) -1)
+ contents = hdr->contents;
+ }
+
for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next)
{
const char *str;
@@ -306,7 +317,12 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
len = -off & (entry->alignment - 1);
if (len != 0)
{
- if (bfd_bwrite (pad, len, abfd) != len)
+ if (contents)
+ {
+ memcpy (contents + offset, pad, len);
+ offset += len;
+ }
+ else if (bfd_bwrite (pad, len, abfd) != len)
goto err;
off += len;
}
@@ -314,7 +330,12 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
str = entry->root.string;
len = entry->len;
- if (bfd_bwrite (str, len, abfd) != len)
+ if (contents)
+ {
+ memcpy (contents + offset, str, len);
+ offset += len;
+ }
+ else if (bfd_bwrite (str, len, abfd) != len)
goto err;
off += len;
@@ -322,9 +343,13 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
/* Trailing alignment needed? */
off = sec->size - off;
- if (off != 0
- && bfd_bwrite (pad, off, abfd) != off)
- goto err;
+ if (off != 0)
+ {
+ if (contents)
+ memcpy (contents + offset, pad, off);
+ else if (bfd_bwrite (pad, off, abfd) != off)
+ goto err;
+ }
if (pad != NULL)
free (pad);
@@ -785,6 +810,7 @@ _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo)
{
struct sec_merge_sec_info *secinfo;
file_ptr pos;
+ unsigned char *contents;
secinfo = (struct sec_merge_sec_info *) psecinfo;
@@ -794,12 +820,42 @@ _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo)
if (secinfo->first_str == NULL)
return TRUE;
+ contents = NULL;
+
/* FIXME: octets_per_byte. */
- pos = sec->output_section->filepos + sec->output_offset;
- if (bfd_seek (output_bfd, pos, SEEK_SET) != 0)
- return FALSE;
+ if (bfd_get_flavour (output_bfd) == bfd_target_elf_flavour)
+ {
+ Elf_Internal_Shdr *hdr
+ = &elf_section_data (sec->output_section)->this_hdr;
+ if (hdr->sh_offset == (file_ptr) -1)
+ {
+ if ((sec->output_section->flags & SEC_ELF_COMPRESS) == 0)
+ abort ();
+
+ /* Cache the section contents so that they can be compressed
+ later. */
+ contents = hdr->contents;
+ if (contents == NULL)
+ {
+ /* Use bfd_malloc since it will be freed by
+ bfd_compress_section_contents. */
+ contents = (unsigned char *) bfd_malloc (hdr->sh_size);
+ if (contents == NULL)
+ return FALSE;
+ hdr->contents = contents;
+ }
+ }
+ }
+
+ if (contents == NULL)
+ {
+ pos = sec->output_section->filepos + sec->output_offset;
+ if (bfd_seek (output_bfd, pos, SEEK_SET) != 0)
+ return FALSE;
+ }
- if (! sec_merge_emit (output_bfd, secinfo->first_str))
+ if (! sec_merge_emit (output_bfd, secinfo->first_str,
+ sec->output_offset))
return FALSE;
return TRUE;
diff --git a/bfd/section.c b/bfd/section.c
index 4a6f2e4..d59a0e3 100644
--- a/bfd/section.c
+++ b/bfd/section.c
@@ -334,6 +334,10 @@ CODE_FRAGMENT
. executables or shared objects. This is for COFF only. *}
.#define SEC_COFF_SHARED 0x8000000
.
+. {* This section should be compressed. This is for ELF linker
+. internal use only. *}
+.#define SEC_ELF_COMPRESS 0x8000000
+.
. {* When a section with this flag is being linked, then if the size of
. the input section is less than a page, it should not cross a page
. boundary. If the size of the input section is one page or more,
diff --git a/gas/as.h b/gas/as.h
index e04cc0f..6de319e 100644
--- a/gas/as.h
+++ b/gas/as.h
@@ -370,16 +370,6 @@ COMMON int flag_strip_local_absolute;
/* True if we should generate a traditional format object file. */
COMMON int flag_traditional_format;
-/* Types of compressed debug sections. We currently support zlib. */
-enum compressed_debug_section_type
-{
- COMPRESS_DEBUG_NONE = 0,
- COMPRESS_DEBUG,
- COMPRESS_DEBUG_ZLIB,
- COMPRESS_DEBUG_GNU_ZLIB,
- COMPRESS_DEBUG_GABI_ZLIB
-};
-
/* Type of compressed debug sections we should generate. */
COMMON enum compressed_debug_section_type flag_compress_debug;
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 6a02a3c..012569b 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -431,6 +431,9 @@ struct bfd_link_info
/* Separator between archive and filename in linker script filespecs. */
char path_separator;
+ /* Compress DWARF debug sections. */
+ enum compressed_debug_section_type compress_debug;
+
/* Default stack size. Zero means default (often zero itself), -1
means explicitly zero-sized. */
bfd_signed_vma stacksize;
diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
index 5db5a93..0802d76 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -2110,6 +2110,7 @@ fragment <<EOF
#define OPTION_HASH_STYLE (OPTION_EXCLUDE_LIBS + 1)
#define OPTION_BUILD_ID (OPTION_HASH_STYLE + 1)
#define OPTION_AUDIT (OPTION_BUILD_ID + 1)
+#define OPTION_COMPRESS_DEBUG (OPTION_AUDIT + 1)
static void
gld${EMULATION_NAME}_add_options
@@ -2137,6 +2138,7 @@ EOF
fi
fragment <<EOF
{"build-id", optional_argument, NULL, OPTION_BUILD_ID},
+ {"compress-debug-sections", required_argument, NULL, OPTION_COMPRESS_DEBUG},
EOF
if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
fragment <<EOF
@@ -2186,6 +2188,19 @@ gld${EMULATION_NAME}_handle_option (int optc)
emit_note_gnu_build_id = xstrdup (optarg);
break;
+ case OPTION_COMPRESS_DEBUG:
+ if (strcasecmp (optarg, "none") == 0)
+ link_info.compress_debug = COMPRESS_DEBUG_NONE;
+ else if (strcasecmp (optarg, "zlib") == 0)
+ link_info.compress_debug = COMPRESS_DEBUG_ZLIB;
+ else if (strcasecmp (optarg, "zlib-gnu") == 0)
+ link_info.compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
+ else if (strcasecmp (optarg, "zlib-gabi") == 0)
+ link_info.compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
+ else
+ einfo (_("%P%F: invalid --compress-debug-sections option: \`%s'\n"),
+ optarg);
+ break;
EOF
if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 5384c98..462ec34 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -2193,6 +2193,22 @@ new style GNU @code{.gnu.hash} section or @code{both} for both
the classic ELF @code{.hash} and new style GNU @code{.gnu.hash}
hash tables. The default is @code{sysv}.
+@kindex --compress-debug-sections=none
+@kindex --compress-debug-sections=zlib
+@kindex --compress-debug-sections=zlib-gnu
+@kindex --compress-debug-sections=zlib-gabi
+@item --compress-debug-sections=none
+@itemx --compress-debug-sections=zlib
+@itemx --compress-debug-sections=zlib-gnu
+@itemx --compress-debug-sections=zlib-gabi
+On ELF platforms , these options control how DWARF debug sections are
+compressed using zlib. @option{--compress-debug-sections=none} doesn't
+compress DWARF debug sections. @option{--compress-debug-sections=zlib}
+and @option{--compress-debug-sections=zlib-gnu} compress DWARF debug
+sections and rename debug section names to begin with @samp{.zdebug}
+instead of @samp{.debug}. @option{--compress-debug-sections=zlib-gabi}
+compresses DWARF debug sections with SHF_COMPRESSED from the ELF ABI.
+
@kindex --reduce-memory-overheads
@item --reduce-memory-overheads
This option reduces memory requirements at ld runtime, at the expense of
diff --git a/ld/ldmain.c b/ld/ldmain.c
index 6674a80..224ba53 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -424,6 +424,13 @@ main (int argc, char **argv)
else
link_info.output_bfd->flags |= EXEC_P;
+ 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;
+ }
+
ldwrite ();
if (config.map_file != NULL)
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 4a71ba4..b618241 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -1722,6 +1722,9 @@ elf_static_list_options (FILE *file)
fprintf (file, _("\
--build-id[=STYLE] Generate build ID note\n"));
fprintf (file, _("\
+ --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi]\n\
+ Compress DWARF debug sections using zlib\n"));
+ fprintf (file, _("\
-z common-page-size=SIZE Set common page size to SIZE\n"));
fprintf (file, _("\
-z max-page-size=SIZE Set maximum page size to SIZE\n"));
diff --git a/ld/testsuite/ld-elf/compress.exp b/ld/testsuite/ld-elf/compress.exp
index adb7fc2..e2448b9 100644
--- a/ld/testsuite/ld-elf/compress.exp
+++ b/ld/testsuite/ld-elf/compress.exp
@@ -49,7 +49,8 @@ set build_tests {
"-shared" "-fPIC -g -Wa,--compress-debug-sections"
{foo.c} {} "libfoo.so"}
{"Build libbar.so with compressed debug sections"
- "-shared" "-fPIC -g -Wa,--compress-debug-sections"
+ "-shared -Wl,--compress-debug-sections=none"
+ "-fPIC -g -Wa,--compress-debug-sections"
{begin.c end.c} {} "libbar.so"}
{"Build libfoozlib.so with compressed debug sections with zlib-gabi"
"-shared" "-fPIC -g -Wa,--compress-debug-sections=zlib-gabi"
@@ -57,6 +58,30 @@ set build_tests {
{"Build libbarzlib.so with compressed debug sections with zlib-gabi"
"-shared" "-fPIC -g -Wa,--compress-debug-sections=zlib-gabi"
{begin.c end.c} {} "libbarzlib.so"}
+ {"Build libzlibfoo.so with zlib compressed debug sections"
+ "-shared -Wl,--compress-debug-sections=zlib"
+ "-fPIC -g -Wa,--compress-debug-sections=zlib"
+ {foo.c} {} "libzlibfoo.so"}
+ {"Build libgnufoo.so with zlib-gnu compressed debug sections"
+ "-shared -Wl,--compress-debug-sections=zlib-gnu"
+ "-fPIC -g -Wa,--compress-debug-sections=zlib-gnu"
+ {foo.c} {} "libgnufoo.so"}
+ {"Build libgabifoo.so with zlib-gabi compressed debug sections"
+ "-shared -Wl,--compress-debug-sections=zlib-gabi"
+ "-fPIC -g -Wa,--compress-debug-sections=zlib-gabi"
+ {foo.c} {} "libgabifoo.so"}
+ {"Build zlibbegin.o with zlib compressed debug sections"
+ "-r -nostdlib -Wl,--compress-debug-sections=zlib"
+ "-g -Wa,--compress-debug-sections=zlib"
+ {begin.c} {} "zlibbegin.o"}
+ {"Build gnubegin.o with zlib-gnu compressed debug sections"
+ "-r -nostdlib -Wl,--compress-debug-sections=zlib-gnu"
+ "-g -Wa,--compress-debug-sections=zlib-gnu"
+ {begin.c} {} "gnubegin.o"}
+ {"Build gabiend.o with zlib-gabi compressed debug sections"
+ "-r -nostdlib -Wl,--compress-debug-sections=zlib-gabi"
+ "-g -Wa,--compress-debug-sections=zlib-gnu"
+ {end.c} {} "gabiend.o"}
}
set run_tests {
@@ -66,6 +91,15 @@ set run_tests {
{"Run normal with libfoo.so with compressed debug sections with zlib-gabi"
"tmpdir/begin.o tmpdir/libfoozlib.so tmpdir/end.o" ""
{main.c} "normal" "normal.out" "-Wa,--compress-debug-sections=zlib-gabi"}
+ {"Run zlibnormal with libzlibfoo.so with zlib compressed debug sections"
+ "tmpdir/begin.o tmpdir/libzlibfoo.so tmpdir/end.o --compress-debug-sections=zlib" ""
+ {main.c} "zlibnormal" "normal.out" "-Wa,--compress-debug-sections=zlib"}
+ {"Run gnunormal with libgnufoo.so with zlib-gnu compressed debug sections"
+ "tmpdir/gnubegin.o tmpdir/libgnufoo.so tmpdir/end.o --compress-debug-sections=zlib-gnu" ""
+ {main.c} "gnunormal" "normal.out" "-Wa,--compress-debug-sections=zlib-gnu"}
+ {"Run gabinormal with libgabifoo.so with zlib-gabi compressed debug sections"
+ "tmpdir/zlibbegin.o tmpdir/libgabifoo.so tmpdir/gabiend.o --compress-debug-sections=zlib-gabi" ""
+ {main.c} "gabinormal" "normal.out" "-Wa,--compress-debug-sections=zlib-gabi"}
}
run_cc_link_tests $build_tests
@@ -79,3 +113,134 @@ if { [catch {exec cmp tmpdir/libfoo.so tmpdir/libfoozlib.so}] } then {
} else {
pass "$test_name"
}
+
+global READELF
+
+set test_name "Link -r with zlib compressed debug output"
+set test zlibbegin
+send_log "$READELF -S -W tmpdir/$test.o > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -S -W tmpdir/$test.o" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+ send_log "$got\n"
+ unresolved "$test_name"
+}
+if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rS] } then {
+ fail "$test_name"
+} else {
+ pass "$test_name"
+}
+
+set test_name "Link -r with zlib-gnu compressed debug output"
+set test gnubegin
+send_log "$READELF -S -W tmpdir/$test.o > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -S -W tmpdir/$test.o" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+ send_log "$got\n"
+ unresolved "$test_name"
+}
+if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rS] } then {
+ fail "$test_name"
+} else {
+ pass "$test_name"
+}
+
+set test_name "Link -r with zlib-gabi compressed debug output"
+set test gabiend
+send_log "$READELF -t -W tmpdir/$test.o > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -t -W tmpdir/$test.o" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+ send_log "$got\n"
+ unresolved "$test_name"
+}
+if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rt] } then {
+ fail "$test_name"
+} else {
+ pass "$test_name"
+}
+
+set test_name "Link with zlib compressed debug output"
+set test normal
+send_log "$READELF -w tmpdir/$test > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -w tmpdir/$test" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+ send_log "$got\n"
+ unresolved "$test_name"
+}
+
+set test_name "Link with zlib compressed debug output"
+set test zlibnormal
+send_log "$READELF -w tmpdir/$test | sed -e \"s/.zdebug_/.debug_/\" > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -w tmpdir/$test | sed -e \"s/.zdebug_/.debug_/\"" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+ send_log "$got\n"
+ unresolved "$test_name"
+}
+if { [catch {exec cmp tmpdir/normal.out tmpdir/$test.out}] } then {
+ send_log "tmpdir/normal.out tmpdir/$test.out differ.\n"
+ fail "$test_name"
+} else {
+ pass "$test_name"
+}
+send_log "$READELF -S -W tmpdir/$test' > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -S -W tmpdir/$test" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+ send_log "$got\n"
+ unresolved "$test_name"
+}
+if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rS] } then {
+ fail "$test_name"
+} else {
+ pass "$test_name"
+}
+
+set test_name "Link with zlib-gnu compressed debug output"
+set test gnunormal
+send_log "$READELF -w tmpdir/$test | sed -e \"s/.zdebug_/.debug_/\" > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -w tmpdir/$test | sed -e \"s/.zdebug_/.debug_/\"" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+ send_log "$got\n"
+ unresolved "$test_name"
+}
+if { [catch {exec cmp tmpdir/normal.out tmpdir/$test.out}] } then {
+ send_log "tmpdir/normal.out tmpdir/$test.out differ.\n"
+ fail "$test_name"
+} else {
+ pass "$test_name"
+}
+send_log "$READELF -S -W tmpdir/$test' > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -S -W tmpdir/$test" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+ send_log "$got\n"
+ unresolved "$test_name"
+}
+if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rS] } then {
+ fail "$test_name"
+} else {
+ pass "$test_name"
+}
+
+set test gabinormal
+set test_name "Link with zlib-gabi compressed debug output"
+send_log "$READELF -w tmpdir/$test > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -w tmpdir/$test" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+ send_log "$got\n"
+ unresolved "$test_name"
+}
+if { [catch {exec cmp tmpdir/normal.out tmpdir/$test.out}] } then {
+ send_log "tmpdir/normal.out tmpdir/$test.out differ.\n"
+ fail "$test_name"
+} else {
+ pass "$test_name"
+}
+send_log "$READELF -t -W tmpdir/$test > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -t -W tmpdir/$test" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+ send_log "$got\n"
+ unresolved "$test_name"
+}
+if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rt] } then {
+ fail "$test_name"
+} else {
+ pass "$test_name"
+}
diff --git a/ld/testsuite/ld-elf/gabiend.rt b/ld/testsuite/ld-elf/gabiend.rt
new file mode 100644
index 0000000..23bc36c
--- /dev/null
+++ b/ld/testsuite/ld-elf/gabiend.rt
@@ -0,0 +1,4 @@
+#...
+ +\[[0-9a-f]+\]: .*COMPRESSED
+ +ZLIB, [0-9a-f]+, 1
+#pass
diff --git a/ld/testsuite/ld-elf/gabinormal.rt b/ld/testsuite/ld-elf/gabinormal.rt
new file mode 100644
index 0000000..23bc36c
--- /dev/null
+++ b/ld/testsuite/ld-elf/gabinormal.rt
@@ -0,0 +1,4 @@
+#...
+ +\[[0-9a-f]+\]: .*COMPRESSED
+ +ZLIB, [0-9a-f]+, 1
+#pass
diff --git a/ld/testsuite/ld-elf/gnubegin.rS b/ld/testsuite/ld-elf/gnubegin.rS
new file mode 100644
index 0000000..54de24c
--- /dev/null
+++ b/ld/testsuite/ld-elf/gnubegin.rS
@@ -0,0 +1,3 @@
+#...
+ +\[[ 0-9]+\] .zdebug_.* +(PROGBITS|MIPS_DWARF) +0+ +[0-9a-f]+ +[0-9a-f]+ [0-9a-f]+ +0 +0 +1
+#pass
diff --git a/ld/testsuite/ld-elf/gnunormal.rS b/ld/testsuite/ld-elf/gnunormal.rS
new file mode 100644
index 0000000..54de24c
--- /dev/null
+++ b/ld/testsuite/ld-elf/gnunormal.rS
@@ -0,0 +1,3 @@
+#...
+ +\[[ 0-9]+\] .zdebug_.* +(PROGBITS|MIPS_DWARF) +0+ +[0-9a-f]+ +[0-9a-f]+ [0-9a-f]+ +0 +0 +1
+#pass
diff --git a/ld/testsuite/ld-elf/zlibbegin.rS b/ld/testsuite/ld-elf/zlibbegin.rS
new file mode 100644
index 0000000..54de24c
--- /dev/null
+++ b/ld/testsuite/ld-elf/zlibbegin.rS
@@ -0,0 +1,3 @@
+#...
+ +\[[ 0-9]+\] .zdebug_.* +(PROGBITS|MIPS_DWARF) +0+ +[0-9a-f]+ +[0-9a-f]+ [0-9a-f]+ +0 +0 +1
+#pass
diff --git a/ld/testsuite/ld-elf/zlibnormal.rS b/ld/testsuite/ld-elf/zlibnormal.rS
new file mode 100644
index 0000000..54de24c
--- /dev/null
+++ b/ld/testsuite/ld-elf/zlibnormal.rS
@@ -0,0 +1,3 @@
+#...
+ +\[[ 0-9]+\] .zdebug_.* +(PROGBITS|MIPS_DWARF) +0+ +[0-9a-f]+ +[0-9a-f]+ [0-9a-f]+ +0 +0 +1
+#pass
--
2.1.0